Makefile.user.cfg
QemuLog.txt
Screenshots/
+
+Tools/*/src/obj/
+Tools/*/src/Makefile.BuildNum
+Tools/DiskTool/DiskTool
--- /dev/null
+
+all:
+ @$(MAKE) -C acesskernel_src
+ @$(MAKE) -C ld-acess_src
#!/bin/sh
trap '' 2
-./AcessKernel --rootapp /Acess/SBin/login
+#$1 ./AcessKernel --rootapp /Acess/SBin/login
+$1 ./AcessKernel --rootapp /Acess/Apps/AxWin/3.0/AxWinWM
trap 2
killall ld-acess
\r
KERNEL_SRC = ../../KernelLand/Kernel/\r
\r
-KERNEL_OBJ := logging.o adt.o lib.o drvutil.o debug.o messages.o\r
+KERNEL_OBJ := logging.o adt.o lib.o libc.o debug.o messages.o drvutil_disk.o drvutil_video.o\r
KERNEL_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o\r
KERNEL_OBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o vfs/select.o\r
KERNEL_OBJ += vfs/fs/root.o vfs/fs/devfs.o\r
BUILDINFO_OBJ := obj-$(PLATFORM)/buildinfo.o\r
BUILDINFO_SRC := $(BUILDINFO_OBJ:%.o=%.c)\r
\r
-OBJ := helpers.o threads.o server.o syscalls.o\r
+OBJ := helpers.o threads.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 := $(addprefix obj-$(PLATFORM)/,$(OBJ))\r
N_OBJ := $(addprefix obj-$(PLATFORM)/,$(N_OBJ))\r
DEPFILES := $(DEPFILES:%=%.dep)\r
\r
CPPFLAGS += -I include/ -I $(KERNEL_SRC)include/\r
-CFLAGS += -Wall -g\r
+CFLAGS += -Wall -g -std=gnu99\r
LDFLAGS += -lSDL -lSDLmain -g -Wl,--defsym,__buildnum=$(BUILD_NUM)\r
\r
ifeq ($(PLATFORM),win)\r
\r
$(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) Makefile\r
@echo "" > $@\r
+ $(eval _GITHASH=$(shell git log -n 1 | head -n 1 | awk '{print $$2}'))\r
+ $(eval _GITCHANGED=$(shell git status --porcelain | grep -c '^ M '))\r
@echo "const char gsKernelVersion[] = \"$(ACESS_VERSION)\";" >> $@\r
- @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@\r
+ @echo "const char gsGitHash[] = \"$(_GITHASH)\";" >> $@\r
+ @echo "const char gsBuildInfo[] = \"Acess2 v$(KERNEL_VERSION) $(ARCH)-$(PLATFORM)\\\\r\\\\n\"" >> $@\r
+ @echo " \"Build $(shell hostname --fqdn):$(BUILD_NUM) Git $(_GITHASH) - $(_GITCHANGED) modified\";" >> $@\r
@echo "const int giBuildNumber = $(BUILD_NUM);" >> $@\r
$(BUILDINFO_OBJ): $(BUILDINFO_SRC)\r
@echo [CC] -o $@\r
free(Ptr);
}
+void Heap_Dump(void)
+{
+}
+
tPAddr MM_GetPhysAddr(tVAddr VAddr)
{
return VAddr; // HACK!
return tv.tv_sec * 1000 + tv.tv_usec/1000;
}
+void IPStack_SendDebugText(const char *str)
+{
+ // nop
+}
+
#define SHORTLOCK(...)
#define SHORTREL(...)
+#define CPU_HAS_LOCK(...) 0
//#define NUM_CFG_ENTRIES 10
+extern void Debug_PutCharDebug(char ch);
+extern void Debug_PutStringDebug(const char *str);
+
#endif
--- /dev/null
+#ifndef _THREADS_INT_H_
+#define _THREADS_INT_H_
+
+/**
+ * \brief IPC Message
+ */
+typedef struct sMessage
+{
+ struct sMessage *Next; //!< Next message in thread's inbox
+ tTID Source; //!< Source thread ID
+ Uint Length; //!< Length of message data in bytes
+ Uint8 Data[]; //!< Message data
+} tMsg;
+
+typedef struct sProcess
+{
+ int nThreads;
+ int NativePID;
+ char *CWD;
+ char *Chroot;
+ int MaxFD;
+} tProcess;
+
+struct sThread
+{
+ struct sThread *GlobalNext;
+ struct sThread *Next;
+
+ int KernelTID;
+
+ tTID TID, PID;
+ tUID UID, GID;
+
+ struct sThread *Parent;
+
+ char *ThreadName;
+
+ int Status; // 0: Dead, 1: Active, 2: Paused, 3: Asleep
+ int ExitStatus;
+ int _errno;
+
+ // Threads waiting for this thread to exit.
+ // Quit logic:
+ // - Wait for `WaitingThreads` to be non-null (maybe?)
+ // - Wake first in the queue, wait for it to be removed
+ // - Repeat
+ // - Free thread and quit kernel thread
+ struct sThread *WaitingThreads;
+ struct sThread *WaitingThreadsEnd;
+
+ tProcess *Process;
+
+ Uint32 Events, WaitMask;
+ void *EventSem; // Should be SDL_sem, but I don't want SDL in this header
+
+ // Message queue
+ tMsg * volatile Messages; //!< Message Queue
+ tMsg *LastMessage; //!< Last Message (speeds up insertion)
+};
+
+enum {
+ THREAD_STAT_NULL, // Invalid process
+ THREAD_STAT_ACTIVE, // Running and schedulable process
+ THREAD_STAT_SLEEPING, // Message Sleep
+ THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
+ THREAD_STAT_SEMAPHORESLEEP, // Semaphore Sleep
+ THREAD_STAT_QUEUESLEEP, // Queue
+ THREAD_STAT_EVENTSLEEP, // Event sleep
+ THREAD_STAT_WAITING, // ??? (Waiting for a thread)
+ THREAD_STAT_PREINIT, // Being created
+ THREAD_STAT_ZOMBIE, // Died/Killed, but parent not informed
+ THREAD_STAT_DEAD, // Awaiting burial (free)
+ THREAD_STAT_BURIED // If it's still on the list here, something's wrong
+};
+extern struct sThread *Threads_GetThread(Uint TID);
+
+#endif
+
* nativefs.c\r
* - Host filesystem access\r
*/\r
-#define DEBUG 1\r
+#define DEBUG 0\r
#define off_t _acess_off_t\r
#include <acess.h> // Acess\r
#include <vfs.h> // Acess\r
tVFS_Node *NativeFS_Mount(const char *Device, const char **Arguments);\r
void NativeFS_Unmount(tVFS_Node *Node);\r
tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name);\r
-char *NativeFS_ReadDir(tVFS_Node *Node, int Position);\r
-Uint64 NativeFS_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);\r
+ int NativeFS_ReadDir(tVFS_Node *Node, int Position, char Dest[FILENAME_MAX]);\r
+size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer);\r
+size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer);\r
+void NativeFS_Close(tVFS_Node *Node);\r
\r
// === GLOBALS ===\r
tVFS_NodeType gNativeFS_FileNodeType = {\r
- .Read = NativeFS_Read\r
+ .Read = NativeFS_Read,\r
+ .Write = NativeFS_Write,\r
+ .Close = NativeFS_Close\r
};\r
tVFS_NodeType gNativeFS_DirNodeType = {\r
.FindDir = NativeFS_FindDir,\r
.ReadDir = NativeFS_ReadDir,\r
+ .Close = NativeFS_Close\r
};\r
tVFS_Driver gNativeFS_Driver = {\r
- "nativefs", 0,\r
- NativeFS_Mount, NativeFS_Unmount,\r
- NULL,\r
+ .Name = "nativefs",\r
+ .InitDevice = NativeFS_Mount,\r
+ .Unmount = NativeFS_Unmount\r
};\r
\r
// === CODE ===\r
\r
dp = opendir(Device);\r
if(!dp) {\r
- Log_Warning("NativeFS", "ERRO: Unable to open device root '%s'", Device);\r
+ Log_Warning("NativeFS", "ERROR: Unable to open device root '%s'", Device);\r
return NULL;\r
}\r
\r
ret->Data = strdup(Device);\r
ret->ImplInt = strlen(ret->Data);\r
ret->ImplPtr = info;\r
- ret->Inode = (Uint64)dp;\r
+ ret->Inode = (Uint64)(tVAddr)dp;\r
ret->Flags = VFS_FFLAG_DIRECTORY;\r
\r
ret->Type = &gNativeFS_DirNodeType; \r
- \r
+\r
return ret;\r
}\r
\r
{\r
tNativeFS *info = Node->ImplPtr;\r
Inode_ClearCache( info->InodeHandle );\r
- closedir( (void *)Node->Inode );\r
+ closedir( (void *)(tVAddr)Node->Inode );\r
free(Node->Data);\r
free(Node);\r
free(info);\r
void NativeFS_Close(tVFS_Node *Node)\r
{\r
tNativeFS *info = Node->ImplPtr;\r
- Inode_UncacheNode( info->InodeHandle, Node->Inode );\r
+ DIR *dp = (Node->Flags & VFS_FFLAG_DIRECTORY) ? (DIR*)(tVAddr)Node->Inode : 0;\r
+ FILE *fp = (Node->Flags & VFS_FFLAG_DIRECTORY) ? 0 : (FILE*)(tVAddr)Node->Inode;\r
+ \r
+ if( Inode_UncacheNode( info->InodeHandle, Node->Inode ) == 1 ) {\r
+ if(dp) closedir(dp);\r
+ if(fp) fclose(fp);\r
+ }\r
}\r
\r
tVFS_Node *NativeFS_FindDir(tVFS_Node *Node, const char *Name)\r
{\r
- char *path = malloc(Node->ImplInt + 1 + strlen(Name) + 1);\r
+ char *path;\r
tNativeFS *info = Node->ImplPtr;\r
tVFS_Node baseRet;\r
struct stat statbuf;\r
ENTER("pNode sName", Node, Name);\r
\r
// Create path\r
+ path = malloc(Node->ImplInt + 1 + strlen(Name) + 1);\r
strcpy(path, Node->Data);\r
path[Node->ImplInt] = '/';\r
strcpy(path + Node->ImplInt + 1, Name);\r
if( S_ISDIR(statbuf.st_mode) )\r
{\r
LOG("Directory");\r
- baseRet.Inode = (Uint64) opendir(path);\r
+ baseRet.Inode = (Uint64)(tVAddr) opendir(path);\r
baseRet.Type = &gNativeFS_DirNodeType;\r
baseRet.Flags |= VFS_FFLAG_DIRECTORY;\r
baseRet.Size = -1;\r
else\r
{\r
LOG("File");\r
- baseRet.Inode = (Uint64) fopen(path, "r+");\r
+ baseRet.Inode = (Uint64)(tVAddr) fopen(path, "r+");\r
baseRet.Type = &gNativeFS_FileNodeType;\r
\r
fseek( (FILE*)(tVAddr)baseRet.Inode, 0, SEEK_END );\r
return Inode_CacheNode(info->InodeHandle, &baseRet);\r
}\r
\r
-char *NativeFS_ReadDir(tVFS_Node *Node, int Position)\r
+int NativeFS_ReadDir(tVFS_Node *Node, int Position, char Dest[FILENAME_MAX])\r
{\r
struct dirent *ent;\r
DIR *dp = (void*)(tVAddr)Node->Inode;\r
- char *ret;\r
\r
ENTER("pNode iPosition", Node, Position);\r
\r
} while(Position-- && ent);\r
\r
if( !ent ) {\r
- LEAVE('n');\r
- return NULL;\r
+ LEAVE('i', -ENOENT);\r
+ return -ENOENT;\r
}\r
\r
- ret = strdup(ent->d_name);\r
+ strncpy(Dest, ent->d_name, FILENAME_MAX);\r
\r
// TODO: Unlock node \r
\r
- LEAVE('s', ret);\r
- return ret;\r
+ LEAVE('i', 0);\r
+ return 0;\r
}\r
\r
-Uint64 NativeFS_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)\r
+size_t NativeFS_Read(tVFS_Node *Node, _acess_off_t Offset, size_t Length, void *Buffer)\r
{\r
- ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);\r
- if( fseek( (void *)Node->Inode, Offset, SEEK_SET ) != 0 )\r
+ ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
+ if( fseek( (FILE *)(tVAddr)Node->Inode, Offset, SEEK_SET ) != 0 )\r
{\r
LEAVE('i', 0);\r
return 0;\r
}\r
LEAVE('-');\r
- return fread( Buffer, 1, Length, (void *)Node->Inode );\r
+ return fread( Buffer, 1, Length, (FILE *)(tVAddr)Node->Inode );\r
+}\r
+\r
+size_t NativeFS_Write(tVFS_Node *Node, _acess_off_t Offset, size_t Length, const void *Buffer)\r
+{\r
+ FILE *fp = (FILE *)(tVAddr)Node->Inode;\r
+ ENTER("pNode XOffset xLength pBuffer", Node, Offset, Length, Buffer);\r
+ if( fseek( fp, Offset, SEEK_SET ) != 0 )\r
+ {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
+ size_t ret = fwrite( Buffer, 1, Length, fp );\r
+ fflush( fp );\r
+ LEAVE('i', ret);\r
+ return ret;\r
+\r
}\r
# include <unistd.h>
# include <sys/socket.h>
# include <netinet/in.h>
+# include <arpa/inet.h> // inet_ntop
#endif
#include "../syscalls.h"
//#include <debug.h>
-#define USE_TCP 0
+#define USE_TCP 1
#define MAX_CLIENTS 16
// === TYPES ===
int ClientID;
SDL_Thread *WorkerThread;
#if USE_TCP
+ int Socket;
#else
tRequestHeader *CurrentRequest;
struct sockaddr_in ClientAddr;
// HACK: Should have these in a header
extern void Log_Debug(const char *Subsys, const char *Message, ...);
extern void Log_Notice(const char *Subsys, const char *Message, ...);
+extern void Log_Warning(const char *Subsys, const char *Message, ...);
// === PROTOTYPES ===
tClient *Server_GetClient(int ClientID);
// Allocate a thread for the process
ret->ClientID = ClientID;
+ #if USE_TCP
+ ret->Socket = 0;
+ #else
ret->CurrentRequest = NULL;
+ #endif
if( !ret->WorkerThread ) {
+ #if USE_TCP
+ #else
ret->WaitFlag = SDL_CreateCond();
ret->Mutex = SDL_CreateMutex();
SDL_mutexP( ret->Mutex );
+ #endif
ret->WorkerThread = SDL_CreateThread( Server_WorkerThread, ret );
}
int Server_WorkerThread(void *ClientPtr)
{
tClient *Client = ClientPtr;
+
+ #if USE_TCP
+ for( ;; )
+ {
+ fd_set fds;
+ int nfd = Client->Socket;
+ FD_ZERO(&fds);
+ FD_SET(Client->Socket, &fds);
+
+ select(nfd, &fds, NULL, NULL, NULL); // TODO: Timeouts?
+
+ if( FD_ISSET(Client->Socket, &fds) )
+ {
+ const int ciMaxParamCount = 6;
+ char lbuf[sizeof(tRequestHeader) + ciMaxParamCount*sizeof(tRequestValue)];
+ tRequestHeader *hdr = (void*)lbuf;
+ size_t len = recv(Client->Socket, hdr, sizeof(*hdr), 0);
+ if( len != sizeof(hdr) ) {
+ // Oops?
+ }
+
+ if( hdr->NParams > ciMaxParamCount ) {
+ // Oops.
+ }
+
+ len = recv(Client->Socket, hdr->Params, hdr->NParams*sizeof(tRequestValue), 0);
+ if( len != hdr->NParams*sizeof(tRequestValue) ) {
+ // Oops.
+ }
+
+ // Get buffer size
+ size_t hdrsize = sizeof(tRequestHeader) + hdr->NParams*sizeof(tRequestValue);
+ size_t bufsize = hdrsize;
+ int i;
+ for( i = 0; i < hdr->NParams; i ++ )
+ {
+ if( hdr->Params[i].Flags & ARG_FLAG_ZEROED )
+ ;
+ else {
+ bufsize += hdr->Params[i].Length;
+ }
+ }
+
+ // Allocate full buffer
+ hdr = malloc(bufsize);
+ memcpy(hdr, lbuf, hdrsize);
+ len = recv(Client->Socket, hdr->Params + hdr->NParams, bufsize - hdrsize, 0);
+ if( len != bufsize - hdrsize ) {
+ // Oops?
+ }
+
+ int retlen;
+ tRequestHeader *retHeader;
+ retHeader = SyscallRecieve(hdr, &retlen);
+ if( !retHeader ) {
+ // Some sort of error
+ }
+
+ send(Client->Socket, retHeader, retlen, 0);
+
+ // Clean up
+ free(hdr);
+ }
+ }
+ #else
tRequestHeader *retHeader;
tRequestHeader errorHeader;
int retSize = 0;
int sentSize;
int cur_client_id = 0;
-
- #if USE_TCP
- #else
for( ;; )
{
// Wait for something to do
while( Client->CurrentRequest == NULL )
SDL_CondWait(Client->WaitFlag, Client->Mutex);
+// Log_Debug("AcessSrv", "Worker got message %p", Client->CurrentRequest);
+
if(Client->ClientID != cur_client_id) {
+// Log_Debug("AcessSrv", "Client thread ID changed from %i to %i",
+// cur_client_id, Client->ClientID);
Threads_SetThread( Client->ClientID );
cur_client_id = Client->ClientID;
}
- // Get the response
- retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
-
+ // Debug
{
int callid = Client->CurrentRequest->CallID;
Log_Debug("AcessSrv", "Client %i request %i %s",
);
}
-
+ // Get the response
+ retHeader = SyscallRecieve(Client->CurrentRequest, &retSize);
+
if( !retHeader ) {
// Return an error to the client
printf("ERROR: SyscallRecieve failed\n");
for( ;; )
{
#if USE_TCP
- struct sockaddr_in client;
- uint clientSize = sizeof(client);
- int clientSock = accept(gSocket, (struct sockaddr*)&client, &clientSize);
+ struct sockaddr_in clientaddr;
+ socklen_t clientSize = sizeof(clientaddr);
+ int clientSock = accept(gSocket, (struct sockaddr*)&clientaddr, &clientSize);
if( clientSock < 0 ) {
perror("SyscallServer - accept");
break ;
}
+
+ char addrstr[4*8+8+1];
+ inet_ntop(clientaddr.sin_family, &clientaddr.sin_addr, addrstr, sizeof(addrstr));
+ Log_Debug("Server", "Client connection %s:%i\n", addrstr, ntohs(clientaddr.sin_port));
- Log("Client connection %x:%i\n",
- ntohl(client.sin_addr), ntohs(client.sin_port)
- );
+ // Perform auth
+ size_t len;
+ tRequestAuthHdr authhdr;
+ len = recv(clientSock, &authhdr, sizeof(authhdr), 0);
+ if( len != sizeof(authhdr) ) {
+ // Some form of error?
+ }
+
+ tClient *client;
+ if( authhdr.pid == 0 ) {
+ // Allocate PID and client structure/thread
+ client = Server_GetClient(0);
+ client->Socket = clientSock;
+ authhdr.pid = client->ClientID;
+ }
+ else {
+ // Get client structure and make sure it's unused
+ // - Auth token / verifcation?
+ client = Server_GetClient(authhdr.pid);
+ if( client->Socket != 0 ) {
+ Log_Warning("Server", "Client (%i)%p owned by FD%i but %s:%i tried to use it",
+ authhdr.pid, client, addrstr, clientaddr.sin_port);
+ authhdr.pid = 0;
+ }
+ else {
+ client->Socket = clientSock;
+ }
+ }
+ len = send(clientSock, &authhdr, sizeof(authhdr), 0);
+ if( len != sizeof(authhdr) ) {
+ // Ok, this is an error
+ perror("Sending auth reply");
+ }
+
+ // All done, client thread should be watching now
+
#else
char data[BUFSIZ];
tRequestHeader *req = (void*)data;
continue;
}
- Log_Debug("AcessSrv", "Message from Client %i (%p)",
- client->ClientID, client);
+// Log_Debug("AcessSrv", "Message from Client %i (%p)",
+// client->ClientID, client);
// Make a copy of the request data
req = malloc(length);
*
* Syscall Distribution
*/
-#define DEBUG 1
+#define DEBUG 0
#include <acess.h>
#include <threads.h>
#include <events.h>
return Proc_SendMessage(a0, Sizes[1], a1);
);
-SYSCALL2(Syscall_GetMessage, "dd", Uint *, void *,
- if( Sizes[0] < sizeof(*a0) )
+SYSCALL2(Syscall_GetMessage, "dd", uint32_t *, void *,
+ if( a0 && Sizes[0] < sizeof(*a0) ) {
+ Log_Notice("Syscalls", "Syscall_GetMessage - Arg 1 Undersize (%i < %i)",
+ Sizes[0], sizeof(*a0));
return -1;
- return Proc_GetMessage(a0, a1);
+ }
+ Uint tmp;
+ int rv;
+ if( a0 ) {
+ rv = Proc_GetMessage(&tmp, a1);
+ *a0 = tmp;
+ }
+ else
+ rv = Proc_GetMessage(NULL, a1);
+ return rv;
);
SYSCALL1(Syscall_WaitEvent, "i", int,
}
formatString[i] = '\0';
- //LOG("Request %i(%s) '%s'", Request->CallID, casSYSCALL_NAMES[Request->CallID], formatString);
+ LOG("Request %i(%s) '%s'", Request->CallID, casSYSCALL_NAMES[Request->CallID], formatString);
{
char argListData[argListLen];
}
// Check for non-resident data
- if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
+ if( Request->Params[i].Length == 0 )
+ {
+ returnData[i] = NULL;
+ *(void**)&argListData[argListLen] = NULL;
+ argListLen += sizeof(void*);
+ }
+ else if( Request->Params[i].Flags & ARG_FLAG_ZEROED )
{
// Allocate and zero the buffer
returnData[i] = calloc(1, Request->Params[i].Length);
#include <acess.h>
#include <mutex.h>
#include <semaphore.h>
+#include <rwlock.h>
#include <events.h>
+#include <threads_int.h>
#undef CLONE_VM // Such a hack
#undef off_t
} tState;
#endif
-typedef struct sProcess
-{
- int nThreads;
- int NativePID;
- char *CWD;
- char *Chroot;
- int MaxFD;
-} tProcess;
-
-struct sThread
-{
- struct sThread *GlobalNext;
- struct sThread *Next;
-
- int KernelTID;
-
- tTID TID, PID;
- tUID UID, GID;
-
- struct sThread *Parent;
-
- char *ThreadName;
-
- int State; // 0: Dead, 1: Active, 2: Paused, 3: Asleep
- int ExitStatus;
- int _errno;
-
- // Threads waiting for this thread to exit.
- // Quit logic:
- // - Wait for `WaitingThreads` to be non-null (maybe?)
- // - Wake first in the queue, wait for it to be removed
- // - Repeat
- // - Free thread and quit kernel thread
- struct sThread *WaitingThreads;
- struct sThread *WaitingThreadsEnd;
-
- tProcess *Process;
-
- Uint32 Events, WaitMask;
- SDL_sem *EventSem;
-
-};
-
// === PROTOTYPES ===
int Threads_Wake(tThread *Thread);
.MaxFD = 100
};
tThread gThreadZero = {
- .State=1,
+ .Status=THREAD_STAT_ACTIVE,
.ThreadName="ThreadZero",
.Process = &gProcessZero
};
Log_Error("Threads", "_SetThread - Thread %i is not on global list", TID);
}
-tThread *Threads_GetThread(int TID)
+tThread *Threads_GetThread(Uint TID)
{
tThread *thread;
for( thread = gpThreads; thread; thread = thread->GlobalNext )
{
- if( thread->TID == TID )
+ if( thread->TID == TID ) {
return thread;
+ }
}
return NULL;
}
if(!thread) return -1;
us->Next = NULL;
- us->State = 3;
+ us->Status = THREAD_STAT_WAITING;
// TODO: Locking
if(thread->WaitingThreadsEnd)
{
int Threads_Wake(tThread *Thread)
{
- Thread->State = 0;
+ Thread->Status = THREAD_STAT_ACTIVE;
Threads_PostEvent(Thread, THREAD_EVENT_WAKEUP);
return 0;
}
return thread->PID;
}
+// --------------------------------------------------------------------
+// Mutexes
+// --------------------------------------------------------------------
int Mutex_Acquire(tMutex *Mutex)
{
if(!Mutex->Protector.IsValid) {
pthread_mutex_unlock( &Mutex->Protector.Mutex );
}
+// --------------------------------------------------------------------
+// Semaphores
+// --------------------------------------------------------------------
void Semaphore_Init(tSemaphore *Sem, int InitValue, int MaxValue, const char *Module, const char *Name)
{
memset(Sem, 0, sizeof(tSemaphore));
return AmmountToAdd;
}
+// --------------------------------------------------------------------
+// Event handling
+// --------------------------------------------------------------------
+int RWLock_AcquireRead(tRWLock *Lock)
+{
+ if( !Lock->ReaderWaiting ) {
+ Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t));
+ pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 );
+ }
+ pthread_rwlock_rdlock( (void*)Lock->ReaderWaiting );
+ return 0;
+}
+int RWLock_AcquireWrite(tRWLock *Lock)
+{
+ if( !Lock->ReaderWaiting ) {
+ Lock->ReaderWaiting = malloc(sizeof(pthread_rwlock_t));
+ pthread_rwlock_init( (void*)Lock->ReaderWaiting, 0 );
+ }
+ pthread_rwlock_wrlock( (void*)Lock->ReaderWaiting );
+ return 0;
+}
+void RWLock_Release(tRWLock *Lock)
+{
+ pthread_rwlock_unlock( (void*)Lock->ReaderWaiting );
+}
+
+
+// --------------------------------------------------------------------
+// Event handling
+// --------------------------------------------------------------------
Uint32 Threads_WaitEvents(Uint32 Mask)
{
Uint32 rv;
}
}
+void Threads_ClearEvent(Uint32 EventMask)
+{
+ gpCurrentThread->Events &= ~EventMask;
+}
+
--- /dev/null
+/*
+ * Acess2 Native Kernel
+ * - Acess kernel emulation on another OS using SDL and UDP
+ *
+ * time.c
+ * - Timer code
+ */
+#include <acess.h>
+#include <timers.h>
+
+struct sTimer {
+ tTimer *Next;
+ Sint64 FiresAfter;
+ void (*Callback)(void*);
+ void *Argument;
+ BOOL bActive;
+};
+
+// === CODE ===
+tTimer *Time_CreateTimer(int Delta, tTimerCallback *Callback, void *Argument)
+{
+ return NULL;
+}
+
+tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument)
+{
+ return NULL;
+}
+
+void Time_FreeTimer(tTimer *Timer)
+{
+}
+
+void Time_ScheduleTimer(tTimer *Timer, int Delta)
+{
+}
+
+void Time_RemoveTimer(tTimer *Timer)
+{
+}
/*
- * AcessNative
+ * AcessNative Dynamic Linker
+ * - By John Hodge (thePowersGang)
+ *
+ * binary.c
+ * - Provides binary loading and type abstraction
*/
-#define DEBUG 1
+#define DEBUG 0
#include "common.h"
#include <stdint.h>
#include <stdio.h>
extern int ElfGetSymbol(void *Base, char *Name, uintptr_t *ret, size_t *size);
extern int ciNumBuiltinSymbols;
extern tSym caBuiltinSymbols[];
+extern char **gEnvP;
// === PROTOTYPES ===
void Binary_AddToList(const char *Filename, void *Base, tBinFmt *Format);
}
ret = Binary_Load(path, (uintptr_t*)&entry);
- printf("LOADED '%s' to %p (Entry=%p)\n", path, ret, entry);
+ if( ret != (void*)-1 )
+ Debug("LOADED '%s' to %p (Entry=%p)", path, ret, entry);
free(path);
#if DEBUG
#if DEBUG
printf("Calling '%s' entry point %p\n", Name, entry);
#endif
- entry(ret, 0, argv, NULL);
+ entry(ret, 0, argv, gEnvP);
}
return ret;
*\r
* ELF Executable Loader Code\r
*/\r
-#define DEBUG 1\r
+#define DEBUG 0\r
#include <stdlib.h>\r
#include <stdio.h>\r
#include <string.h>\r
\r
ENTER("iFD", FD);\r
\r
- #if BITS <= 32\r
- Warning("ELF64 being loaded in 32-bit env, this may not work");\r
- #endif\r
+ if( sizeof(void*) == 4) {\r
+ Warning("ELF64 being loaded in 32-bit env, this may not work");\r
+ }\r
\r
// Check for a program header\r
if(hdr->e_phoff == 0) {\r
* - Exported functions
*/
#define DONT_INCLUDE_SYSCALL_NAMES 1
-#include "../../Usermode/include/acess/sys.h"
+#include "../../Usermode/Libraries/ld-acess.so_src/include_exp/acess/sys.h"
#include "../syscalls.h"
#include "exports.h"
#include <stdarg.h>
size_t acess_read(int FD, void *Dest, size_t Bytes) {
if(FD & NATIVE_FILE_MASK)
return native_read(FD & (NATIVE_FILE_MASK-1), Dest, Bytes);
- DEBUG("read(0x%x, 0x%x, *%p)", FD, Bytes, Dest);
+// if( FD > 2 )
+ DEBUG("read(0x%x, 0x%x, *%p)", FD, Bytes, Dest);
return _Syscall(SYS_READ, ">i >i <d", FD, Bytes, Bytes, Dest);
}
size_t acess_write(int FD, const void *Src, size_t Bytes) {
if(FD & NATIVE_FILE_MASK)
return native_write(FD & (NATIVE_FILE_MASK-1), Src, Bytes);
- DEBUG("write(0x%x, 0x%x, %p\"%.*s\")", FD, Bytes, Src, Bytes, (char*)Src);
+// if( FD > 2 )
+ DEBUG("write(0x%x, 0x%x, %p\"%.*s\")", FD, Bytes, Src, Bytes, (char*)Src);
return _Syscall(SYS_WRITE, ">i >i >d", FD, Bytes, Bytes, Src);
}
int acess_ioctl(int fd, int id, void *data) {
int len;
- // NOTE: 1024 byte size is a hack
DEBUG("ioctl(%i, %i, %p)", fd, id, data);
+ // NOTE: The length here is hacky and could break
if( data == NULL )
len = 0;
else
int lastlen;
lastlen = _Syscall(SYS_GETMSG, "<d <d",
- SourceTID ? sizeof(int) : 0, SourceTID,
+ SourceTID ? sizeof(uint32_t) : 0, SourceTID,
Data ? 1024 : 0, Data
);
return lastlen;
va_start(args, Format);
- printf("[_SysDebug %i]", giSyscall_ClientID);
+ printf("[_SysDebug %i] ", giSyscall_ClientID);
vprintf(Format, args);
printf("\n");
#ifndef _EXPORTS_H_
#define _EXPORTS_H_
+#include <stddef.h>
+
// Syscall request (used by acess_*)
extern uint64_t _Syscall(int SyscallID, const char *ArgTypes, ...);
// === PROTOTYPES ===
void CallUser(void *Entry, int argc, char *argv[], char **envp) __attribute__((noreturn));
+// === GLOBALS ===
+char **gEnvP;
+
// === CODE ===
int main(int argc, char *argv[], char **envp)
{
int (*appMain)(int, char *[], char **);
void *base;
int rv;
+
+ gEnvP = envp;
Request_Preinit();
end <<= (sizeof(intptr_t)*8-MaxBits);
end >>= (sizeof(intptr_t)*8-MaxBits);
- printf("end = %p\n", (void*)end);
+// printf("end = %p\n", (void*)end);
// for( base = 0; base < end - size; base -= PAGE_SIZE )
for( base = end - size + 1; base > 0; base -= PAGE_SIZE )
* uint8_t paramData[SUM(params[].Lengh)];
*/
+typedef struct {
+ uint32_t pid;
+ uint32_t key;
+} tRequestAuthHdr;
+
typedef struct sRequestValue {
/// \see eArgumentTypes
uint16_t Type;
--- /dev/null
+
+ARM_CPUNAME = gerneric-armv6
+CC = arm-armv6-eabi-gcc -mcpu=$(ARM_CPUNAME)
+AS = arm-armv6-eabi-gcc -mcpu=$(ARM_CPUNAME) -c
+LD = arm-armv6-eabi-ld
+OBJDUMP = arm-armv6-eabi-objdump
+DISASM = $(OBJDUMP) -d -S
+ARCHDIR = armv6
+STRIP = arm-elf-strip
+
+ASSUFFIX = S
+
+# Default Configuration
+ifeq ($(PLATFORM),)
+ PLATFORM=raspberrypi
+$(warning Defaulting to "PLATFORM=$(PLATFORM)")
+endif
+
--- /dev/null
+
+ifeq ($(PLATFORM),default)
+ $(error Please select a platform)
+endif
+
+#MODULES += armv7/GIC
+MODULES += Filesystems/InitRD
--- /dev/null
+
+include $(ACESSDIR)/BuildConf/armv6/default.mk
+ARM_CPUNAME = arm1176jzf-s
-CC = arm-elf-gcc
-AS = arm-elf-gcc -c
-LD = arm-elf-ld
+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-elf-objdump
DISASM = $(OBJDUMP) -d -S
ARCHDIR = armv7
include $(ACESSDIR)/BuildConf/armv7/default.mk
+ARM_CPUNAME = cortex-a8
MODULES += Input/PS2KbMouse
MODULES += Display/PL110
include $(ACESSDIR)/BuildConf/armv7/default.mk
+ARM_CPUNAME = cortex-a9
MODULES += Display/Tegra2Vid
+MODULES += USB/Core USB/EHCI
MODULES += Storage/FDDv2
MODULES += Network/NE2000 Network/RTL8139
MODULES += Network/VIARhineII
+MODULES += Network/E1000
MODULES += Display/VESA
MODULES += Display/BochsGA
#MODULES += Display/VIAVideo
MODULES += x86/ISADMA x86/VGAText
MODULES += USB/Core USB/UHCI
+#MODULES += USB/EHCI
#USB/OHCI
-MODULES += USB/HID
+MODULES += USB/HID USB/MSC
#MODULES += Interfaces/UDI
+
+DYNMODS += Filesystems/InitRD
-PREFIX := x86_64-pc-elf
-#PREFIX := x86_64-none-elf
+#PREFIX := x86_64-pc-elf
+PREFIX := x86_64-none-elf
CC := $(PREFIX)-gcc
LD := $(PREFIX)-ld
-MODULES += Storage/ATA
-MODULES += Storage/FDDv2
-MODULES += Network/NE2000 Network/RTL8139
-MODULES += Display/BochsGA
-MODULES += Interfaces/UDI
-MODULES += Input/PS2KbMouse
-MODULES += x86/ISADMA x86/VGAText
+include $(ACESSDIR)/BuildConf/x86/default.mk
+
+MODULES := $(filter-out Display/VESA,$(MODULES))
+
CPPFLAGS += -I./include -I./arch/$(ARCHDIR)/include -D_MODULE_NAME_=\"Kernel\"
CPPFLAGS += -D ARCH=$(ARCH) -D ARCHDIR=$(ARCHDIR) -D PLATFORM=\"$(PLATFORM)\" -D ARCHDIR_IS_$(ARCHDIR)=1 -D PLATFORM_is_$(PLATFORM)=1
CPPFLAGS += -D KERNEL_VERSION=$(KERNEL_VERSION) -ffreestanding
-CFLAGS += -Wall -fno-stack-protector -Wstrict-prototypes -g
+CFLAGS += -Wall -fno-stack-protector -Wstrict-prototypes -std=gnu99 -g
CFLAGS += -Wshadow -Wpointer-arith -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline -Wuninitialized
CFLAGS += -O3
LDFLAGS += -T arch/$(ARCHDIR)/link.ld -g
+LIBGCC_PATH := $(shell $(CC) -print-libgcc-file-name)
ifeq ($(PLATFORM),default)
OBJDIR := obj-$(ARCH)/
BUILDINFO_SRC := $(OBJDIR)buildinfo.c$(OBJSUFFIX)
OBJ := $(addprefix arch/$(ARCHDIR)/,$(A_OBJ))
-OBJ += heap.o drvutil.o logging.o debug.o lib.o adt.o time.o
+OBJ += pmemmap.o
+OBJ += heap.o logging.o debug.o lib.o libc.o adt.o time.o
+OBJ += drvutil_video.o drvutil_disk.o
OBJ += messages.o modules.o syscalls.o system.o
-OBJ += threads.o mutex.o semaphore.o workqueue.o events.o
-OBJ += drv/proc.o drv/fifo.o drv/iocache.o drv/pci.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/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 += 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
# Creates a stripped and compressed copy of the kernel
# and installs it to the target
install: $(BIN)
- @cp $(BIN) $(BIN)_
- @$(STRIP) $(BIN)_
- @gzip -c $(BIN)_ > $(GZBIN)
- @$(RM) $(BIN)_
$(xCP) $(GZBIN) $(DISTROOT)
# Compile API documentation
# Output binary
# - Links kernel
# - Disassembles it
-# - Gets a line count
# - Increments the build count
# - Does whatever architecture defined rules
$(BIN): $(OBJ) $(MODS) arch/$(ARCHDIR)/link.ld Makefile ../../BuildConf/$(ARCH)/Makefile.cfg ../../BuildConf/$(ARCH)/$(PLATFORM).mk
@echo --- LD -o $(BIN)
- @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) --defsym __buildnum=$$(( $(BUILD_NUM) + 1 )) -Map ../Map.$(ARCH).txt
+ @$(LD) $(LDFLAGS) -o $(BIN) $(OBJ) $(MODS) $(LIBGCC_PATH) --defsym __buildnum=$$(( $(BUILD_NUM) + 1 )) -Map ../Map.$(ARCH).txt
@$(DISASM) -S $(BIN) > $(BIN).dsm
- @wc -l $(SRCFILES) include/*.h > LineCounts.$(ARCH).txt
@echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum.$(ARCH)
$(POSTBUILD)
+ @cp $(BIN) $(BIN)_
+ @$(STRIP) $(BIN)_ || true
+ @gzip -c $(BIN)_ > $(GZBIN)
+ @$(RM) $(BIN)_
# Assembly Sources
$(OBJDIR)%.ao$(OBJSUFFIX): %.$(AS_SUFFIX) Makefile
@mkdir -p $(dir $@)
@$(AS) $(ASFLAGS) $< -o $@
ifeq ($(AS_SUFFIX),S)
- @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.ao.dep$(OBJSUFFIX) $<
+ @$(MAKEDEP) $(CPPFLAGS) -MT $@ -MP -o $(OBJDIR)$*.ao.dep$(OBJSUFFIX) $<
endif
# C Sources
@echo --- CC -o $@
@mkdir -p $(dir $@)
@$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
- @$(MAKEDEP) $(CPPFLAGS) -MT $@ -o $(OBJDIR)$*.o.dep$(OBJSUFFIX) $<
+ @$(MAKEDEP) $(CPPFLAGS) -MT $@ -MP -o $(OBJDIR)$*.o.dep$(OBJSUFFIX) $<
# Build-time linked modules
%.xo.$(ARCH):
include/syscalls.h include/syscalls.inc.asm: syscalls.lst Makefile GenSyscalls.pl
perl GenSyscalls.pl
-# Rules based on the makefile
-Makefile: ../../Makefile.cfg arch/$(ARCHDIR)/Makefile
+# Differences for the makefile
+Makefile: ../../Makefile.cfg ../../BuildConf/$(ARCH)/Makefile.cfg ../../BuildConf/$(ARCH)/$(PLATFORM).mk arch/$(ARCHDIR)/Makefile
# Build-time information (git hash and build number)
$(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) $(MODS) arch/$(ARCHDIR)/link.ld Makefile
+ $(eval _GITHASH=$(shell git log -n 1 | head -n 1 | awk '{print $$2}'))
+ $(eval _GITCHANGED=$(shell git status --porcelain | grep -c '^ M '))
@echo "#include <acess.h>" > $@
- @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@
+ @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\";" >> $@
# Compile rule for buildinfo (needs a special one because it's not a general source file)
$(BUILDINFO_OBJ): $(BUILDINFO_SRC)
@echo --- CC -o $@
# Dependency Files
-include $(DEPFILES)
+
--- /dev/null
+#
+# Acess2 Kernel
+# arm7 Architecture Makefile
+# arch/arm7/Makefile
+
+CPPFLAGS =
+CFLAGS =
+ASFLAGS =
+
+CPPFLAGS += -DMMU_PRESENT=1
+LDFLAGS +=
+LIBGCC_PATH = $(shell $(CC) --print-libgcc-file-name)
+
+A_OBJ = start.ao main.o lib.o lib.ao time.o pci.o debug.o
+A_OBJ += mm_phys.o mm_virt.o proc.o proc.ao
+
+#main.c: Makefile.BuildNum.$(ARCH)
+
+ifeq ($(PLATFORM),tegra2)
+ POSTBUILD = arm-elf-objcopy $(BIN) -O binary $(BIN)
+endif
--- /dev/null
+/**
+ * Acess2
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/debug.c
+ * - ARM7 Debug output
+ * NOTE: Currently designed for the realview-pb-a8 emulated by Qemu
+ */
+#include <acess.h>
+
+// === CONSTANTS ===
+//#define UART0_BASE 0x10009000
+#define UART0_BASE 0xF1000000 // Boot time mapped
+
+// === PROTOTYPES ===
+void KernelPanic_SetMode(void);
+void KernelPanic_PutChar(char Ch);
+void StartupPrint(const char *str);
+
+// === GLOBALS ===
+ int giDebug_SerialInitialised = 0;
+
+// === CODE ===
+void Debug_PutCharDebug(char ch)
+{
+ if(ch == '\n')
+ Debug_PutCharDebug('\r');
+
+ #if PLATFORM_is_tegra2
+ // Tegra2
+ while( !(*(volatile Uint32*)(UART0_BASE + 0x14) & (1 << 5)) )
+ ;
+ #endif
+
+// *(volatile Uint32*)(SERIAL_BASE + SERIAL_REG_DATA) = ch;
+ *(volatile Uint32*)(UART0_BASE) = ch;
+}
+
+void Debug_PutStringDebug(const char *str)
+{
+ for( ; *str; str++ )
+ Debug_PutCharDebug( *str );
+}
+
+void KernelPanic_SetMode(void)
+{
+}
+
+void KernelPanic_PutChar(char ch)
+{
+// Debug_PutCharDebug(ch);
+}
+
+void StartupPrint(const char *str)
+{
+}
+
--- /dev/null
+/*
+ * Acess2
+ * ARM7 Architecture Header
+ */
+#ifndef _ARCH_H_
+#define _ARCH_H_
+
+// === CONSTANTS ===
+#define INVLPTR ((void*)-1)
+#define BITS 32
+#define PAGE_SIZE 0x1000
+#define KERNEL_BASE 0x80000000 // 2GiB
+
+// === TYPES ===
+typedef unsigned int Uint;
+typedef unsigned char Uint8;
+typedef unsigned short Uint16;
+typedef unsigned long Uint32;
+typedef unsigned long long Uint64;
+typedef signed int Sint;
+typedef signed char Sint8;
+typedef signed short Sint16;
+typedef signed long Sint32;
+typedef signed long long Sint64;
+
+typedef int size_t;
+typedef char BOOL;
+
+typedef Uint32 tVAddr;
+typedef Uint32 tPAddr;
+
+#include "lock.h"
+
+// --- Debug
+extern void Debug_PutCharDebug(char Ch);
+extern void Debug_PutStringDebug(const char *String);
+
+// This should be elsewhere, but CBF
+extern void MM_SetupPhys(void);
+extern int MM_InitialiseVirtual(void);
+
+#define NO_IO_BUS 1
+
+#endif
--- /dev/null
+/*
+ * Acess2 ARMv7
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/include/assembly.h
+ * - Assembly specific macros
+ */
+#ifndef _ASSEMBLY_H_
+#define _ASSEMBLY_H_
+
+#define PUSH_GPRS \
+ str r0, [sp,#-1*4];\
+ str r1, [sp,#-2*4];\
+ str r2, [sp,#-3*4];\
+ str r3, [sp,#-4*4];\
+ str r4, [sp,#-5*4];\
+ str r5, [sp,#-6*4];\
+ str r6, [sp,#-7*4];\
+ str r7, [sp,#-8*4];\
+ str r8, [sp,#-9*4];\
+ str r9, [sp,#-10*4];\
+ str r10, [sp,#-11*4];\
+ str r11, [sp,#-12*4];\
+ str r12, [sp,#-13*4];\
+ str sp, [sp,#-14*4];\
+ str lr, [sp,#-15*4];\
+ sub sp, #16*4
+
+#define POP_GPRS add sp, #16*4; \
+ ldr r0, [sp,#-1*4]; \
+ ldr r1, [sp,#-2*4]; \
+ ldr r2, [sp,#-3*4]; \
+ ldr r3, [sp,#-4*4]; \
+ ldr r4, [sp,#-5*4]; \
+ ldr r5, [sp,#-6*4]; \
+ ldr r6, [sp,#-7*4]; \
+ ldr r7, [sp,#-8*4]; \
+ ldr r8, [sp,#-9*4]; \
+ ldr r9, [sp,#-10*4]; \
+ ldr r10, [sp,#-11*4]; \
+ ldr r11, [sp,#-12*4]; \
+ ldr r12, [sp,#-13*4]; \
+ ldr lr, [sp,#-15*4];
+
+#endif
+
--- /dev/null
+/*
+ * Acess2
+ * ARM7 Architecture
+ *
+ * lock.h - Hardware level spinlocks
+ */
+#ifndef _LOCK_H_
+#define _LOCK_H_
+
+// === CODE ===
+struct sShortSpinlock {
+ int Lock;
+};
+
+// --- Spinlocks ---
+static inline int IS_LOCKED(struct sShortSpinlock *Lock)
+{
+ return !!Lock->Lock;
+}
+
+static inline int CPU_HAS_LOCK(struct sShortSpinlock *Lock)
+{
+ // TODO: Handle multiple CPUs
+ return !!Lock->Lock;
+}
+
+static inline int SHORTLOCK(struct sShortSpinlock *Lock)
+{
+ #if 0
+ // Coped from linux, yes, but I know what it does now :)
+ Uint tmp;
+ __asm__ __volatile__ (
+ "1: ldrex %0, [%1]\n" // Exclusive LOAD
+ " teq %0, #0\n" // Check if zero
+ " strexeq %0, %2, [%1]\n" // Set to one if it is zero (releasing lock on the memory)
+ " teqeq %0, #0\n" // If the lock was avaliable, check if the write succeeded
+ " bne 1b" // If the lock was unavaliable, or the write failed, loop
+ : "=&r" (tmp) // Temp
+ : "r" (&Lock->Lock), "r" (1)
+ : "cc" // Condition codes clobbered
+ );
+ #elif 1
+ while( *(volatile int*)&Lock->Lock ) ;
+ Lock->Lock = 1;
+ #else
+ int v = 1;
+ while( v )
+ __asm__ __volatile__ (
+ "swp %0, %0, [%1]"
+ : "=r" (v) : "r" (&Lock->Lock)
+ : "cc"
+ );
+ #endif
+ return 1;
+}
+
+static inline void SHORTREL(struct sShortSpinlock *Lock)
+{
+ Lock->Lock = 0;
+}
+
+#endif
+
--- /dev/null
+/*
+ * Acess2
+ * ARM7 Virtual Memory Manager Header
+ */
+#ifndef _MM_VIRT_H_
+#define _MM_VIRT_H_
+
+#include "options.h"
+
+#define USER_STACK_COMM 0x04000 // Pages to allocate up front
+#define USER_STACK_SIZE 0x10000 // Stack space
+#define USER_STACK_TOP 0x78000000
+
+#define MM_USER_MIN 0x00001000
+#define USER_LIB_MAX 0x70000000
+#define MM_PPD_HANDLES 0x7F800000
+#define MM_TABLE1USER 0x7FC00000 // 2 GiB - 4 MiB
+#define MM_TABLE0USER 0x7FE00000 // 2 GiB - 2 MiB
+#define MM_KSTACK_BASE 0x7FE00000
+#define MM_KSTACK_END 0x80000000
+
+// Page Blocks are 12-bits wide (12 address bits used)
+// Hence, the table is 16KiB large (and must be so aligned)
+// and each block addresses 1MiB of data
+
+// First level table is aligned to 16KiB (restriction of TTBR reg)
+// - VMSAv6 uses two TTBR regs, determined by bit 31
+
+//#define KERNEL_BASE 0x80000000 // 2GiB
+
+#define MM_KHEAP_BASE 0x80800000 // 8MiB of kernel code
+#define MM_KHEAP_MAX 0xC0000000 // ~1GiB of kernel heap
+
+#define MM_MODULE_MIN 0xC0000000 // - 0xD0000000
+#define MM_MODULE_MAX 0xCF000000
+
+#define MM_GLOBALSTACKS 0xCF000000 // Global stacks
+#define MM_GLOBALSTACKS_END 0xD0000000
+
+// PMM Data, giving it 256MiB is overkill, but it's unused atm
+#define MM_MAXPHYSPAGE (1024*1024)
+// 2^(32-12) max pages
+// 8.125 bytes per page (for bitmap allocation)
+// = 8.125 MiB
+#define MM_PMM_BASE 0xE0000000
+#define MM_PMM_END 0xF0000000
+
+#define MM_HWMAP_BASE 0xF0000000 // Ent 0xF00
+#define MM_HWMAP_END 0xFE000000
+#define MM_TMPMAP_BASE 0xFE000000
+#define MM_TMPMAP_END 0xFF000000
+
+#define MM_KERNEL_VFS 0xFF000000 //
+#define MM_TABLE1KERN 0xFF800000 // - 0x???????? 4MiB
+//#define MM_TABLE0KERN 0xFFC00000 // - 0xFFE04000 16KiB
+
+#endif
--- /dev/null
+/*
+ * Acess2 ARMv6 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * options.h
+ * - C/ASM Shared constants
+ */
+#ifndef _ARMV7_OPTIONS_H_
+#define _ARMV7_OPTIONS_H_
+
+#define KERNEL_BASE 0x80000000
+
+#if PLATFORM_is_raspberrypi
+# define UART0_PADDR 0x7E215040 // Realview
+#else
+# error Unknown platform
+#endif
+
+#define MM_KSTACK_SIZE 0x2000 // 2 Pages
+
+#endif
+
--- /dev/null
+/*
+ * Acess2
+ * ARM7 Architecture
+ *
+ * proc.h - Arch-Dependent Process Management
+ */
+#ifndef _PROC_H_
+#define _PROC_H_
+
+#define MAX_CPUS 4
+#define USER_MAX 0x80000000
+
+// === STRUCTURES ===
+typedef struct {
+ Uint32 IP, SP;
+ Uint32 UserIP, UserSP;
+} tTaskState;
+
+typedef struct {
+ Uint32 Base;
+} tMemoryState;
+
+typedef struct {
+ union {
+ Uint32 Num;
+ Uint32 Error;
+ };
+ union {
+ Uint32 Arg1;
+ Uint32 Return;
+ };
+ union {
+ Uint32 Arg2;
+ Uint32 RetHi;
+ };
+ Uint32 Arg3;
+ Uint32 Arg4;
+ Uint32 Arg5;
+ Uint32 Arg6; // R6
+} tSyscallRegs;
+
+// === MACROS ===
+#define HALT() do{}while(0)
+
+// === PROTOTYPES ===
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 ARM
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/lib.S
+ * - Assembly editions of library functions
+ */
+#include "include/assembly.h"
+
+.globl __memcpy_byte
+__memcpy_byte:
+1:
+ tst r2, r2 @ Check counter
+ moveq pc, lr @ Return if zero
+ ldrb r3, [r1],#1 @ Read
+ strb r3, [r0],#1 @ Write
+ sub r2, #1
+ b 1b
+
+@
+@ Pre-aligned memcpy (32-bit blocks)
+@
+.globl __memcpy_align4
+__memcpy_align4:
+ push {r4}
+ mvn r3, #3 @ Mask for checking length
+
+ @ 4 byte chunk copies
+1: tst r2, r3
+ ldrne r4, [r1],#4
+ strne r4, [r0],#4
+ subne r2, #4
+ bne 1b
+
+ @ single byte copies to finish off
+2: tst r2, #3
+ beq 3f
+ ldrb r4, [r1],#1
+ strb r4, [r0],#1
+ sub r2, #1
+ b 2b
+
+3: pop {r4}
+ mov pc, lr
+
+@
+@ Division
+@
+.globl __divmod32_asm
+__divmod32_asm:
+ push {r4}
+ mov r4, #0 @ Return value
+ mov r3, #1 @ add value
+
+ @ Scan up for first larger multiple of 2
+1: cmp r0, r1 @ N < D
+ bmi 2f @ ^^
+ lsl r1, r1, #1 @ D <<= 1
+ lsls r3, r3, #1 @ add <<= 1
+ beq .err @ result is zero
+ b 1b
+
+ @ Go back down
+2: lsrs r3, r3, #1 @ add >>= 1
+ beq 3f @ Done (value is zero)
+ lsr r1, r1, #1 @ D >>= 1
+ cmp r0, r1 @ N < D
+ bmi 2b
+ sub r0, r1 @ N -= D
+ add r4, r3 @ ret += add
+ b 2b
+3:
+ tst r2, r2 @ Remainder (if wanted)
+ strne r0,[r2]
+ mov r0, r4 @ Return value
+ pop {r4}
+ mov pc, lr
+.err:
+ mov r0, #0
+ tst r2, r2
+ strne r0, [r2]
+ pop {r4}
+ mov pc, lr
+
--- /dev/null
+/*
+ * Acess2 ARM7 Port
+ *
+ * lib.c - Library Functions
+ */
+#include <acess.h>
+#include "../helpers.h"
+
+// === IMPORTS ===
+extern void __memcpy_align4(void *_dest, const void *_src, size_t _length);
+extern void __memcpy_byte(void *_dest, const void *_src, size_t _length);
+extern Uint32 __divmod32_asm(Uint32 Num, Uint32 Den, Uint32 *Rem);
+
+// === PROTOTYPES ===
+Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
+Uint32 __divmod32(Uint32 Num, Uint32 Den, Uint32 *Rem);
+#if 0
+Uint64 __udivdi3(Uint64 Num, Uint64 Den);
+Uint64 __umoddi3(Uint64 Num, Uint64 Den);
+Uint32 __udivsi3(Uint32 Num, Uint32 Den);
+Uint32 __umodsi3(Uint32 Num, Uint32 Den);
+Sint32 __divsi3(Sint32 Num, Sint32 Den);
+Sint32 __modsi3(Sint32 Num, Sint32 Den);
+#endif
+
+// === CODE ===
+void *memcpy(void *_dest, const void *_src, size_t _length)
+{
+ Uint8 *dst8 = _dest;
+ const Uint8 *src8 = _src;
+
+ if( ((tVAddr)_dest & 3) == 0 && ((tVAddr)_src & 3) == 0 )
+ {
+ __memcpy_align4(_dest, _src, _length);
+ return _dest;
+ }
+
+ // Handle small copies / Non-aligned
+ if( _length < 4 || ((tVAddr)_dest & 3) != ((tVAddr)_src & 3) )
+ {
+ __memcpy_byte(_dest, _src, _length);
+ return _dest;
+ }
+
+ // Force alignment
+ while( (tVAddr)dst8 & 3 ) *dst8 ++ = *src8++, _length --;
+
+ __memcpy_align4(dst8, src8, _length);
+
+ return _dest;
+}
+
+int memcmp(const void *_m1, const void *_m2, size_t _length)
+{
+ const Uint32 *m1, *m2;
+ const Uint8 *m1_8 = _m1, *m2_8 = _m2;
+
+ // Handle small copies / Non-aligned
+ if( _length < 4 || ((tVAddr)_m1 & 3) != ((tVAddr)_m1 & 3) )
+ {
+ for( ; _length--; m1_8++,m2_8++ ) {
+ if(*m1_8 != *m2_8) return *m1_8 - *m2_8;
+ }
+ return 0;
+ }
+
+ // Force alignment
+ for( ; (tVAddr)m1_8 & 3; m1_8 ++, m2_8 ++) {
+ if(*m1_8 != *m2_8) return *m1_8 - *m2_8;
+ }
+ m1 = (void *)m1_8; m2 = (void *)m2_8;
+
+ // DWORD copies
+ for( ; _length > 3; _length -= 4, m1++, m2++)
+ if(*m1 != *m2) return *m1 - *m2;
+
+ // Trailing bytes
+ m1_8 = (void*)m1; m2_8 = (void*)m2;
+ for( ; _length; _length --, m1_8++, m2_8++ )
+ if(*m1_8 != *m2_8) return *m1_8 - *m2_8;
+
+ return 0;
+}
+
+void *memset(void *_dest, int _value, size_t _length)
+{
+ Uint32 *dst, val32;
+ Uint8 *dst8 = _dest;
+
+ _value = (Uint8)_value;
+
+ // Handle small copies
+ if( _length < 4 )
+ {
+ for( ; _length--; dst8++ )
+ *dst8 = _value;
+ return _dest;
+ }
+
+ val32 = _value;
+ val32 |= val32 << 8;
+ val32 |= val32 << 16;
+
+ // Force alignment
+ while( (tVAddr)dst8 & 3 ) *dst8 ++ = _value;
+ dst = (void *)dst8;
+
+ // DWORD copies
+ for( ; _length > 3; _length -= 4)
+ *dst++ = val32;
+
+ // Trailing bytes
+ dst8 = (void*)dst;
+ for( ; _length; _length -- )
+ *dst8 ++ = _value;
+
+ return _dest;
+}
+
+DEF_DIVMOD(64)
+DEF_DIVMOD(32)
+
+Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
+{
+ Uint64 ret;
+ if(Den == 0) return 0; // TODO: #div0
+ if(Num < Den) {
+ if(Rem) *Rem = Num;
+ return 0;
+ }
+ if(Num == 0) {
+ if(Rem) *Rem = 0;
+ return 0;
+ }
+ if(Den == 1) {
+ if(Rem) *Rem = 0;
+ return Num;
+ }
+ if(Den == 2) {
+ if(Rem) *Rem = Num & 1;
+ return Num >> 1;
+ }
+ if(Den == 16) {
+ if(Rem) *Rem = Num & 0xF;
+ return Num >> 4;
+ }
+ if(Den == 32) {
+ if(Rem) *Rem = Num & 0x1F;
+ return Num >> 5;
+ }
+ if(Den == 0x1000) {
+ if(Rem) *Rem = Num & 0xFFF;
+ return Num >> 12;
+ }
+
+ if( !(Den >> 32) && !(Num >> 32) ) {
+ if(Rem) *Rem = 0; // Clear high bits
+ return __divmod32_asm(Num, Den, (Uint32*)Rem);
+ }
+
+ ret = __divmod64(Num, Den, Rem);
+ return ret;
+}
+
+#if 0
+// Unsigned Divide 64-bit Integer
+Uint64 __udivdi3(Uint64 Num, Uint64 Den)
+{
+ return DivMod64U(Num, Den, NULL);
+}
+
+// Unsigned Modulus 64-bit Integer
+Uint64 __umoddi3(Uint64 Num, Uint64 Den)
+{
+ Uint64 ret = 0;
+ DivMod64U(Num, Den, &ret);
+ return ret;
+}
+
+Uint32 __udivsi3(Uint32 Num, Uint32 Den)
+{
+ return __divmod32_asm(Num, Den, NULL);
+}
+
+Uint32 __umodsi3(Uint32 Num, Uint32 Den)
+{
+ Uint32 rem;
+ __divmod32_asm(Num, Den, &rem);
+ return rem;
+}
+#endif
+
+static inline Sint32 DivMod32S(Sint32 Num, Sint32 Den, Sint32 *Rem)
+{
+ Sint32 ret = 1;
+ if( Num < 0 ) {
+ ret = -ret;
+ Num = -Num;
+ }
+ if( Den < 0 ) {
+ ret = -ret;
+ Den = -Den;
+ }
+ if(ret < 0)
+ ret = -__divmod32(Num, Den, (Uint32*)Rem);
+ else
+ ret = __divmod32(Num, Den, (Uint32*)Rem);
+ return ret;
+}
+
+#if 0
+Sint32 __divsi3(Sint32 Num, Sint32 Den)
+{
+ return DivMod32S(Num, Den, NULL);
+}
+
+Sint32 __modsi3(Sint32 Num, Sint32 Den)
+{
+ Sint32 rem;
+ DivMod32S(Num, Den, &rem);
+ return rem;
+}
+#endif
+
--- /dev/null
+ENTRY (_start)
+
+_kernel_base = 0x80000000;
+_usertext_vbase = 0xFFFFE000;
+
+SECTIONS
+{
+ . = 0;
+ .init :
+ {
+ *(.init)
+ }
+ . += _kernel_base;
+ .text : AT( ADDR(.text) - _kernel_base )
+ {
+ *(.text*)
+ *(.rodata*)
+ }
+ __exidx_start = .;
+ .ARM.exidx : { *(.ARM.exidx*) }
+ __exidx_end = .;
+ .ARM.extab : { *(.ARM.extab*) }
+
+
+ /* HACKS: User accesible .text section */
+ . = ALIGN(0x1000);
+ gUsertextPhysStart = . - _kernel_base;
+ . = _usertext_vbase;
+ .usertext : AT( gUsertextPhysStart )
+ {
+ *(.usertext)
+ }
+ . += gUsertextPhysStart + _kernel_base - _usertext_vbase;
+
+ /* 0x4000 (4 pages) alignment needed for root table */
+ .data ALIGN(0x4000) : AT( ADDR(.data) - _kernel_base )
+ {
+ *(.padata)
+ *(.data*)
+
+ gKernelSymbols = .;
+ *(KEXPORT)
+ gKernelSymbolsEnd = .;
+
+ gKernelModules = .;
+ *(KMODULES)
+ gKernelModulesEnd = .;
+ }
+ .bss : AT( ADDR(.bss) - _kernel_base )
+ {
+ bss_start = .;
+ *(.bss*)
+ *(COMMON*)
+ . = ALIGN(0x1000);
+ *(.pabss)
+ bss_end = .;
+ }
+ gKernelEnd = .;
+}
--- /dev/null
+/*
+ * Acess2
+ *
+ * ARM7 Entrypoint
+ * arch/arm7/main.c
+ */
+#define DEBUG 0
+
+#include <acess.h>
+#include <modules.h>
+
+// === IMPORTS ===
+extern void Interrupts_Setup(void);
+extern void Arch_LoadBootModules(void);
+extern void Heap_Install(void);
+extern void Threads_Init(void);
+extern void System_Init(const char *Commandline);
+
+// === PROTOTYPES ===
+ int kmain(void);
+Uint32 ARMv7_int_HandleSyscalls(Uint32 Num, Uint32 *Args);
+
+// === CODE ===
+int kmain(void)
+{
+ LogF("Acess2 ARMv7 v"EXPAND_STR(KERNEL_VERSION)"\n");
+ LogF(" Git Hash %s\n", gsGitHash);
+ LogF(" Build %i\n", BUILD_NUM);
+
+ MM_SetupPhys();
+
+ LogF("Heap Setup...\n");
+ Heap_Install();
+
+ LogF("Threads Init...\n");
+ Threads_Init();
+
+ LogF("VFS Init...\n");
+ VFS_Init();
+
+ // Boot modules?
+ Module_EnsureLoaded("armv7_GIC");
+
+ //
+ LogF("Moving to arch-independent init\n");
+ #if PLATFORM_is_tegra2
+ System_Init("Acess2.armv7.bin /Acess=initrd: -VTerm:Video=Tegra2Vid");
+ #else
+ System_Init("Acess2.armv7.bin /Acess=initrd: -VTerm:Video=PL110");
+ #endif
+// System_Init("Acess2.armv7.bin /Acess=initrd:");
+ //TODO:
+ LogF("End of kmain(), for(;;) Threads_Sleep();\n");
+ for(;;)
+ Threads_Sleep();
+}
+
+void Arch_LoadBootModules(void)
+{
+}
+
+Uint32 ARMv7_int_HandleSyscalls(Uint32 Num, Uint32 *Args)
+{
+ Uint32 ret = -1, err = 0;
+ Uint32 addr;
+ ENTER("iNum xArgs[0] xArgs[1] xArgs[2] xArgs[3]",
+ Num, Args[0], Args[1], Args[2], Args[3]
+ );
+ switch(Num)
+ {
+ case 1:
+// Log_Debug("ARMv7", "__clear_cache(%p, %p)", Args[0], Args[1]);
+ // Align
+ Args[0] &= ~0xFFF;
+ Args[1] += 0xFFF; Args[1] &= ~0xFFF;
+ // Invalidate!
+ for( addr = Args[0]; addr < Args[1]; addr += 0x1000 )
+ {
+ LOG("addr = %p", addr);
+ __asm__ __volatile__ (
+ "mcrlt p15, 0, %0, c7, c5, 1;\n\t"
+ "mcrlt p15, 0, %0, c7, c6, 1;\n\t"
+ :
+ : "r" (addr)
+ );
+ }
+ ret = 0;
+ break;
+ }
+ Args[0] = ret; // RetLow
+ Args[1] = 0; // RetHi
+ Args[2] = err; // Errno
+ LEAVE('x', ret);
+ return ret;
+}
+
--- /dev/null
+/*
+ * Acess2
+ *
+ * ARM7 Physical Memory Manager
+ * arch/arm7/mm_phys.c
+ */
+#define DEBUG 0
+
+#include <acess.h>
+#include <mm_virt.h>
+
+#define MM_NUM_RANGES 1 // Single range
+#define MM_RANGE_MAX 0
+#define TRACE_ALLOCS 0
+
+#define NUM_STATIC_ALLOC 4
+
+char gStaticAllocPages[NUM_STATIC_ALLOC][PAGE_SIZE] __attribute__ ((section(".padata")));
+tPAddr gaiStaticAllocPages[NUM_STATIC_ALLOC] = {
+ (tPAddr)(&gStaticAllocPages[0]) - KERNEL_BASE,
+ (tPAddr)(&gStaticAllocPages[1]) - KERNEL_BASE,
+ (tPAddr)(&gStaticAllocPages[2]) - KERNEL_BASE,
+ (tPAddr)(&gStaticAllocPages[3]) - KERNEL_BASE
+};
+extern char gKernelEnd[];
+
+
+#include <tpl_mm_phys_bitmap.h>
+
+//#define REALVIEW_LOWRAM_SIZE 0x10000000
+#define REALVIEW_LOWRAM_SIZE (32*1024*1024)
+
+void MM_SetupPhys(void)
+{
+ LogF("MM_SetupPhys: ()\n");
+ MM_Tpl_InitPhys( REALVIEW_LOWRAM_SIZE/0x1000, NULL );
+}
+
+int MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length )
+{
+ switch(Index)
+ {
+ case 0:
+ *Start = ((tVAddr)&gKernelEnd - KERNEL_BASE + 0xFFF) & ~0xFFF;
+ *Length = REALVIEW_LOWRAM_SIZE - *Start;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/**
+ * \brief Takes a physical address and returns the ID of its range
+ * \param Addr Physical address of page
+ * \return Range ID from eMMPhys_Ranges
+ */
+int MM_int_GetRangeID( tPAddr Addr )
+{
+ return MM_RANGE_MAX; // ARM doesn't need ranges
+}
--- /dev/null
+/*
+ * Acess2
+ *
+ * ARM7 Virtual Memory Manager
+ * - arch/arm7/mm_virt.c
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <mm_virt.h>
+#include <hal_proc.h>
+
+#define TRACE_MAPS 0
+
+#define AP_KRW_ONLY 1 // Kernel page
+#define AP_KRO_ONLY 5 // Kernel RO page
+#define AP_RW_BOTH 3 // Standard RW
+#define AP_RO_BOTH 7 // COW Page
+#define AP_RO_USER 2 // User RO Page
+#define PADDR_MASK_LVL1 0xFFFFFC00
+
+// === IMPORTS ===
+extern Uint32 kernel_table0[];
+
+// === TYPES ===
+typedef struct
+{
+ tPAddr PhysAddr;
+ Uint8 Size;
+ Uint8 Domain;
+ BOOL bExecutable;
+ BOOL bGlobal;
+ BOOL bShared;
+ int AP;
+} tMM_PageInfo;
+
+//#define FRACTAL(table1, addr) ((table1)[ (0xFF8/4*1024) + ((addr)>>20)])
+#define FRACTAL(table1, addr) ((table1)[ (0xFF8/4*1024) + ((addr)>>22)])
+#define USRFRACTAL(addr) (*((Uint32*)(0x7FDFF000) + ((addr)>>22)))
+#define TLBIALL() __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 0" : : "r" (0))
+#define TLBIMVA(addr) __asm__ __volatile__ ("mcr p15, 0, %0, c8, c7, 1" : : "r" (((addr)&~0xFFF)|1):"memory")
+#define DCCMVAC(addr) __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 1" : : "r" ((addr)&~0xFFF))
+
+// === PROTOTYPES ===
+void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1);
+ int MM_int_AllocateCoarse(tVAddr VAddr, int Domain);
+ int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
+ int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi);
+tVAddr MM_NewUserStack(void);
+tPAddr MM_AllocateZero(tVAddr VAddr);
+tPAddr MM_AllocateRootTable(void);
+void MM_int_CloneTable(Uint32 *DestEnt, int Table);
+tPAddr MM_Clone(void);
+tVAddr MM_NewKStack(int bGlobal);
+void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info);
+//void MM_DumpTables(tVAddr Start, tVAddr End);
+void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch);
+
+// === GLOBALS ===
+tPAddr giMM_ZeroPage;
+
+// === CODE ===
+int MM_InitialiseVirtual(void)
+{
+ return 0;
+}
+
+void MM_int_GetTables(tVAddr VAddr, Uint32 **Table0, Uint32 **Table1)
+{
+ if(VAddr & 0x80000000) {
+ *Table0 = (void*)&kernel_table0; // Level 0
+ *Table1 = (void*)MM_TABLE1KERN; // Level 1
+ }
+ else {
+ *Table0 = (void*)MM_TABLE0USER;
+ *Table1 = (void*)MM_TABLE1USER;
+ }
+}
+
+int MM_int_AllocateCoarse(tVAddr VAddr, int Domain)
+{
+ Uint32 *table0, *table1;
+ Uint32 *desc;
+ tPAddr paddr;
+
+ ENTER("xVAddr iDomain", VAddr, Domain);
+
+ MM_int_GetTables(VAddr, &table0, &table1);
+
+ VAddr &= ~(0x400000-1); // 4MiB per "block", 1 Page
+
+ desc = &table0[ VAddr>>20];
+ LOG("desc = %p", desc);
+
+ // table0: 4 bytes = 1 MiB
+
+ LOG("desc[0] = %x", desc[0]);
+ LOG("desc[1] = %x", desc[1]);
+ LOG("desc[2] = %x", desc[2]);
+ LOG("desc[3] = %x", desc[3]);
+
+ if( (desc[0] & 3) != 0 || (desc[1] & 3) != 0
+ || (desc[2] & 3) != 0 || (desc[3] & 3) != 0 )
+ {
+ // Error?
+ LEAVE('i', 1);
+ return 1;
+ }
+
+ paddr = MM_AllocPhys();
+ if( !paddr )
+ {
+ // Error
+ LEAVE('i', 2);
+ return 2;
+ }
+
+ *desc = paddr | (Domain << 5) | 1;
+ desc[1] = desc[0] + 0x400;
+ desc[2] = desc[0] + 0x800;
+ desc[3] = desc[0] + 0xC00;
+
+ if( VAddr < 0x80000000 ) {
+ USRFRACTAL(VAddr) = paddr | 0x13;
+ }
+ else {
+ FRACTAL(table1, VAddr) = paddr | 0x13;
+ }
+
+ // TLBIALL
+ TLBIALL();
+
+ memset( (void*)&table1[ (VAddr >> 12) & ~(1024-1) ], 0, 0x1000 );
+
+ LEAVE('i', 0);
+ return 0;
+}
+
+int MM_int_SetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
+{
+ Uint32 *table0, *table1;
+ Uint32 *desc;
+
+ ENTER("pVAddr ppi", VAddr, pi);
+
+ MM_int_GetTables(VAddr, &table0, &table1);
+
+ desc = &table0[ VAddr >> 20 ];
+ LOG("desc = %p", desc);
+
+ switch(pi->Size)
+ {
+ case 12: // Small Page
+ case 16: // Large Page
+ LOG("Page");
+ if( (*desc & 3) == 0 ) {
+ MM_int_AllocateCoarse( VAddr, pi->Domain );
+ }
+ desc = &table1[ VAddr >> 12 ];
+ LOG("desc (2) = %p", desc);
+ if( pi->Size == 12 )
+ {
+ // Small page
+ // - Error if overwriting a large page
+ if( (*desc & 3) == 1 ) LEAVE_RET('i', 1);
+ if( pi->PhysAddr == 0 ) {
+ *desc = 0;
+ TLBIMVA( VAddr );
+ DCCMVAC( (tVAddr) desc );
+// #warning "HACK: TLBIALL"
+// TLBIALL();
+ LEAVE('i', 0);
+ return 0;
+ }
+
+ *desc = (pi->PhysAddr & 0xFFFFF000) | 2;
+ if(!pi->bExecutable) *desc |= 1; // XN
+ if(!pi->bGlobal) *desc |= 1 << 11; // nG
+ if( pi->bShared) *desc |= 1 << 10; // S
+ *desc |= (pi->AP & 3) << 4; // AP
+ *desc |= ((pi->AP >> 2) & 1) << 9; // APX
+ TLBIMVA( VAddr );
+// #warning "HACK: TLBIALL"
+// TLBIALL();
+ DCCMVAC( (tVAddr) desc );
+ LEAVE('i', 0);
+ return 0;
+ }
+ else
+ {
+ // Large page
+ Log_Warning("MMVirt", "TODO: Implement large pages in MM_int_SetPageInfo");
+ }
+ break;
+ case 20: // Section or unmapped
+ Log_Warning("MMVirt", "TODO: Implement sections in MM_int_SetPageInfo");
+ break;
+ case 24: // Supersection
+ // Error if not aligned
+ if( VAddr & 0xFFFFFF ) {
+ LEAVE('i', 1);
+ return 1;
+ }
+ if( (*desc & 3) == 0 || ((*desc & 3) == 2 && (*desc & (1 << 18))) )
+ {
+ if( pi->PhysAddr == 0 ) {
+ *desc = 0;
+ }
+ else {
+ // Apply
+ *desc = pi->PhysAddr & 0xFF000000;
+// *desc |= ((pi->PhysAddr >> 32) & 0xF) << 20;
+// *desc |= ((pi->PhysAddr >> 36) & 0x7) << 5;
+ *desc |= 2 | (1 << 18);
+ }
+ // TODO: Apply to all entries
+ Log_Warning("MMVirt", "TODO: Apply changes to all entries of supersections");
+ LEAVE('i', 0);
+ return 0;
+ }
+ // TODO: What here?
+ Log_Warning("MMVirt", "TODO: 24-bit not on supersection?");
+ LEAVE('i', 1);
+ return 1;
+ }
+
+ LEAVE('i', 1);
+ return 1;
+}
+
+int MM_int_GetPageInfo(tVAddr VAddr, tMM_PageInfo *pi)
+{
+ Uint32 *table0, *table1;
+ Uint32 desc;
+
+// LogF("MM_int_GetPageInfo: VAddr=%p, pi=%p\n", VAddr, pi);
+
+ MM_int_GetTables(VAddr, &table0, &table1);
+
+ desc = table0[ VAddr >> 20 ];
+
+// if( VAddr > 0x90000000)
+// LOG("table0 desc(%p) = %x", &table0[ VAddr >> 20 ], desc);
+
+ pi->bExecutable = 1;
+ pi->bGlobal = 0;
+ pi->bShared = 0;
+ pi->AP = 0;
+
+ switch( (desc & 3) )
+ {
+ // 0: Unmapped
+ case 0:
+ pi->PhysAddr = 0;
+ pi->Size = 20;
+ pi->Domain = 0;
+ return 1;
+
+ // 1: Coarse page table
+ case 1:
+ // Domain from top level table
+ pi->Domain = (desc >> 5) & 7;
+ // Get next level
+ desc = table1[ VAddr >> 12 ];
+// LOG("table1 desc(%p) = %x", &table1[ VAddr >> 12 ], desc);
+ switch( desc & 3 )
+ {
+ // 0: Unmapped
+ case 0:
+ pi->Size = 12;
+ return 1;
+ // 1: Large Page (64KiB)
+ case 1:
+ pi->Size = 16;
+ pi->PhysAddr = desc & 0xFFFF0000;
+ pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
+ pi->bExecutable = !(desc & 0x8000);
+ pi->bShared = (desc >> 10) & 1;
+ return 0;
+ // 2/3: Small page
+ case 2:
+ case 3:
+ pi->Size = 12;
+ pi->PhysAddr = desc & 0xFFFFF000;
+ pi->bExecutable = !(desc & 1);
+ pi->bGlobal = !(desc >> 11);
+ pi->bShared = (desc >> 10) & 1;
+ pi->AP = ((desc >> 4) & 3) | (((desc >> 9) & 1) << 2);
+ return 0;
+ }
+ return 1;
+
+ // 2: Section (or Supersection)
+ case 2:
+ if( desc & (1 << 18) ) {
+ // Supersection
+ pi->PhysAddr = desc & 0xFF000000;
+ pi->PhysAddr |= (Uint64)((desc >> 20) & 0xF) << 32;
+ pi->PhysAddr |= (Uint64)((desc >> 5) & 0x7) << 36;
+ pi->Size = 24;
+ pi->Domain = 0; // Supersections default to zero
+ pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
+ return 0;
+ }
+
+ // Section
+ pi->PhysAddr = desc & 0xFFF80000;
+ pi->Size = 20;
+ pi->Domain = (desc >> 5) & 7;
+ pi->AP = ((desc >> 10) & 3) | (((desc >> 15) & 1) << 2);
+ return 0;
+
+ // 3: Reserved (invalid)
+ case 3:
+ pi->PhysAddr = 0;
+ pi->Size = 20;
+ pi->Domain = 0;
+ return 2;
+ }
+ return 2;
+}
+
+// --- Exports ---
+tPAddr MM_GetPhysAddr(const void *Ptr)
+{
+ tVAddr VAddr = (tPAddr)Ptr;
+ tMM_PageInfo pi;
+ if( MM_int_GetPageInfo(VAddr, &pi) )
+ return 0;
+ return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
+}
+
+Uint MM_GetFlags(tVAddr VAddr)
+{
+ tMM_PageInfo pi;
+ int ret;
+
+ if( MM_int_GetPageInfo(VAddr, &pi) )
+ return 0;
+
+ ret = 0;
+
+ switch(pi.AP)
+ {
+ case 0:
+ break;
+ case AP_KRW_ONLY:
+ ret |= MM_PFLAG_KERNEL;
+ break;
+ case AP_KRO_ONLY:
+ ret |= MM_PFLAG_KERNEL|MM_PFLAG_RO;
+ break;
+ case AP_RW_BOTH:
+ break;
+ case AP_RO_BOTH:
+ ret |= MM_PFLAG_COW;
+ break;
+ case AP_RO_USER:
+ ret |= MM_PFLAG_RO;
+ break;
+ }
+
+ if( pi.bExecutable ) ret |= MM_PFLAG_EXEC;
+ return ret;
+}
+
+void MM_SetFlags(tVAddr VAddr, Uint Flags, Uint Mask)
+{
+ tMM_PageInfo pi;
+ Uint curFlags;
+
+ if( MM_int_GetPageInfo(VAddr, &pi) )
+ return ;
+
+ curFlags = MM_GetFlags(VAddr);
+ if( (curFlags & Mask) == Flags )
+ return ;
+ curFlags &= ~Mask;
+ curFlags |= Flags;
+
+ if( curFlags & MM_PFLAG_COW )
+ pi.AP = AP_RO_BOTH;
+ else
+ {
+ switch(curFlags & (MM_PFLAG_KERNEL|MM_PFLAG_RO) )
+ {
+ case 0:
+ pi.AP = AP_RW_BOTH; break;
+ case MM_PFLAG_KERNEL:
+ pi.AP = AP_KRW_ONLY; break;
+ case MM_PFLAG_RO:
+ pi.AP = AP_RO_USER; break;
+ case MM_PFLAG_KERNEL|MM_PFLAG_RO:
+ pi.AP = AP_KRO_ONLY; break;
+ }
+ }
+
+ pi.bExecutable = !!(curFlags & MM_PFLAG_EXEC);
+
+ MM_int_SetPageInfo(VAddr, &pi);
+}
+
+int MM_IsValidBuffer(tVAddr Addr, size_t Size)
+{
+ tMM_PageInfo pi;
+ int bUser = 0;
+
+ Size += Addr & (PAGE_SIZE-1);
+ Addr &= ~(PAGE_SIZE-1);
+
+ if( MM_int_GetPageInfo(Addr, &pi) ) return 0;
+ Addr += PAGE_SIZE;
+
+ if(pi.AP != AP_KRW_ONLY && pi.AP != AP_KRO_ONLY)
+ bUser = 1;
+
+ while( Size >= PAGE_SIZE )
+ {
+ if( MM_int_GetPageInfo(Addr, &pi) )
+ return 0;
+ if(bUser && (pi.AP == AP_KRW_ONLY || pi.AP == AP_KRO_ONLY))
+ return 0;
+ Addr += PAGE_SIZE;
+ Size -= PAGE_SIZE;
+ }
+
+ return 1;
+}
+
+int MM_Map(tVAddr VAddr, tPAddr PAddr)
+{
+ tMM_PageInfo pi = {0};
+ #if TRACE_MAPS
+ Log("MM_Map %P=>%p", PAddr, VAddr);
+ #endif
+
+ pi.PhysAddr = PAddr;
+ pi.Size = 12;
+ if(VAddr < USER_STACK_TOP)
+ pi.AP = AP_RW_BOTH;
+ else
+ pi.AP = AP_KRW_ONLY; // Kernel Read/Write
+ pi.bExecutable = 1;
+ if( MM_int_SetPageInfo(VAddr, &pi) ) {
+// MM_DerefPhys(pi.PhysAddr);
+ return 0;
+ }
+ return pi.PhysAddr;
+}
+
+tPAddr MM_Allocate(tVAddr VAddr)
+{
+ tMM_PageInfo pi = {0};
+
+ ENTER("pVAddr", VAddr);
+
+ pi.PhysAddr = MM_AllocPhys();
+ if( pi.PhysAddr == 0 ) LEAVE_RET('i', 0);
+ pi.Size = 12;
+ if(VAddr < USER_STACK_TOP)
+ pi.AP = AP_RW_BOTH;
+ else
+ pi.AP = AP_KRW_ONLY;
+ pi.bExecutable = 0;
+ if( MM_int_SetPageInfo(VAddr, &pi) ) {
+ MM_DerefPhys(pi.PhysAddr);
+ LEAVE('i', 0);
+ return 0;
+ }
+ LEAVE('x', pi.PhysAddr);
+ return pi.PhysAddr;
+}
+
+tPAddr MM_AllocateZero(tVAddr VAddr)
+{
+ if( !giMM_ZeroPage ) {
+ giMM_ZeroPage = MM_Allocate(VAddr);
+ MM_RefPhys(giMM_ZeroPage);
+ memset((void*)VAddr, 0, PAGE_SIZE);
+ }
+ else {
+ MM_RefPhys(giMM_ZeroPage);
+ MM_Map(VAddr, giMM_ZeroPage);
+ }
+ MM_SetFlags(VAddr, MM_PFLAG_COW, MM_PFLAG_COW);
+ return giMM_ZeroPage;
+}
+
+void MM_Deallocate(tVAddr VAddr)
+{
+ tMM_PageInfo pi;
+
+ if( MM_int_GetPageInfo(VAddr, &pi) ) return ;
+ if( pi.PhysAddr == 0 ) return;
+ MM_DerefPhys(pi.PhysAddr);
+
+ pi.PhysAddr = 0;
+ pi.AP = 0;
+ pi.bExecutable = 0;
+ MM_int_SetPageInfo(VAddr, &pi);
+}
+
+tPAddr MM_AllocateRootTable(void)
+{
+ tPAddr ret;
+
+ ret = MM_AllocPhysRange(2, -1);
+ if( ret & 0x1000 ) {
+ MM_DerefPhys(ret);
+ MM_DerefPhys(ret+0x1000);
+ ret = MM_AllocPhysRange(3, -1);
+ if( ret & 0x1000 ) {
+ MM_DerefPhys(ret);
+ ret += 0x1000;
+// Log("MM_AllocateRootTable: Second try not aligned, %P", ret);
+ }
+ else {
+ MM_DerefPhys(ret + 0x2000);
+// Log("MM_AllocateRootTable: Second try aligned, %P", ret);
+ }
+ }
+// else
+// Log("MM_AllocateRootTable: Got it in one, %P", ret);
+ return ret;
+}
+
+void MM_int_CloneTable(Uint32 *DestEnt, int Table)
+{
+ tPAddr table;
+ Uint32 *tmp_map;
+ Uint32 *cur = (void*)MM_TABLE1USER;
+// Uint32 *cur = &FRACTAL(MM_TABLE1USER,0);
+ int i;
+
+ table = MM_AllocPhys();
+ if(!table) return ;
+
+ cur += 256*Table;
+
+ tmp_map = MM_MapTemp(table);
+
+ for( i = 0; i < 1024; i ++ )
+ {
+// Log_Debug("MMVirt", "cur[%i] (%p) = %x", Table*256+i, &cur[Table*256+i], cur[Table*256+i]);
+ switch(cur[i] & 3)
+ {
+ case 0: tmp_map[i] = 0; break;
+ case 1:
+ tmp_map[i] = 0;
+ Log_Error("MMVirt", "TODO: Support large pages in MM_int_CloneTable (%p)", (Table*256+i)*0x1000);
+ // Large page?
+ break;
+ case 2:
+ case 3:
+ // Small page
+ // - If full RW
+// Debug("%p cur[%i] & 0x230 = 0x%x", Table*256*0x1000, i, cur[i] & 0x230);
+ if( (cur[i] & 0x230) == 0x010 )
+ {
+ void *dst, *src;
+ tPAddr newpage;
+ newpage = MM_AllocPhys();
+ src = (void*)( (Table*256+i)*0x1000 );
+ dst = MM_MapTemp(newpage);
+// Debug("Taking a copy of kernel page %p (%P)", src, cur[i] & ~0xFFF);
+ memcpy(dst, src, PAGE_SIZE);
+ MM_FreeTemp( dst );
+ tmp_map[i] = newpage | (cur[i] & 0xFFF);
+ }
+ else
+ {
+ if( (cur[i] & 0x230) == 0x030 )
+ cur[i] |= 0x200; // Set to full RO (Full RO=COW, User RO = RO)
+ tmp_map[i] = cur[i];
+ MM_RefPhys( tmp_map[i] & ~0xFFF );
+ }
+ break;
+ }
+ }
+ MM_FreeTemp( tmp_map );
+
+ DestEnt[0] = table + 0*0x400 + 1;
+ DestEnt[1] = table + 1*0x400 + 1;
+ DestEnt[2] = table + 2*0x400 + 1;
+ DestEnt[3] = table + 3*0x400 + 1;
+}
+
+tPAddr MM_Clone(void)
+{
+ tPAddr ret;
+ Uint32 *new_lvl1_1, *new_lvl1_2, *cur;
+ Uint32 *tmp_map;
+ int i;
+
+// MM_DumpTables(0, KERNEL_BASE);
+
+ ret = MM_AllocateRootTable();
+
+ cur = (void*)MM_TABLE0USER;
+ new_lvl1_1 = MM_MapTemp(ret);
+ new_lvl1_2 = MM_MapTemp(ret+0x1000);
+ tmp_map = new_lvl1_1;
+ for( i = 0; i < 0x800-4; i ++ )
+ {
+ // HACK! Ignore the original identity mapping
+ if( i == 0 && Threads_GetTID() == 0 ) {
+ tmp_map[0] = 0;
+ continue;
+ }
+ if( i == 0x400 )
+ tmp_map = &new_lvl1_2[-0x400];
+ switch( cur[i] & 3 )
+ {
+ case 0: tmp_map[i] = 0; break;
+ case 1:
+ MM_int_CloneTable(&tmp_map[i], i);
+ i += 3; // Tables are alocated in blocks of 4
+ break;
+ case 2:
+ case 3:
+ Log_Error("MMVirt", "TODO: Support Sections/Supersections in MM_Clone (i=%i)", i);
+ tmp_map[i] = 0;
+ break;
+ }
+ }
+
+ // Allocate Fractal table
+ {
+ int j, num;
+ tPAddr tmp = MM_AllocPhys();
+ Uint32 *table = MM_MapTemp(tmp);
+ Uint32 sp;
+ register Uint32 __SP asm("sp");
+
+ // Map table to last 4MiB of user space
+ new_lvl1_2[0x3FC] = tmp + 0*0x400 + 1;
+ new_lvl1_2[0x3FD] = tmp + 1*0x400 + 1;
+ new_lvl1_2[0x3FE] = tmp + 2*0x400 + 1;
+ new_lvl1_2[0x3FF] = tmp + 3*0x400 + 1;
+
+ tmp_map = new_lvl1_1;
+ for( j = 0; j < 512; j ++ )
+ {
+ if( j == 256 )
+ tmp_map = &new_lvl1_2[-0x400];
+ if( (tmp_map[j*4] & 3) == 1 )
+ {
+ table[j] = tmp_map[j*4] & PADDR_MASK_LVL1;// 0xFFFFFC00;
+ table[j] |= 0x813; // nG, Kernel Only, Small page, XN
+ }
+ else
+ table[j] = 0;
+ }
+ // Fractal
+ table[j++] = (ret + 0x0000) | 0x813;
+ table[j++] = (ret + 0x1000) | 0x813;
+ // Nuke the rest
+ for( ; j < 1024; j ++ )
+ table[j] = 0;
+
+ // Get kernel stack bottom
+ sp = __SP & ~(MM_KSTACK_SIZE-1);
+ j = (sp / 0x1000) % 1024;
+ num = MM_KSTACK_SIZE/0x1000;
+
+// Log("num = %i, sp = %p, j = %i", num, sp, j);
+
+ // Copy stack pages
+ for(; num--; j ++, sp += 0x1000)
+ {
+ tVAddr page;
+ void *tmp_page;
+
+ page = MM_AllocPhys();
+// Log("page = %P", page);
+ table[j] = page | 0x813;
+
+ tmp_page = MM_MapTemp(page);
+ memcpy(tmp_page, (void*)sp, 0x1000);
+ MM_FreeTemp( tmp_page );
+ }
+
+ MM_FreeTemp( table );
+ }
+
+ MM_FreeTemp( new_lvl1_1 );
+ MM_FreeTemp( new_lvl1_2 );
+
+// Log("MM_Clone: ret = %P", ret);
+
+ return ret;
+}
+
+void MM_ClearUser(void)
+{
+ int i, j;
+ const int user_table_count = USER_STACK_TOP / (256*0x1000);
+ Uint32 *cur = (void*)MM_TABLE0USER;
+ Uint32 *tab;
+
+// MM_DumpTables(0, 0x80000000);
+
+// Log("user_table_count = %i (as opposed to %i)", user_table_count, 0x800-4);
+
+ for( i = 0; i < user_table_count; i ++ )
+ {
+ switch( cur[i] & 3 )
+ {
+ case 0: break; // Already unmapped
+ case 1: // Sub pages
+ tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32));
+ for( j = 0; j < 1024; j ++ )
+ {
+ switch( tab[j] & 3 )
+ {
+ case 0: break; // Unmapped
+ case 1:
+ Log_Error("MMVirt", "TODO: Support large pages in MM_ClearUser");
+ break;
+ case 2:
+ case 3:
+ MM_DerefPhys( tab[j] & ~(PAGE_SIZE-1) );
+ break;
+ }
+ }
+ MM_DerefPhys( cur[i] & ~(PAGE_SIZE-1) );
+ cur[i+0] = 0;
+ cur[i+1] = 0;
+ cur[i+2] = 0;
+ i += 3;
+ break;
+ case 2:
+ case 3:
+ Log_Error("MMVirt", "TODO: Implement sections/supersections in MM_ClearUser");
+ break;
+ }
+ cur[i] = 0;
+ }
+
+ // Final block of 4 tables are KStack
+ i = 0x800 - 4;
+
+ // Clear out unused stacks
+ {
+ register Uint32 __SP asm("sp");
+ int cur_stack_base = ((__SP & ~(MM_KSTACK_SIZE-1)) / PAGE_SIZE) % 1024;
+
+ tab = (void*)(MM_TABLE1USER + i*256*sizeof(Uint32));
+
+ // First 512 is the Table1 mapping + 2 for Table0 mapping
+ for( j = 512+2; j < 1024; j ++ )
+ {
+ // Skip current stack
+ if( j == cur_stack_base ) {
+ j += (MM_KSTACK_SIZE / PAGE_SIZE) - 1;
+ continue ;
+ }
+ if( !(tab[j] & 3) ) continue;
+ ASSERT( (tab[j] & 3) == 2 );
+ MM_DerefPhys( tab[j] & ~(PAGE_SIZE) );
+ tab[j] = 0;
+ }
+ }
+
+
+// MM_DumpTables(0, 0x80000000);
+}
+
+void *MM_MapTemp(tPAddr PAddr)
+{
+ tVAddr ret;
+ tMM_PageInfo pi;
+
+ for( ret = MM_TMPMAP_BASE; ret < MM_TMPMAP_END - PAGE_SIZE; ret += PAGE_SIZE )
+ {
+ if( MM_int_GetPageInfo(ret, &pi) == 0 )
+ continue;
+
+// Log("MapTemp %P at %p by %p", PAddr, ret, __builtin_return_address(0));
+ MM_RefPhys(PAddr); // Counter the MM_Deallocate in FreeTemp
+ MM_Map(ret, PAddr);
+
+ return (void*)ret;
+ }
+ Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
+ return 0;
+}
+
+void MM_FreeTemp(void *Ptr)
+{
+ tVAddr VAddr = (tVAddr)Ptr;
+ if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) {
+ Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr);
+ return ;
+ }
+
+ MM_Deallocate(VAddr);
+}
+
+tVAddr MM_MapHWPages(tPAddr PAddr, Uint NPages)
+{
+ tVAddr ret;
+ int i;
+ tMM_PageInfo pi;
+
+ ENTER("xPAddr iNPages", PAddr, NPages);
+
+ // Scan for a location
+ for( ret = MM_HWMAP_BASE; ret < MM_HWMAP_END - NPages * PAGE_SIZE; ret += PAGE_SIZE )
+ {
+// LOG("checking %p", ret);
+ // Check if there is `NPages` free pages
+ for( i = 0; i < NPages; i ++ )
+ {
+ if( MM_int_GetPageInfo(ret + i*PAGE_SIZE, &pi) == 0 )
+ break;
+ }
+ // Nope, jump to after the used page found and try again
+// LOG("i = %i, ==? %i", i, NPages);
+ if( i != NPages ) {
+ ret += i * PAGE_SIZE;
+ continue ;
+ }
+
+ // Map the pages
+ for( i = 0; i < NPages; i ++ )
+ MM_Map(ret+i*PAGE_SIZE, PAddr+i*PAGE_SIZE);
+ // and return
+ LEAVE('p', ret);
+ return ret;
+ }
+ Log_Warning("MMVirt", "MM_MapHWPages: No space for a %i page block", NPages);
+ LEAVE('p', 0);
+ return 0;
+}
+
+tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PAddr)
+{
+ tPAddr phys;
+ tVAddr ret;
+
+ phys = MM_AllocPhysRange(Pages, MaxBits);
+ if(!phys) {
+ Log_Warning("MMVirt", "No space left for a %i page block (MM_AllocDMA)", Pages);
+ return 0;
+ }
+
+ ret = MM_MapHWPages(phys, Pages);
+ *PAddr = phys;
+
+ return ret;
+}
+
+void MM_UnmapHWPages(tVAddr Vaddr, Uint Number)
+{
+ Log_Error("MMVirt", "TODO: Implement MM_UnmapHWPages");
+}
+
+tVAddr MM_NewKStack(int bShared)
+{
+ tVAddr min_addr, max_addr;
+ tVAddr addr, ofs;
+
+ if( bShared ) {
+ min_addr = MM_GLOBALSTACKS;
+ max_addr = MM_GLOBALSTACKS_END;
+ }
+ else {
+ min_addr = MM_KSTACK_BASE;
+ max_addr = MM_KSTACK_END;
+ }
+
+ // Locate a free slot
+ for( addr = min_addr; addr < max_addr; addr += MM_KSTACK_SIZE )
+ {
+ tMM_PageInfo pi;
+ if( MM_int_GetPageInfo(addr+MM_KSTACK_SIZE-PAGE_SIZE, &pi) ) break;
+ }
+
+ // Check for an error
+ if(addr >= max_addr) {
+ return 0;
+ }
+
+ // 1 guard page
+ for( ofs = PAGE_SIZE; ofs < MM_KSTACK_SIZE; ofs += PAGE_SIZE )
+ {
+ if( MM_Allocate(addr + ofs) == 0 )
+ {
+ while(ofs)
+ {
+ ofs -= PAGE_SIZE;
+ MM_Deallocate(addr + ofs);
+ }
+ Log_Warning("MMVirt", "MM_NewKStack: Unable to allocate");
+ return 0;
+ }
+ }
+ return addr + ofs;
+}
+
+tVAddr MM_NewUserStack(void)
+{
+ tVAddr addr, ofs;
+
+ addr = USER_STACK_TOP - USER_STACK_SIZE;
+ if( MM_GetPhysAddr( (void*)(addr + PAGE_SIZE) ) ) {
+ Log_Error("MMVirt", "Unable to create initial user stack, addr %p taken",
+ addr + PAGE_SIZE
+ );
+ return 0;
+ }
+
+ // 1 guard page
+ for( ofs = PAGE_SIZE; ofs < USER_STACK_SIZE; ofs += PAGE_SIZE )
+ {
+ tPAddr rv;
+ if(ofs >= USER_STACK_SIZE - USER_STACK_COMM)
+ rv = MM_Allocate(addr + ofs);
+ else
+ rv = MM_AllocateZero(addr + ofs);
+ if(rv == 0)
+ {
+ while(ofs)
+ {
+ ofs -= PAGE_SIZE;
+ MM_Deallocate(addr + ofs);
+ }
+ Log_Warning("MMVirt", "MM_NewUserStack: Unable to allocate");
+ return 0;
+ }
+ MM_SetFlags(addr+ofs, 0, MM_PFLAG_KERNEL);
+ }
+// Log("Return %p", addr + ofs);
+// MM_DumpTables(0, 0x80000000);
+ return addr + ofs;
+}
+
+void MM_int_DumpTableEnt(tVAddr Start, size_t Len, tMM_PageInfo *Info)
+{
+ if( giMM_ZeroPage && Info->PhysAddr == giMM_ZeroPage )
+ {
+ Debug("%p => %8s - 0x%7x %i %x %s",
+ Start, "ZERO", Len,
+ Info->Domain, Info->AP,
+ Info->bGlobal ? "G" : "nG"
+ );
+ }
+ else
+ {
+ Debug("%p => %8x - 0x%7x %i %x %s",
+ Start, Info->PhysAddr-Len, Len,
+ Info->Domain, Info->AP,
+ Info->bGlobal ? "G" : "nG"
+ );
+ }
+}
+
+void MM_DumpTables(tVAddr Start, tVAddr End)
+{
+ tVAddr range_start = 0, addr;
+ tMM_PageInfo pi, pi_old;
+ int i = 0, inRange=0;
+
+ memset(&pi_old, 0, sizeof(pi_old));
+
+ Debug("Page Table Dump (%p to %p):", Start, End);
+ range_start = Start;
+ for( addr = Start; i == 0 || (addr && addr < End); i = 1 )
+ {
+ int rv;
+// Log("addr = %p", addr);
+ rv = MM_int_GetPageInfo(addr, &pi);
+ if( rv
+ || pi.Size != pi_old.Size
+ || pi.Domain != pi_old.Domain
+ || pi.AP != pi_old.AP
+ || pi.bGlobal != pi_old.bGlobal
+ || pi_old.PhysAddr != pi.PhysAddr )
+ {
+ if(inRange) {
+ MM_int_DumpTableEnt(range_start, addr - range_start, &pi_old);
+ }
+ addr &= ~((1 << pi.Size)-1);
+ range_start = addr;
+ }
+
+ pi_old = pi;
+ // Handle the zero page
+ if( !giMM_ZeroPage || pi_old.Size != 12 || pi_old.PhysAddr != giMM_ZeroPage )
+ pi_old.PhysAddr += 1 << pi_old.Size;
+ addr += 1 << pi_old.Size;
+ inRange = (rv == 0);
+ }
+ if(inRange)
+ MM_int_DumpTableEnt(range_start, addr - range_start, &pi);
+ Debug("Done");
+}
+
+// NOTE: Runs in abort context, not much difference, just a smaller stack
+void MM_PageFault(Uint32 PC, Uint32 Addr, Uint32 DFSR, int bPrefetch)
+{
+ int rv;
+ tMM_PageInfo pi;
+
+ rv = MM_int_GetPageInfo(Addr, &pi);
+
+ // Check for COW
+ if( rv == 0 && pi.AP == AP_RO_BOTH )
+ {
+ pi.AP = AP_RW_BOTH;
+ if( giMM_ZeroPage && pi.PhysAddr == giMM_ZeroPage )
+ {
+ tPAddr newpage;
+ newpage = MM_AllocPhys();
+ if( !newpage ) {
+ Log_Error("MMVirt", "Unable to allocate new page for COW of ZERO");
+ for(;;);
+ }
+
+ #if TRACE_COW
+ Log_Notice("MMVirt", "COW %p caused by %p, ZERO duped to %P (RefCnt(%i)--)", Addr, PC,
+ newpage, MM_GetRefCount(pi.PhysAddr));
+ #endif
+
+ MM_DerefPhys(pi.PhysAddr);
+ pi.PhysAddr = newpage;
+ pi.AP = AP_RW_BOTH;
+ MM_int_SetPageInfo(Addr, &pi);
+
+ memset( (void*)(Addr & ~(PAGE_SIZE-1)), 0, PAGE_SIZE );
+
+ return ;
+ }
+ else if( MM_GetRefCount(pi.PhysAddr) > 1 )
+ {
+ // Duplicate the page
+ tPAddr newpage;
+ void *dst, *src;
+
+ newpage = MM_AllocPhys();
+ if(!newpage) {
+ Log_Error("MMVirt", "Unable to allocate new page for COW");
+ for(;;);
+ }
+ dst = MM_MapTemp(newpage);
+ src = (void*)(Addr & ~(PAGE_SIZE-1));
+ memcpy( dst, src, PAGE_SIZE );
+ MM_FreeTemp( dst );
+
+ #if TRACE_COW
+ Log_Notice("MMVirt", "COW %p caused by %p, %P duped to %P (RefCnt(%i)--)", Addr, PC,
+ pi.PhysAddr, newpage, MM_GetRefCount(pi.PhysAddr));
+ #endif
+
+ MM_DerefPhys(pi.PhysAddr);
+ pi.PhysAddr = newpage;
+ }
+ #if TRACE_COW
+ else {
+ Log_Notice("MMVirt", "COW %p caused by %p, took last reference to %P",
+ Addr, PC, pi.PhysAddr);
+ }
+ #endif
+ // Unset COW
+ pi.AP = AP_RW_BOTH;
+ MM_int_SetPageInfo(Addr, &pi);
+ return ;
+ }
+
+
+ Log_Error("MMVirt", "Code at %p accessed %p (DFSR = 0x%x)%s", PC, Addr, DFSR,
+ (bPrefetch ? " - Prefetch" : "")
+ );
+ if( Addr < 0x80000000 )
+ MM_DumpTables(0, 0x80000000);
+ else
+ MM_DumpTables(0x80000000, -1);
+ for(;;);
+}
+
--- /dev/null
+/*
+ *
+ */
+#include <acess.h>
+#include <drv_pci_int.h>
+
+// Realview
+//#define PCI_BASE 0x60000000
+
+//#define PCI_BASE 0xF0400000 // VMM Mapping
+#define PCI_BASE 0
+
+// === CODE ===
+void PCI_CfgWriteDWord(Uint32 Addr, Uint32 Data)
+{
+ #if PCI_BASE
+ Uint32 address = PCI_BASE | Addr;
+ *(Uint32*)(address) = Data;
+ #else
+ #endif
+}
+
+Uint32 PCI_CfgReadDWord(Uint32 Addr)
+{
+ #if PCI_BASE
+ Uint32 address = PCI_BASE | Addr;
+ return *(Uint32*)address;
+ #else
+ return 0xFFFFFFFF;
+ #endif
+}
+
--- /dev/null
+/*
+ * Acess2 ARM
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/proc.S
+ * - Process management assembly
+ */
+
+#include "include/assembly.h"
+
+.globl KernelThreadHeader
+@ SP+12: Argument 1
+@ SP+8: Argument Count
+@ SP+4: Function
+@ SP+0: Thread Pointer
+KernelThreadHeader:
+ ldr r0, [sp],#4
+ @ TODO: Do something with the thread pointer
+
+ ldr r4, [sp],#4 @ Function
+ @ Get argument
+ ldr r0, [sp],#4
+
+ blx r4
+
+ ldr r0, =0
+ bl Threads_Exit
+ b .
+
+.globl SwitchTask
+@ R0: New stack
+@ R1: Pointer to where to save old stack
+@ R2: New IP
+@ R3: Pointer to save old IP
+@ SP+0: New address space
+SwitchTask:
+ push {r4-r12,lr}
+
+ @ Save IP
+ ldr r4, =.return
+ str r4, [r3]
+ @ Save SP
+ str sp, [r1]
+
+ @ Only update TTBR0 if the task has an explicit address space
+ ldr r1, [sp,#4*10]
+ tst r1, r1
+ mcrne p15, 0, r1, c2, c0, 0 @ Set TTBR0 to r0
+# mov r1, #1
+ mcrne p15, 0, r1, c8, c7, 0 @ TLBIALL - Invalid user space
+
+ @ Restore state
+ mov sp, r0
+ bx r2
+
+.return:
+ pop {r4-r12,pc}
+
+.extern MM_Clone
+.extern MM_DumpTables
+.globl Proc_CloneInt
+Proc_CloneInt:
+ @ R0: SP Destination
+ @ R1: Mem Destination
+ push {r4-r12,lr}
+ mov r4, r1 @ Save mem destination
+ str sp, [r0] @ Save SP to SP dest
+
+ bl MM_Clone
+ str r0, [r4] @ Save clone return to Mem Dest
+
+ ldr r0, =Proc_CloneInt_new
+ pop {r4-r12,pc}
+Proc_CloneInt_new:
+ mov r0, #0
+ pop {r4-r12,pc}
+
+@ R0: New user SP
+@ Return: Old user SP
+.globl Proc_int_SwapUserSP
+Proc_int_SwapUserSP:
+ cps #31 @ Go to system mode
+ mov r1, sp
+ tst r0, r0 @ Only update if non-zero
+ movne sp, r0
+ mov r0, r1
+ cps #19
+ mov pc, lr
+
+.section .usertext, "ax"
+.globl Proc_int_DropToUser
+@ R0: User IP
+@ R1: User SP
+Proc_int_DropToUser:
+ cps #16
+ mov sp, r1
+ mov pc, r0
+
+.section .rodata
+csProc_CloneInt_NewTaskMessage:
+ .asciz "New task PC=%p, R4=%p, sp=%p"
+csProc_CloneInt_OldTaskMessage:
+ .asciz "Parent task PC=%p, R4=%p, SP=%p"
+
+@ vim: ft=armv7
--- /dev/null
+/*
+ * Acess2
+ * - By John Hodge (thePowersGang)
+ *
+ * arch/arm7/proc.c
+ * - ARM7 Process Switching
+ */
+#include <acess.h>
+#include <threads_int.h>
+#include <hal_proc.h>
+
+// === IMPORTS ===
+extern tThread gThreadZero;
+extern tProcess gProcessZero;
+extern void SwitchTask(Uint32 NewSP, Uint32 *OldSP, Uint32 NewIP, Uint32 *OldIP, Uint32 MemPtr);
+extern void KernelThreadHeader(void); // Actually takes args on stack
+extern void Proc_int_DropToUser(Uint32 IP, Uint32 SP) NORETURN __attribute__((long_call));
+extern Uint32 Proc_int_SwapUserSP(Uint32 NewSP);
+extern Uint32 Proc_CloneInt(Uint32 *SP, Uint32 *MemPtr);
+extern tVAddr MM_NewKStack(int bGlobal); // TODO: Move out into a header
+extern tVAddr MM_NewUserStack(void);
+extern char kernel_table0[];
+
+// === PROTOTYPES ===
+void Proc_IdleThread(void *unused);
+
+// === GLOBALS ===
+tThread *gpCurrentThread = &gThreadZero;
+tThread *gpIdleThread = NULL;
+
+// === CODE ===
+void ArchThreads_Init(void)
+{
+ gProcessZero.MemState.Base = (tPAddr)&kernel_table0 - KERNEL_BASE;
+}
+
+void Proc_IdleThread(void *unused)
+{
+ Threads_SetPriority(gpIdleThread, -1);
+ for(;;) {
+ Proc_Reschedule();
+ __asm__ __volatile__ ("wfi");
+ }
+}
+
+void Proc_Start(void)
+{
+ tTID tid;
+
+ tid = Proc_NewKThread( Proc_IdleThread, NULL );
+ gpIdleThread = Threads_GetThread(tid);
+ gpIdleThread->ThreadName = (char*)"Idle Thread";
+}
+
+int GetCPUNum(void)
+{
+ return 0;
+}
+
+tThread *Proc_GetCurThread(void)
+{
+ return gpCurrentThread;
+}
+
+void Proc_StartUser(Uint Entrypoint, Uint Base, int ArgC, const char **ArgV, int DataSize)
+{
+ Uint32 *usr_sp;
+ int i;
+ const char **envp;
+ tVAddr delta;
+
+// Log_Debug("Proc", "Proc_StartUser: (Entrypoint=%p, Base=%p, ArgC=%i, ArgV=%p, DataSize=0x%x)",
+// Entrypoint, Base, ArgC, ArgV, DataSize);
+
+ // Write data to the user's stack
+ usr_sp = (void*)MM_NewUserStack();
+ usr_sp -= (DataSize+3)/4;
+ memcpy(usr_sp, ArgV, DataSize);
+ free(ArgV);
+
+ // Adjust user's copy of the arguments
+ delta = (tVAddr)usr_sp - (tVAddr)ArgV;
+ ArgV = (void*)usr_sp;
+ for(i = 0; ArgV[i]; i ++) ArgV[i] += delta;
+ envp = &ArgV[i+1];
+ for(i = 0; envp[i]; i ++) envp[i] += delta;
+
+ *--usr_sp = (Uint32)envp;
+ *--usr_sp = (Uint32)ArgV;
+ *--usr_sp = (Uint32)ArgC;
+ *--usr_sp = Base;
+
+ // Drop to user code
+ Log_Debug("Proc", "Proc_int_DropToUser(%p, %p)", Entrypoint, usr_sp);
+ Proc_int_DropToUser(Entrypoint, (Uint32)usr_sp);
+}
+
+void Proc_ClearProcess(tProcess *Process)
+{
+ Log_Warning("Proc", "TODO: Nuke address space etc");
+}
+
+void Proc_ClearThread(tThread *Thread)
+{
+}
+
+tTID Proc_Clone(Uint Flags)
+{
+ tThread *new;
+ Uint32 pc, sp, mem;
+
+ new = Threads_CloneTCB(Flags);
+ if(!new) return -1;
+
+ // Actual clone magic
+ pc = Proc_CloneInt(&sp, &mem);
+ if(pc == 0) {
+ Log("Proc_Clone: In child");
+ return 0;
+ }
+
+ new->SavedState.IP = pc;
+ new->SavedState.SP = sp;
+ new->SavedState.UserSP = Proc_int_SwapUserSP(0);
+ new->SavedState.UserIP = Proc_GetCurThread()->SavedState.UserIP;
+ new->Process->MemState.Base = mem;
+
+ Threads_AddActive(new);
+
+ return new->TID;
+}
+
+int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
+{
+ tThread *new;
+ Uint32 sp;
+
+ new = Threads_CloneThreadZero();
+ if(!new) return -1;
+ if(new->ThreadName) free(new->ThreadName);
+ new->ThreadName = NULL;
+
+ new->KernelStack = MM_NewKStack(1);
+ if(!new->KernelStack) {
+ // TODO: Delete thread
+ Log_Error("Proc", "Unable to allocate kernel stack");
+ return -1;
+ }
+
+ sp = new->KernelStack;
+
+ *(Uint32*)(sp -= 4) = (Uint)Ptr;
+ *(Uint32*)(sp -= 4) = (Uint)Fnc;
+ *(Uint32*)(sp -= 4) = (Uint)new;
+
+ new->SavedState.SP = sp;
+ new->SavedState.IP = (Uint)KernelThreadHeader;
+
+ Threads_AddActive(new);
+
+ return new->TID;
+}
+
+tTID Proc_NewKThread( void (*Fnc)(void*), void *Ptr )
+{
+ tThread *new;
+ Uint32 sp;
+
+ new = Threads_CloneTCB(0);
+ if(!new) return -1;
+ free(new->ThreadName);
+ new->ThreadName = NULL;
+
+ // TODO: Non-shared stack
+ new->KernelStack = MM_NewKStack(1);
+ if(!new->KernelStack) {
+ // TODO: Delete thread
+ Log_Error("Proc", "Unable to allocate kernel stack");
+ return -1;
+ }
+
+ sp = new->KernelStack;
+
+ *(Uint32*)(sp -= 4) = (Uint)Ptr;
+ *(Uint32*)(sp -= 4) = (Uint)Fnc;
+ *(Uint32*)(sp -= 4) = (Uint)new;
+
+ new->SavedState.SP = sp;
+ new->SavedState.IP = (Uint)KernelThreadHeader;
+
+ Threads_AddActive(new);
+
+ return new->TID;
+}
+
+void Proc_CallFaultHandler(tThread *Thread)
+{
+
+}
+
+void Proc_Reschedule(void)
+{
+ tThread *cur, *next;
+
+ cur = gpCurrentThread;
+
+ next = Threads_GetNextToRun(0, cur);
+ if(!next) next = gpIdleThread;
+ if(!next || next == cur) return;
+
+ Log("Switching to %p (%i %s) IP=%p SP=%p TTBR0=%p UsrSP=%p",
+ next, next->TID, next->ThreadName,
+ next->SavedState.IP, next->SavedState.SP, next->Process->MemState.Base,
+ next->SavedState.UserSP
+ );
+
+ Log("Requested by %p", __builtin_return_address(0));
+
+ gpCurrentThread = next;
+
+ cur->SavedState.UserSP = Proc_int_SwapUserSP( next->SavedState.UserSP );
+
+ SwitchTask(
+ next->SavedState.SP, &cur->SavedState.SP,
+ next->SavedState.IP, &cur->SavedState.IP,
+ next->Process->MemState.Base
+ );
+
+}
+
+void Proc_DumpThreadCPUState(tThread *Thread)
+{
+
+}
+
--- /dev/null
+
+#include "include/assembly.h"
+#include "include/options.h"
+
+@
+@ Exception defs taken from ARM DDI 0406B
+@
+.section .init
+interrupt_vector_table:
+ivt_reset: b _start @ 0x00 Reset
+ivt_undef: b Undef_Handler @ 0x04 #UD
+ivt_svc: b SVC_Handler @ 0x08 SVC (used to be called SWI)
+ivt_prefetch: b PrefetchAbort @ 0x0C Prefetch abort
+ivt_data: b DataAbort @ 0x10 Data abort
+ivt_unused: b . @ 0x14 Not Used
+ivt_irq: b IRQHandler @ 0x18 IRQ
+ivt_fiq: b . @ 0x1C FIQ (Fast interrupt)
+
+.globl _start
+_start:
+ ldr r2, =UART0_PADDR
+ mov r1, #'A'
+ str r1, [r2]
+
+ ldr r0, =kernel_table0-KERNEL_BASE
+ mcr p15, 0, r0, c2, c0, 1 @ Set TTBR1 to r0
+ mcr p15, 0, r0, c2, c0, 0 @ Set TTBR0 to r0 too (for identity)
+
+ mov r1, #'c'
+ str r1, [r2]
+
+ mov r0, #1
+ mcr p15, 0, r0, c2, c0, 2 @ Set TTCR to 1 (50/50 split)
+
+ mov r1, #'e'
+ str r1, [r2]
+
+ mov r0, #3
+ mcr p15, 0, r0, c3, c0, 0 @ Set Domain 0 to Manager
+
+ mov r1, #'s'
+ str r1, [r2]
+
+ @ Enable VMSA
+ mrc p15, 0, r0, c1, c0, 0
+ orr r0, r0, #1
+ orr r0, r0, #1 << 23
+ mcr p15, 0, r0, c1, c0, 0
+
+ @ HACK: Set ASID to non zero
+ mov r0, #1
+ MCR p15,0,r0,c13,c0,1
+
+ ldr r2, =0xF1000000
+ mov r1, #'s'
+ str r1, [r2]
+
+ @ Enable access faults on domains 0 & 1
+ mov r0, #0x55 @ 01010101b
+ mcr p15, 0, r0, c3, c0, 0
+
+ mov r1, #'2'
+ str r1, [r2]
+
+ @
+ @ Check for security extensions
+ @
+ mrc p15, 0, r0, c0, c1, 1
+ and r0, #0xF0
+ @ - Present
+ ldrne r0,=KERNEL_BASE
+ mcrne p15, 0, r0, c12, c0, 0 @ Set the VBAR (brings exceptions into high memory)
+ @ - Absent
+ mrceq p15, 0, r0, c1, c0, 0 @ Set SCTLR.V
+ orreq r0, #0x2000
+ mcreq p15, 0, r0, c1, c0, 0
+
+ mov r1, #'-'
+ str r1, [r2]
+
+ @ Prepare for interrupts
+ cps #18 @ IRQ Mode
+ ldr sp, =irqstack+0x1000 @ Set up stack
+ cps #23 @ Abort Mode
+ ldr sp, =abortstack+0x1000
+ cps #19
+
+ mov r1, #'a'
+ str r1, [r2]
+ mov r1, #'r'
+ str r1, [r2]
+ mov r1, #'m'
+ str r1, [r2]
+ mov r1, #13
+ str r1, [r2]
+ mov r1, #10
+ str r1, [r2]
+
+.extern bss_start
+.extern bss_size_div_4
+.zero_bss:
+ ldr r0, =bss_start
+ ldr r1, =bss_end
+ mov r3, #0
+.zero_bss_loop:
+ str r3, [r0],#4
+ cmp r0, r1
+ bls .zero_bss_loop
+
+.goto_c:
+ ldr sp, =0x80000000-8 @ Set up stack (top of user range)
+ ldr r0, =kmain
+ mov pc, r0
+1: b 1b @ Infinite loop
+
+.comm irqstack, 0x1000 @ ; 4KiB Stack
+.comm abortstack, 0x1000 @ ; 4KiB Stack
+
+.extern SyscallHandler
+SVC_Handler:
+@ sub lr, #4
+ srsdb sp!, #19 @ Save state to stack
+ cpsie ifa, #19 @ Ensure we're in supervisor with interrupts enabled (should already be there)
+ push {r0-r12}
+
+ ldr r4, [lr,#-4]
+ mvn r5, #0xFF000000
+ and r4, r5
+
+ tst r4, #0x1000
+ bne .arm_specifics
+
+ push {r4}
+
+ mov r0, sp
+ ldr r4, =SyscallHandler
+ blx r4
+
+@ ldr r0, =csSyscallPrintRetAddr
+@ ldr r1, [sp,#9*4+5*4]
+@ ldr r4, =Log
+@ blx r4
+
+ pop {r2} @ errno
+ pop {r0,r1} @ Ret/RetHi
+ add sp, #2*4 @ Saved r2/r3
+
+ pop {r4-r12}
+ rfeia sp! @ Pop state (actually RFEFD)
+.arm_specifics:
+ and r4, #0xFF
+ mov r0, r4 @ Number
+ mov r1, sp @ Arguments
+
+ ldr r4, =ARMv7_int_HandleSyscalls
+ blx r4
+
+ add sp, #4*4
+ pop {r4-r12}
+ rfeia sp!
+
+
+.globl gpIRQHandler
+gpIRQHandler: .long 0
+IRQ_saved_sp: .long 0
+IRQ_saved_lr: .long 0
+.globl IRQHandler
+IRQHandler:
+ sub lr, #4 @ Adjust LR to the correct value
+ srsdb sp!, #19 @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+ cps #19
+
+ PUSH_GPRS
+
+@ ldr r0, =csIRQ_Tag
+@ ldr r1, =csIRQ_Fmt
+@ ldr r4, =Log_Debug
+@ blx r4
+
+ @ Call the registered handler
+ ldr r0, gpIRQHandler
+ blx r0
+
+ @ Restore CPU state
+ POP_GPRS
+ cpsie i
+ rfeia sp! @ Pop state (actually RFEFD)
+ bx lr
+
+.globl DataAbort
+DataAbort:
+ sub lr, #8 @ Adjust LR to the correct value
+ srsdb sp!, #23 @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+@ cpsid ifa, #19
+ PUSH_GPRS
+
+ mov r3, #0 @ not a prefetch abort
+ mrc p15, 0, r2, c5, c0, 0 @ Read DFSR (Data Fault Status Register) to R2
+ mrc p15, 0, r1, c6, c0, 0 @ Read DFAR (Data Fault Address Register) into R1
+ mov r0, lr @ PC
+ ldr r4, =MM_PageFault
+ blx r4
+
+ POP_GPRS
+ rfeia sp! @ Pop state (actually RFEFD)
+
+.globl PrefetchAbort
+PrefetchAbort:
+ sub lr, #4 @ Adjust LR to the correct value
+ srsdb sp!, #23 @ Switch to supervisor mode (DDI0406B D1.6.5) (actually SRSFD)
+@ cpsid ifa, #19
+ PUSH_GPRS
+
+ ldr r0, =csAbort_Tag
+ ldr r1, =csPrefetchAbort_Fmt
+# mov r2, lr
+ mrc p15, 0, r2, c6, c0, 2 @ Read IFAR (Instruction Fault Address Register) into R3
+ mrc p15, 0, r3, c5, c0, 1 @ Read IFSR (Instruction Fault Status Register) into R3
+ ldr r5, =Log_Error
+ blx r5
+
+.loop:
+ wfi
+ b .loop
+.globl Undef_Handler
+Undef_Handler:
+ wfi
+ b Undef_Handler
+
+.globl abort
+abort:
+ wfi
+ b abort
+
+
+.section .rodata
+csIRQ_Tag:
+csAbort_Tag:
+ .asciz "ARMv7"
+csIRQ_Fmt:
+ .asciz "IRQ"
+csDataAbort_Fmt:
+ .asciz "Data Abort - %p accessed %p, DFSR=%x Unk:%x Unk:%x"
+csPrefetchAbort_Fmt:
+ .asciz "Prefetch Abort at %p, IFSR=%x"
+csSyscallPrintRetAddr:
+ .asciz "Syscall ret to %p"
+
+.section .padata
+.globl kernel_table0
+
+kernel_table0:
+ .long 0x00000402 @ Identity map the first 1 MiB
+ .rept 0x7FC - 1
+ .long 0
+ .endr
+ .long user_table1_map + 0x000 - KERNEL_BASE + 1 @ 0x7FC00000
+ .long user_table1_map + 0x400 - KERNEL_BASE + 1 @ 0x7FD00000
+ .long user_table1_map + 0x800 - KERNEL_BASE + 1 @ KStacks
+ .long user_table1_map + 0xC00 - KERNEL_BASE + 1
+ @ 0x80000000 - User/Kernel split
+ .long 0x00000402 @ Map first 4 MiB to 2GiB (KRW only)
+ .long 0x00100402 @
+ .long 0x00200402 @
+ .long 0x00300402 @
+ .rept 0xF00 - 0x800 - 4
+ .long 0
+ .endr
+#if PCI_PADDR
+ .long PCI_PADDR + 0*(1 << 20) + 0x402 @ Map PCI config space
+ .long PCI_PADDR + 1*(1 << 20) + 0x402
+ .long PCI_PADDR + 2*(1 << 20) + 0x402
+ .long PCI_PADDR + 3*(1 << 20) + 0x402
+ .long PCI_PADDR + 4*(1 << 20) + 0x402
+ .long PCI_PADDR + 5*(1 << 20) + 0x402
+ .long PCI_PADDR + 6*(1 << 20) + 0x402
+ .long PCI_PADDR + 7*(1 << 20) + 0x402
+ .long PCI_PADDR + 8*(1 << 20) + 0x402
+ .long PCI_PADDR + 9*(1 << 20) + 0x402
+ .long PCI_PADDR + 10*(1 << 20) + 0x402
+ .long PCI_PADDR + 11*(1 << 20) + 0x402
+ .long PCI_PADDR + 12*(1 << 20) + 0x402
+ .long PCI_PADDR + 13*(1 << 20) + 0x402
+ .long PCI_PADDR + 14*(1 << 20) + 0x402
+ .long PCI_PADDR + 15*(1 << 20) + 0x402
+#else
+ .rept 16
+ .long 0
+ .endr
+#endif
+ .long hwmap_table_0 + 0x000 - KERNEL_BASE + 1
+ .long hwmap_table_0 + 0x400 - KERNEL_BASE + 1
+ .long hwmap_table_0 + 0x800 - KERNEL_BASE + 1
+ .long hwmap_table_0 + 0xC00 - KERNEL_BASE + 1
+ .rept 0xFF8 - 0xF00 - 16 - 4
+ .long 0
+ .endr
+ @ Page fractals
+ .long kernel_table1_map + 0x000 - KERNEL_BASE + 1
+ .long kernel_table1_map + 0x400 - KERNEL_BASE + 1
+ .long kernel_table1_map + 0x800 - KERNEL_BASE + 1
+ .long kernel_table1_map + 0xC00 - KERNEL_BASE + 1
+ .long kernel_exception_map + 0x000 - KERNEL_BASE + 1
+ .long kernel_exception_map + 0x400 - KERNEL_BASE + 1
+ .long kernel_exception_map + 0x800 - KERNEL_BASE + 1
+ .long kernel_exception_map + 0xC00 - KERNEL_BASE + 1
+
+@ PID0 user table
+.globl user_table1_map
+@ User table1 data table (only the first half is needed)
+@ - Abused to provide kernel stacks in the unused half of the table
+user_table1_map: @ Size = 4KiB (only 2KiB used)
+ .rept 0x800/4-1
+ .long 0
+ .endr
+ .long user_table1_map - KERNEL_BASE + 0x13 @ ...1FF000 = 0x7FDFF000
+ @ Kernel stack zone
+ .long kernel_table0 + 0x0000 - KERNEL_BASE + 0x13 @ ...200000 = 0x7FE00000
+ .long kernel_table0 + 0x1000 - KERNEL_BASE + 0x13 @ ...201000 = 0x7FE01000
+ .rept (0x800/4)-(MM_KSTACK_SIZE/0x1000)-2
+ .long 0
+ .endr
+ #if MM_KSTACK_SIZE != 0x2000
+ #error Kernel stack size not changed in start.S
+ #endif
+ .long stack + 0x0000 - KERNEL_BASE + 0x13 @ Kernel Stack
+ .long stack + 0x1000 - KERNEL_BASE + 0x13 @
+
+.globl kernel_table1_map
+kernel_table1_map: @ Size = 4KiB
+ .rept (0xF00+16)/4
+ .long 0
+ .endr
+ .long hwmap_table_0 - KERNEL_BASE + 0x13
+ .rept 0xFF8/4 - (0xF00+16)/4 - 1
+ .long 0
+ .endr
+ .long kernel_table1_map - KERNEL_BASE + 0x13
+ .long kernel_exception_map - KERNEL_BASE + 0x13
+
+@ Hardware mappings
+.globl hwmap_table_0
+hwmap_table_0:
+ .long UART0_PADDR + 0x13 @ UART0
+ .rept 1024 - 1
+ .long 0
+ .endr
+.globl kernel_exception_map
+kernel_exception_map:
+ @ Padding
+ .rept 1024-256
+ .long 0
+ .endr
+ @ Align to nearly the end
+ .rept 256-16
+ .long 0
+ .endr
+ .long 0x212 @ Map first page for exceptions (Kernel RO, Execute)
+ .rept 16-1-2
+ .long 0
+ .endr
+ .long gUsertextPhysStart + 0x22 @ User .text (User RO, Kernel RW, because both is COW)
+ .long 0
+
+.section .padata
+stack:
+ .space MM_KSTACK_SIZE, 0 @ Original kernel stack
+
+// vim: ts=8 ft=armv7
+
--- /dev/null
+/*
+ * Acess2
+ *
+ * ARM7 Time code
+ * arch/arm7/time.c
+ */
+#include <acess.h>
+
+// === GLOBALS ===
+tTime giTimestamp;
+
+// === CODE ===
+tTime now(void)
+{
+ return giTimestamp;
+}
A_OBJ = start.ao main.o lib.o lib.ao time.o pci.o debug.o
A_OBJ += mm_phys.o mm_virt.o proc.o proc.ao
+A_OBJ += vpci_$(PLATFORM).o
#main.c: Makefile.BuildNum.$(ARCH)
// === PROTOTYPES ===
Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
Uint32 __divmod32(Uint32 Num, Uint32 Den, Uint32 *Rem);
+#if 0
Uint64 __udivdi3(Uint64 Num, Uint64 Den);
Uint64 __umoddi3(Uint64 Num, Uint64 Den);
Uint32 __udivsi3(Uint32 Num, Uint32 Den);
Uint32 __umodsi3(Uint32 Num, Uint32 Den);
Sint32 __divsi3(Sint32 Num, Sint32 Den);
Sint32 __modsi3(Sint32 Num, Sint32 Den);
+#endif
+void abort(void);
// === CODE ===
void *memcpy(void *_dest, const void *_src, size_t _length)
return ret;
}
+#if 0
// Unsigned Divide 64-bit Integer
Uint64 __udivdi3(Uint64 Num, Uint64 Den)
{
DivMod32S(Num, Den, &rem);
return rem;
}
+#endif
+
+void abort(void)
+{
+ for(;;);
+}
*(.usertext)
}
. += gUsertextPhysStart + _kernel_base - _usertext_vbase;
-
+
+ /DISCARD/ : { *(.ARM.extab.init .ARM.exidx.init) }
+ .ARM.extab : AT( ADDR(.ARM.extab) - _kernel_base)
+ {
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ }
+ PROVIDE_HIDDEN ( __exidx_start = . );
+ .ARM.exidx : AT( ADDR(.ARM.exidx) - _kernel_base)
+ {
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ }
+ PROVIDE_HIDDEN ( __exidx_end = . );
+ .eh_frame_hdr : AT( ADDR(.eh_frame_hdr) - _kernel_base) {
+ *(.eh_frame_hdr)
+ }
+ .eh_frame : AT( ADDR(.eh_frame) - _kernel_base) ONLY_IF_RO
+ {
+ KEEP (*(.eh_frame))
+ }
+ .gcc_except_table : AT( ADDR(.gcc_except_table) - _kernel_base) ONLY_IF_RO
+ {
+ *(.gcc_except_table .gcc_except_table.*)
+ }
+
/* 0x4000 (4 pages) alignment needed for root table */
- .data ALIGN(0x4000) : AT( ADDR(.data) - _kernel_base )
+ . = ALIGN(0x4000);
+ .data : AT( ADDR(.data) - _kernel_base )
{
*(.padata)
*(.data*)
*(KMODULES)
gKernelModulesEnd = .;
}
- .bss : AT( ADDR(.bss) - _kernel_base )
+ .bss ALIGN(0x1000) : AT( ADDR(.bss) - _kernel_base )
{
bss_start = .;
*(.bss*)
}
// --- Exports ---
-tPAddr MM_GetPhysAddr(tVAddr VAddr)
+tPAddr MM_GetPhysAddr(const void *Ptr)
{
tMM_PageInfo pi;
- if( MM_int_GetPageInfo(VAddr, &pi) )
+ if( MM_int_GetPageInfo((tVAddr)Ptr, &pi) )
return 0;
- return pi.PhysAddr | (VAddr & ((1 << pi.Size)-1));
+ return pi.PhysAddr | ((tVAddr)Ptr & ((1 << pi.Size)-1));
}
Uint MM_GetFlags(tVAddr VAddr)
cur += 256*Table;
- tmp_map = (void*)MM_MapTemp(table);
+ tmp_map = MM_MapTemp(table);
for( i = 0; i < 1024; i ++ )
{
tPAddr newpage;
newpage = MM_AllocPhys();
src = (void*)( (Table*256+i)*0x1000 );
- dst = (void*)MM_MapTemp(newpage);
+ dst = MM_MapTemp(newpage);
// Debug("Taking a copy of kernel page %p (%P)", src, cur[i] & ~0xFFF);
memcpy(dst, src, PAGE_SIZE);
- MM_FreeTemp( (tVAddr)dst );
+ MM_FreeTemp( dst );
tmp_map[i] = newpage | (cur[i] & 0xFFF);
}
else
break;
}
}
- MM_FreeTemp( (tVAddr) tmp_map );
+ MM_FreeTemp( tmp_map );
DestEnt[0] = table + 0*0x400 + 1;
DestEnt[1] = table + 1*0x400 + 1;
ret = MM_AllocateRootTable();
cur = (void*)MM_TABLE0USER;
- new_lvl1_1 = (void*)MM_MapTemp(ret);
- new_lvl1_2 = (void*)MM_MapTemp(ret+0x1000);
+ new_lvl1_1 = MM_MapTemp(ret);
+ new_lvl1_2 = MM_MapTemp(ret+0x1000);
tmp_map = new_lvl1_1;
for( i = 0; i < 0x800-4; i ++ )
{
{
int j, num;
tPAddr tmp = MM_AllocPhys();
- Uint32 *table = (void*)MM_MapTemp(tmp);
+ Uint32 *table = MM_MapTemp(tmp);
Uint32 sp;
register Uint32 __SP asm("sp");
// Log("page = %P", page);
table[j] = page | 0x813;
- tmp_page = (void*)MM_MapTemp(page);
+ tmp_page = MM_MapTemp(page);
memcpy(tmp_page, (void*)sp, 0x1000);
- MM_FreeTemp( (tVAddr) tmp_page );
+ MM_FreeTemp( tmp_page );
}
- MM_FreeTemp( (tVAddr)table );
+ MM_FreeTemp( table );
}
- MM_FreeTemp( (tVAddr)new_lvl1_1 );
- MM_FreeTemp( (tVAddr)new_lvl1_2 );
+ MM_FreeTemp( new_lvl1_1 );
+ MM_FreeTemp( new_lvl1_2 );
// Log("MM_Clone: ret = %P", ret);
// MM_DumpTables(0, 0x80000000);
}
-tVAddr MM_MapTemp(tPAddr PAddr)
+void *MM_MapTemp(tPAddr PAddr)
{
tVAddr ret;
tMM_PageInfo pi;
MM_RefPhys(PAddr); // Counter the MM_Deallocate in FreeTemp
MM_Map(ret, PAddr);
- return ret;
+ return (void*)ret;
}
Log_Warning("MMVirt", "MM_MapTemp: All slots taken");
return 0;
}
-void MM_FreeTemp(tVAddr VAddr)
+void MM_FreeTemp(void *Ptr)
{
+ tVAddr VAddr = (tVAddr)Ptr;
if( VAddr < MM_TMPMAP_BASE || VAddr >= MM_TMPMAP_END ) {
Log_Warning("MMVirt", "MM_FreeTemp: Passed an addr not from MM_MapTemp (%p)", VAddr);
return ;
Log_Error("MMVirt", "Unable to allocate new page for COW");
for(;;);
}
- dst = (void*)MM_MapTemp(newpage);
+ dst = MM_MapTemp(newpage);
src = (void*)(Addr & ~(PAGE_SIZE-1));
memcpy( dst, src, PAGE_SIZE );
- MM_FreeTemp( (tVAddr)dst );
+ MM_FreeTemp( dst );
#if TRACE_COW
Log_Notice("MMVirt", "COW %p caused by %p, %P duped to %P (RefCnt(%i)--)", Addr, PC,
return new->TID;
}
-int Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
+tThread *Proc_SpawnWorker( void (*Fnc)(void*), void *Ptr )
{
tThread *new;
Uint32 sp;
if(!new->KernelStack) {
// TODO: Delete thread
Log_Error("Proc", "Unable to allocate kernel stack");
- return -1;
+ return NULL;
}
sp = new->KernelStack;
Threads_AddActive(new);
- return new->TID;
+ return new;
}
tTID Proc_NewKThread( void (*Fnc)(void*), void *Ptr )
--- /dev/null
+/*
+ * Acess2 Kernel ARMv7 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * vpci_tegra2.c
+ * - Tegra2 VPCI Definitions
+ */
+#include <virtual_pci.h>
+
+// === PROTOTYPES ===
+
+// === GLOBALS ===
+tVPCI_Device gaVPCI_Devices[] = {
+ {
+ .Vendor=0x0ACE,.Device=0x1100,
+ .Class = 0x0C032000, // Serial, USB, ECHI
+ .BARs = {0xC5000000,0,0,0,0,0},
+ .IRQ = 0*32+20,
+ },
+ {
+ .Vendor=0x0ACE,.Device=0x1100,
+ .Class = 0x0C032000, // Serial, USB, ECHI
+ .BARs = {0xC5004000,0,0,0,0,0},
+ .IRQ = 0*32+21,
+ },
+ {
+ .Vendor=0x0ACE,.Device=0x1100,
+ .Class = 0x0C032000, // Serial, USB, ECHI
+ .BARs = {0xC5008000,0,0,0,0,0},
+ .IRQ = 4*32+1,
+ }
+};
+int giVPCI_DeviceCount = sizeof(gaVPCI_Devices)/sizeof(gaVPCI_Devices[0]);
+
ASFLAGS += -D USE_MP=$(USE_MP)
CPPFLAGS += -DUSE_MP=$(USE_MP)
-A_OBJ = start.ao main.o lib.o desctab.ao errors.o irq.o
+A_OBJ = start.ao main.o mboot.o lib.o desctab.ao errors.o irq.o
A_OBJ += mm_phys.o mm_virt.o
A_OBJ += proc.o proc.ao time.o vm8086.o
-A_OBJ += kpanic.o pci.o
+A_OBJ += kpanic.o pci.o vpci.o
csaERROR_NAMES[Regs->int_num], Regs->err_code);
Log_Warning("Arch", "at CS:EIP %04x:%08x",
Regs->cs, Regs->eip);
+ Error_Backtrace(Regs->eip, Regs->ebp);
+
MM_DumpTables(0, KERNEL_BASE);
switch( Regs->int_num )
{
LogF("Backtrace: 0x%x", eip);
// else
// LogF("Backtrace: %s+0x%x", str, delta);
- if(!MM_GetPhysAddr(ebp))
+ if(!MM_GetPhysAddr((void*)ebp))
{
- LogF("\nBacktrace: Invalid EBP, stopping\n");
+ LogF("\nBacktrace: Invalid EBP %p, stopping\n", ebp);
return;
}
- while( MM_GetPhysAddr(ebp) && i < MAX_BACKTRACE )
+ while( MM_GetPhysAddr((void*)ebp) && i < MAX_BACKTRACE )
{
if( ebp >= MM_KERNEL_STACKS_END ) break;
//str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
ebp = *(Uint*)ebp;
i++;
}
- LogF("\n");
+ LogF("\r\n");
}
/**
int i;
for( i = 0; i < MAX_CALLBACKS_PER_IRQ; i++ )
{
- if( gIRQ_Handlers[Num][i] == NULL ) {
-// Log_Log("IRQ", "Added IRQ%i Cb#%i %p", Num, i, Callback);
+ if( gIRQ_Handlers[Num][i] == NULL )
+ {
+ Log_Log("IRQ", "Added IRQ%i Cb#%i %p", Num, i, Callback);
gIRQ_Handlers[Num][i] = Callback;
gaIRQ_DataPointers[Num][i] = Ptr;
return 1;
#include <init.h>
#include <mm_virt.h>
#include <mp.h>
+#include <pmemmap.h>
#define VGA_ERRORS 0
+#define KERNEL_LOAD 0x100000 // 1MiB
#define MAX_ARGSTR_POS (0x400000-0x2000)
+#define MAX_PMEMMAP_ENTS 16
// === IMPORTS ===
+extern char gKernelEnd[];
extern void Heap_Install(void);
-extern void Desctab_Install(void);
extern void MM_PreinitVirtual(void);
-extern void MM_Install(tMBoot_Info *MBoot);
+extern void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges);
extern void MM_InstallVirtual(void);
-extern void Threads_Init(void);
extern int Time_Setup(void);
-// --- Core ---
-extern void System_Init(char *Commandline);
// === PROTOTYPES ===
int kmain(Uint MbMagic, void *MbInfoPtr);
// === GLOBALS ===
char *gsBootCmdLine = NULL;
-struct {
- Uint32 PBase;
- void *Base;
- Uint Size;
- char *ArgString;
-} *gaArch_BootModules;
+tBootModule *gaArch_BootModules;
int giArch_NumBootModules = 0;
// === CODE ===
int kmain(Uint MbMagic, void *MbInfoPtr)
{
- int i;
- tMBoot_Module *mods;
tMBoot_Info *mbInfo;
+ tPMemMapEnt pmemmap[MAX_PMEMMAP_ENTS];
+ int nPMemMapEnts;
- LogF("Acess2 x86-"PLATFORM" v"EXPAND_STR(KERNEL_VERSION)"\n");
- LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
+ LogF("%s\r\n", gsBuildInfo);
- Log("MbMagic = %08x, MbInfoPtr = %p", MbMagic, MbInfoPtr);
-
- // Set up non-boot info dependent stuff
- Desctab_Install(); // Set up GDT and IDT
MM_PreinitVirtual(); // Initialise virtual mappings
-
+
+ mbInfo = MbInfoPtr;
+
switch(MbMagic)
{
// Multiboot 1
- case MULTIBOOT_MAGIC:
- // Adjust Multiboot structure address
- mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
+ case MULTIBOOT_MAGIC: {
+ // TODO: Handle when this isn't in the mapped area
gsBootCmdLine = (char*)(mbInfo->CommandLine + KERNEL_BASE);
-
- MM_Install( mbInfo ); // Set up physical memory manager
- break;
+
+ // Adjust Multiboot structure address
+ mbInfo = (void*)( (tVAddr)MbInfoPtr + KERNEL_BASE );
+
+ nPMemMapEnts = Multiboot_LoadMemoryMap(mbInfo, KERNEL_BASE, pmemmap, MAX_PMEMMAP_ENTS,
+ KERNEL_LOAD, (tVAddr)&gKernelEnd - KERNEL_BASE);
+
+ break; }
// Multiboot 2
case MULTIBOOT2_MAGIC:
return 0;
}
+ // Set up physical memory manager
+ MM_Install(nPMemMapEnts, pmemmap);
+
MM_InstallVirtual(); // Clean up virtual address space
Heap_Install(); // Create initial heap
VFS_Init();
// Load initial modules
- mods = (void*)( mbInfo->Modules + KERNEL_BASE );
- giArch_NumBootModules = mbInfo->ModuleCount;
- gaArch_BootModules = malloc( giArch_NumBootModules * sizeof(*gaArch_BootModules) );
- for( i = 0; i < mbInfo->ModuleCount; i ++ )
- {
- int ofs;
-
- Log_Log("Arch", "Multiboot Module at 0x%08x, 0x%08x bytes (String at 0x%08x)",
- mods[i].Start, mods[i].End-mods[i].Start, mods[i].String);
-
- gaArch_BootModules[i].PBase = mods[i].Start;
- gaArch_BootModules[i].Size = mods[i].End - mods[i].Start;
-
- // Always HW map the module data
- ofs = mods[i].Start&0xFFF;
- gaArch_BootModules[i].Base = (void*)( MM_MapHWPages(mods[i].Start,
- (gaArch_BootModules[i].Size+ofs+0xFFF) / 0x1000
- ) + ofs );
-
- // Only map the string if needed
- if( (tVAddr)mods[i].String > MAX_ARGSTR_POS )
- {
- // Assumes the string is < 4096 bytes long)
- gaArch_BootModules[i].ArgString = (void*)(
- MM_MapHWPages(mods[i].String, 2) + (mods[i].String&0xFFF)
- );
- }
- else
- gaArch_BootModules[i].ArgString = (char *)mods[i].String + KERNEL_BASE;
- }
+ gaArch_BootModules = Multiboot_LoadModules(mbInfo, KERNEL_BASE, &giArch_NumBootModules);
// Pass on to Independent Loader
Log_Log("Arch", "Starting system");
{
Log_Log("Arch", "Loading '%s'", gaArch_BootModules[i].ArgString);
- if( !Module_LoadMem( gaArch_BootModules[i].Base, gaArch_BootModules[i].Size, gaArch_BootModules[i].ArgString ) )
+ if( !Module_LoadMem( gaArch_BootModules[i].Base,
+ gaArch_BootModules[i].Size, gaArch_BootModules[i].ArgString
+ ) )
{
Log_Warning("Arch", "Unable to load module");
}
MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].ArgString, 2 );
}
Log_Log("Arch", "Boot modules loaded");
- free( gaArch_BootModules );
+ if( gaArch_BootModules )
+ free( gaArch_BootModules );
}
--- /dev/null
+/*
+ * Acess2 Kernel x86 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * mboot.c
+ * - Multiboot Support
+ */
+#define DEBUG 1
+#include <acess.h>
+#include <mboot.h>
+
+// === CODE ===
+int Multiboot_LoadMemoryMap(tMBoot_Info *MBInfo, tVAddr MapOffset, tPMemMapEnt *Map, const int MapSize, tPAddr KStart, tPAddr KEnd)
+{
+ int nPMemMapEnts = 0;
+ tMBoot_MMapEnt *ent = (void*)((tVAddr)MBInfo->MMapAddr + MapOffset);
+ tMBoot_MMapEnt *last = (void*)((tVAddr)ent + MBInfo->MMapLength);
+
+ ENTER("pMBInfo pMapOffset pMap iMapSize PKStart PKEnd",
+ MBInfo, MapOffset, Map, MapSize, KStart, KEnd);
+
+ // Check that the memory map is present
+ if( MBInfo->Flags & (1 << 6) )
+ {
+ // Build up memory map
+ nPMemMapEnts = 0;
+ while( ent < last && nPMemMapEnts < MapSize )
+ {
+ tPMemMapEnt *nent = &Map[nPMemMapEnts];
+ if( !MM_GetPhysAddr(ent) )
+ Log_KernelPanic("MBoot", "MBoot Map entry %i addres bad (%p)",
+ nPMemMapEnts, ent);
+
+ nent->Start = ent->Base;
+ nent->Length = ent->Length;
+ switch(ent->Type)
+ {
+ case 1:
+ nent->Type = PMEMTYPE_FREE;
+ break;
+ default:
+ nent->Type = PMEMTYPE_RESERVED;
+ break;
+ }
+ nent->NUMADomain = 0;
+
+ nPMemMapEnts ++;
+ ent = (void*)( (tVAddr)ent + ent->Size + 4 );
+ }
+ }
+ else if( MBInfo->Flags & (1 << 0) )
+ {
+ Log_Warning("MBoot", "No memory map passed, using mem_lower and mem_upper");
+ nPMemMapEnts = 2;
+ Map[0].Start = 0;
+ Map[0].Length = MBInfo->LowMem * 1024;
+ Map[0].Type = PMEMTYPE_FREE;
+ Map[0].NUMADomain = 0;
+
+ Map[1].Start = 0x100000;
+ Map[1].Length = MBInfo->HighMem * 1024;
+ Map[1].Type = PMEMTYPE_FREE;
+ Map[1].NUMADomain = 0;
+ }
+ else
+ {
+ Log_KernelPanic("MBoot", "Multiboot didn't pass memory information");
+ }
+
+ // Ensure it's valid
+ nPMemMapEnts = PMemMap_ValidateMap(Map, nPMemMapEnts, MapSize);
+ // TODO: Error handling
+
+ // Replace kernel with PMEMTYPE_USED
+ nPMemMapEnts = PMemMap_MarkRangeUsed(
+ Map, nPMemMapEnts, MapSize,
+ KStart, KEnd - KStart
+ );
+
+ PMemMap_DumpBlocks(Map, nPMemMapEnts);
+
+ // Check if boot modules were passed
+ if( MBInfo->Flags & (1 << 3) )
+ {
+ // Replace modules with PMEMTYPE_USED
+ nPMemMapEnts = PMemMap_MarkRangeUsed(Map, nPMemMapEnts, MapSize,
+ MBInfo->Modules, MBInfo->ModuleCount*sizeof(tMBoot_Module)
+ );
+ LOG("MBInfo->Modules = %x", MBInfo->Modules);
+ tMBoot_Module *mods = (void*)( (tVAddr)MBInfo->Modules + MapOffset);
+ for( int i = 0; i < MBInfo->ModuleCount; i ++ )
+ {
+ LOG("&mods[%i] = %p", i, &mods[i]);
+ LOG("mods[i] = {0x%x -> 0x%x}", mods[i].Start, mods[i].End);
+ nPMemMapEnts = PMemMap_MarkRangeUsed(
+ Map, nPMemMapEnts, MapSize,
+ mods[i].Start, mods[i].End - mods[i].Start
+ );
+ }
+ }
+
+ // Debug - Output map
+ PMemMap_DumpBlocks(Map, nPMemMapEnts);
+
+ LEAVE('i', nPMemMapEnts);
+ return nPMemMapEnts;
+}
+
+tBootModule *Multiboot_LoadModules(tMBoot_Info *MBInfo, tVAddr MapOffset, int *ModuleCount)
+{
+ if( !(MBInfo->Flags & (1 << 3)) ) {
+ *ModuleCount = 0;
+ Log_Log("Arch", "No multiboot module information passed");
+ return NULL;
+ }
+
+ tMBoot_Module *mods = (void*)( MBInfo->Modules + MapOffset );
+ *ModuleCount = MBInfo->ModuleCount;
+ tBootModule *ret = malloc( MBInfo->ModuleCount * sizeof(*ret) );
+ for( int i = 0; i < MBInfo->ModuleCount; i ++ )
+ {
+ int ofs;
+
+ Log_Log("Arch", "Multiboot Module at 0x%08x, 0x%08x bytes (String at 0x%08x)",
+ mods[i].Start, mods[i].End-mods[i].Start, mods[i].String);
+
+ ret[i].PBase = mods[i].Start;
+ ret[i].Size = mods[i].End - mods[i].Start;
+
+ // Always HW map the module data
+ ofs = mods[i].Start&0xFFF;
+ ret[i].Base = (void*)( MM_MapHWPages(mods[i].Start,
+ (ret[i].Size+ofs+0xFFF) / 0x1000
+ ) + ofs );
+
+ // Only map the string if needed
+ if( !MM_GetPhysAddr( (void*)(mods[i].String + MapOffset) ) )
+ {
+ // Assumes the string is < 4096 bytes long)
+ ret[i].ArgString = (void*)(
+ MM_MapHWPages(mods[i].String, 2) + (mods[i].String&0xFFF)
+ );
+ }
+ else
+ ret[i].ArgString = (char*)(tVAddr)mods[i].String + MapOffset;
+ }
+
+ return ret;
+}
+
*/
#define DEBUG 0
#include <acess.h>
-#include <mboot.h>
#include <mm_virt.h>
+#include <pmemmap.h>
+#include <hal_proc.h>
//#define USE_STACK 1
#define TRACE_ALLOCS 0 // Print trace messages on AllocPhys/DerefPhys
+static const int addrClasses[] = {0,16,20,24,32,64};
+static const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
// === IMPORTS ===
-extern char gKernelEnd[];
extern void Proc_PrintBacktrace(void);
// === PROTOTYPES ===
-void MM_Install(tMBoot_Info *MBoot);
+void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges);
//tPAddr MM_AllocPhys(void);
//tPAddr MM_AllocPhysRange(int Pages, int MaxBits);
//void MM_RefPhys(tPAddr PAddr);
Uint64 giPhysAlloc = 0; // Number of allocated pages
Uint64 giPageCount = 0; // Total number of pages
Uint64 giLastPossibleFree = 0; // Last possible free page (before all pages are used)
+Uint64 giTotalMemorySize = 0; // Total number of allocatable pages
Uint32 gaSuperBitmap[1024]; // Blocks of 1024 Pages
Uint32 gaPageBitmap[1024*1024/32]; // Individual pages
#define REFENT_PER_PAGE (0x1000/sizeof(gaPageReferences[0]))
// === CODE ===
-void MM_Install(tMBoot_Info *MBoot)
+void MM_Install(int NPMemRanges, tPMemMapEnt *PMemRanges)
{
- Uint kernelPages, num;
Uint i;
Uint64 maxAddr = 0;
- tMBoot_Module *mods;
- tMBoot_MMapEnt *ent;
// --- Find largest address
- MBoot->MMapAddr |= KERNEL_BASE;
- ent = (void *)( MBoot->MMapAddr );
- while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
+ for( i = 0; i < NPMemRanges; i ++ )
{
- // Adjust for size
- ent->Size += 4;
-
+ tPMemMapEnt *ent = &PMemRanges[i];
// If entry is RAM and is above `maxAddr`, change `maxAddr`
- if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
- maxAddr = ent->Base + ent->Length;
- // Go to next entry
- ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+ if(ent->Type == PMEMTYPE_FREE || ent->Type == PMEMTYPE_USED)
+ {
+ if(ent->Start + ent->Length > maxAddr)
+ maxAddr = ent->Start + ent->Length;
+ giTotalMemorySize += ent->Length >> 12;
+ }
}
- if(maxAddr == 0) {
- giPageCount = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value
- }
- else {
- giPageCount = maxAddr >> 12;
- }
+ giPageCount = maxAddr >> 12;
giLastPossibleFree = giPageCount - 1;
memsetd(gaPageBitmap, 0xFFFFFFFF, giPageCount/32);
// Set up allocateable space
- ent = (void *)( MBoot->MMapAddr );
- while( (Uint)ent < MBoot->MMapAddr + MBoot->MMapLength )
- {
- memsetd( &gaPageBitmap[ent->Base/(4096*32)], 0, ent->Length/(4096*32) );
- ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+ for( i = 0; i < NPMemRanges; i ++ )
+ {
+ tPMemMapEnt *ent = &PMemRanges[i];
+ if( ent->Type == PMEMTYPE_FREE )
+ {
+ Uint64 startpg = ent->Start / PAGE_SIZE;
+ Uint64 pgcount = ent->Length / PAGE_SIZE;
+ while( startpg % 32 && pgcount ) {
+ gaPageBitmap[startpg/32] &= ~(1U << (startpg%32));
+ startpg ++;
+ pgcount --;
+ }
+ memsetd( &gaPageBitmap[startpg/32], 0, pgcount/32 );
+ startpg += pgcount - pgcount%32;
+ pgcount -= pgcount - pgcount%32;
+ while(pgcount) {
+ gaPageBitmap[startpg/32] &= ~(1U << (startpg%32));
+ startpg ++;
+ pgcount --;
+ }
+ }
+ else if( ent->Type == PMEMTYPE_USED )
+ {
+ giPhysAlloc += ent->Length / PAGE_SIZE;
+ }
}
-
- // Get used page count (Kernel)
- kernelPages = (Uint)&gKernelEnd - KERNEL_BASE - 0x100000;
- kernelPages += 0xFFF; // Page Align
- kernelPages >>= 12;
- giPhysAlloc += kernelPages; // Add to used count
- // Fill page bitmap
- num = kernelPages/32;
- memsetd( &gaPageBitmap[0x100000/(4096*32)], -1, num );
- gaPageBitmap[ 0x100000/(4096*32) + num ] = (1 << (kernelPages & 31)) - 1;
-
// Fill Superpage bitmap
- num = kernelPages/(32*32);
- memsetd( &gaSuperBitmap[0x100000/(4096*32*32)], -1, num );
- gaSuperBitmap[ 0x100000/(4096*32*32) + num ] = (1 << ((kernelPages / 32) & 31)) - 1;
-
- // Mark Multiboot's pages as taken
- // - Structure
- MM_RefPhys( (Uint)MBoot - KERNEL_BASE );
- // - Module List
- for(i = (MBoot->ModuleCount*sizeof(tMBoot_Module)+0xFFF)>12; i--; )
- MM_RefPhys( MBoot->Modules + (i << 12) );
- // - Modules
- mods = (void*)(MBoot->Modules + KERNEL_BASE);
- for(i = 0; i < MBoot->ModuleCount; i++)
+ // - A set bit means that there are no free pages in this block of 32
+ for( i = 0; i < (giPageCount+31)/32; i ++ )
{
- num = (mods[i].End - mods[i].Start + 0xFFF) >> 12;
- while(num--)
- MM_RefPhys( (mods[i].Start & ~0xFFF) + (num<<12) );
+ if( gaPageBitmap[i] + 1 == 0 ) {
+ gaSuperBitmap[i/32] |= (1 << i%32);
+ }
}
-
+
gaPageReferences = (void*)MM_REFCOUNT_BASE;
Log_Log("PMem", "Physical memory set up (%lli pages of ~%lli MiB used)",
- giPhysAlloc, (giPageCount*4)/1024
+ giPhysAlloc, (giTotalMemorySize*PAGE_SIZE)/(1024*1024)
);
}
+void MM_DumpStatistics(void)
+{
+ int i, pg;
+ for( i = 1; i < numAddrClasses; i ++ )
+ {
+ int first = (i == 1 ? 0 : (1UL << (addrClasses[i-1] - 12)));
+ int last = (1UL << (addrClasses[i] - 12)) - 1;
+ int nFree = 0;
+ int nMultiRef = 0;
+ int totalRefs = 0;
+
+ if( last > giPageCount )
+ last = giPageCount;
+
+ int total = last - first + 1;
+
+ for( pg = first; pg < last; pg ++ )
+ {
+ if( !MM_GetPhysAddr(&gaPageReferences[pg]) || gaPageReferences[pg] == 0 ) {
+ nFree ++;
+ continue ;
+ }
+ totalRefs += gaPageReferences[pg];
+ if(gaPageReferences[pg] > 1)
+ nMultiRef ++;
+ }
+
+ int nUsed = (total - nFree);
+ Log_Log("MMPhys", "%ipbit - %i/%i used, %i reused, %i average reference count",
+ addrClasses[i], nUsed, total, nMultiRef,
+ nMultiRef ? (totalRefs-(nUsed - nMultiRef)) / nMultiRef : 0
+ );
+
+ if( last == giPageCount )
+ break;
+ }
+ Log_Log("MMPhys", "%lli/%lli total pages used, 0 - %i possible free range",
+ giPhysAlloc, giTotalMemorySize, giLastPossibleFree);
+}
+
/**
* \fn tPAddr MM_AllocPhys(void)
* \brief Allocates a physical page from the general pool
*/
tPAddr MM_AllocPhys(void)
{
- // int a, b, c;
int indx = -1;
tPAddr ret;
Mutex_Acquire( &glPhysAlloc );
// Classful scan
- #if 1
{
- const int addrClasses[] = {0,16,20,24,32,64};
- const int numAddrClasses = sizeof(addrClasses)/sizeof(addrClasses[0]);
int i;
int first, last;
for( i = numAddrClasses; i -- > 1; )
// Out of memory?
if( i <= 1 ) indx = -1;
}
- #elif 0
- // Find free page
- // Scan downwards
- LOG("giLastPossibleFree = %i", giLastPossibleFree);
- for( indx = giLastPossibleFree; indx >= 0; )
- {
- if( gaSuperBitmap[indx>>10] == -1 ) {
- indx -= 1024;
- continue;
- }
-
- if( gaPageBitmap[indx>>5] == -1 ) {
- indx -= 32;
- continue;
- }
-
- if( gaPageBitmap[indx>>5] & (1 << (indx&31)) ) {
- indx --;
- continue;
- }
- break;
- }
- if( indx >= 0 )
- giLastPossibleFree = indx;
- LOG("indx = %i", indx);
- #else
- c = giLastPossibleFree % 32;
- b = (giLastPossibleFree / 32) % 32;
- a = giLastPossibleFree / 1024;
-
- LOG("a=%i,b=%i,c=%i", a, b, c);
- for( ; gaSuperBitmap[a] == -1 && a >= 0; a-- );
- if(a < 0) {
- Mutex_Release( &glPhysAlloc );
- Warning("MM_AllocPhys - OUT OF MEMORY (Called by %p) - %lli/%lli used",
- __builtin_return_address(0), giPhysAlloc, giPageCount);
- LEAVE('i', 0);
- return 0;
- }
- for( ; gaSuperBitmap[a] & (1<<b); b-- );
- for( ; gaPageBitmap[a*32+b] & (1<<c); c-- );
- LOG("a=%i,b=%i,c=%i", a, b, c);
- indx = (a << 10) | (b << 5) | c;
- if( indx >= 0 )
- giLastPossibleFree = indx;
- #endif
if( indx < 0 ) {
Mutex_Release( &glPhysAlloc );
}
// Mark page used
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[indx] ) )
+ if( MM_GetPhysAddr( &gaPageReferences[indx] ) )
gaPageReferences[indx] = 1;
gaPageBitmap[ indx>>5 ] |= 1 << (indx&31);
*/
tPAddr MM_AllocPhysRange(int Pages, int MaxBits)
{
- int a, b;
int i, idx, sidx;
tPAddr ret;
}
idx = sidx / 32;
sidx %= 32;
- b = idx % 32;
- a = idx / 32;
-
- #if 0
- LOG("a=%i, b=%i, idx=%i, sidx=%i", a, b, idx, sidx);
-
- // Find free page
- for( ; gaSuperBitmap[a] == -1 && a --; ) b = 31;
- if(a < 0) {
- Mutex_Release( &glPhysAlloc );
- Warning("MM_AllocPhysRange - OUT OF MEMORY (Called by %p)", __builtin_return_address(0));
- LEAVE('i', 0);
- return 0;
- }
- LOG("a = %i", a);
- for( ; gaSuperBitmap[a] & (1 << b); b-- ) sidx = 31;
- LOG("b = %i", b);
- idx = a * 32 + b;
- for( ; gaPageBitmap[idx] & (1 << sidx); sidx-- )
- LOG("gaPageBitmap[%i] = 0x%08x", idx, gaPageBitmap[idx]);
-
- LOG("idx = %i, sidx = %i", idx, sidx);
- #else
-
- #endif
// Check if the gap is large enough
while( idx >= 0 )
// Mark pages used
for( i = 0; i < Pages; i++ )
{
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[idx*32+sidx] ) )
+ if( MM_GetPhysAddr( &gaPageReferences[idx*32+sidx] ) )
gaPageReferences[idx*32+sidx] = 1;
gaPageBitmap[ idx ] |= 1 << sidx;
sidx ++;
// Reference the page
if( gaPageReferences )
{
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+ if( MM_GetPhysAddr( &gaPageReferences[PAddr] ) == 0 )
{
int i, base;
tVAddr addr = ((tVAddr)&gaPageReferences[PAddr]) & ~0xFFF;
giLastPossibleFree = PAddr;
// Dereference
- if( !MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
+ if( !MM_GetPhysAddr( &gaPageReferences[PAddr] ) || (-- gaPageReferences[PAddr]) == 0 )
{
#if TRACE_ALLOCS
Log_Debug("PMem", "MM_DerefPhys: Free'd %P (%i free)", PAddr<<12, giPageCount-giPhysAlloc);
if(gaPageBitmap[ PAddr / 32 ] == 0)
gaSuperBitmap[ PAddr >> 10 ] &= ~(1 << ((PAddr >> 5)&31));
- if( MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) )
+ if( MM_GetPhysAddr( &gaPageNodes[PAddr] ) )
{
gaPageNodes[PAddr] = NULL;
// TODO: Free Node Page when fully unused
// We don't care about non-ram pages
if(PAddr >= giPageCount) return -1;
- if( MM_GetPhysAddr( (tVAddr)&gaPageReferences[PAddr] ) == 0 )
+ if( MM_GetPhysAddr( &gaPageReferences[PAddr] ) == 0 )
return (gaPageBitmap[PAddr / 32] & (1 << PAddr%32)) ? 1 : 0;
// Check if it is freed
block_addr = (tVAddr) &gaPageNodes[PAddr];
block_addr &= ~(PAGE_SIZE-1);
- if( !MM_GetPhysAddr( block_addr ) )
+ if( !MM_GetPhysAddr( (void*)block_addr ) )
{
if( !MM_Allocate( block_addr ) ) {
Log_Warning("PMem", "Unable to allocate Node page");
if( MM_GetRefCount(PAddr) == 0 ) return 1;
PAddr /= PAGE_SIZE;
- if( !MM_GetPhysAddr( (tVAddr) &gaPageNodes[PAddr] ) ) {
+ if( !MM_GetPhysAddr( &gaPageNodes[PAddr] ) ) {
*Node = NULL;
return 0;
}
* \fn tPAddr MM_GetPhysAddr(tVAddr Addr)
* \brief Checks if the passed address is accesable
*/
-tPAddr MM_GetPhysAddr(tVAddr Addr)
+tPAddr MM_GetPhysAddr(const void *Addr)
{
- if( !(gaPageDir[Addr >> 22] & 1) )
+ tVAddr addr = (tVAddr)Addr;
+ if( !(gaPageDir[addr >> 22] & 1) )
return 0;
- if( !(gaPageTable[Addr >> 12] & 1) )
+ if( !(gaPageTable[addr >> 12] & 1) )
return 0;
- return (gaPageTable[Addr >> 12] & ~0xFFF) | (Addr & 0xFFF);
+ return (gaPageTable[addr >> 12] & ~0xFFF) | (addr & 0xFFF);
}
/**
MM_RefPhys( gaTmpTable[i*1024+j] & ~0xFFF );
- tmp = (void *) MM_MapTemp( gaTmpTable[i*1024+j] & ~0xFFF );
+ tmp = MM_MapTemp( gaTmpTable[i*1024+j] & ~0xFFF );
memcpy( tmp, (void *)( (i*1024+j)*0x1000 ), 0x1000 );
- MM_FreeTemp( (Uint)tmp );
+ MM_FreeTemp( tmp );
}
}
for(base = MM_KERNEL_STACKS; base < MM_KERNEL_STACKS_END; base += MM_KERNEL_STACK_SIZE)
{
// Check if space is free
- if(MM_GetPhysAddr(base) != 0) continue;
+ if(MM_GetPhysAddr( (void*) base) != 0)
+ continue;
// Allocate
//for(i = MM_KERNEL_STACK_SIZE; i -= 0x1000 ; )
for(i = 0; i < MM_KERNEL_STACK_SIZE; i += 0x1000 )
// NOTE: Max of 1 page
// `page` is the last allocated page from the previious for loop
- tmpPage = MM_MapTemp( page );
+ tmpPage = (tVAddr)MM_MapTemp( page );
memcpy( (void*)( tmpPage + (0x1000 - ContentsSize) ), StackContents, ContentsSize);
- MM_FreeTemp(tmpPage);
+ MM_FreeTemp( (void*)tmpPage );
//Log("MM_NewWorkerStack: RETURN 0x%x", base);
return base + WORKER_STACK_SIZE;
tPAddr MM_DuplicatePage(tVAddr VAddr)
{
tPAddr ret;
- Uint temp;
+ void *temp;
int wasRO = 0;
//ENTER("xVAddr", VAddr);
// Copy Data
temp = MM_MapTemp(ret);
- memcpy( (void*)temp, (void*)VAddr, 0x1000 );
+ memcpy( temp, (void*)VAddr, 0x1000 );
MM_FreeTemp(temp);
// Restore Writeable status
* \brief Create a temporary memory mapping
* \todo Show Luigi Barone (C Lecturer) and see what he thinks
*/
-tVAddr MM_MapTemp(tPAddr PAddr)
+void * MM_MapTemp(tPAddr PAddr)
{
int i;
INVLPG( TEMP_MAP_ADDR + (i << 12) );
//LEAVE('p', TEMP_MAP_ADDR + (i << 12));
Mutex_Release( &glTempMappings );
- return TEMP_MAP_ADDR + (i << 12);
+ return (void*)( TEMP_MAP_ADDR + (i << 12) );
}
Mutex_Release( &glTempMappings );
Threads_Yield(); // TODO: Use a sleep queue here instead
* \fn void MM_FreeTemp(tVAddr PAddr)
* \brief Free's a temp mapping
*/
-void MM_FreeTemp(tVAddr VAddr)
+void MM_FreeTemp(void *VAddr)
{
- int i = VAddr >> 12;
+ int i = (tVAddr)VAddr >> 12;
//ENTER("xVAddr", VAddr);
if(i >= (TEMP_MAP_ADDR >> 12))
*/
tVAddr MM_AllocDMA(int Pages, int MaxBits, tPAddr *PhysAddr)
{
- tPAddr maxCheck = (1 << MaxBits);
tPAddr phys;
tVAddr ret;
return 0;
}
- // Bound
- if(MaxBits >= PHYS_BITS) maxCheck = -1;
-
// Fast Allocate
if(Pages == 1 && MaxBits >= PHYS_BITS)
{
*/
void Proc_Start(void)
{
- int tid;
#if USE_MP
int i;
#endif
if(i) gaCPUs[i].Current = NULL;
// Create Idle Task
- tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
+ Proc_NewKThread(Proc_IdleThread, &gaCPUs[i]);
// Start the AP
if( i != giProc_BootProcessorID ) {
while( giNumInitingCPUs ) __asm__ __volatile__ ("hlt");
#else
// Create Idle Task
- tid = Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
-// gaCPUs[0].IdleThread = Threads_GetThread(tid);
+ Proc_NewKThread(Proc_IdleThread, &gaCPUs[0]);
// Set current task
gaCPUs[0].Current = &gThreadZero;
tTID Proc_NewKThread(void (*Fcn)(void*), void *Data)
{
Uint esp;
- tThread *newThread, *cur;
+ tThread *newThread;
- cur = Proc_GetCurThread();
newThread = Threads_CloneTCB(0);
if(!newThread) return -1;
* \fn int Proc_SpawnWorker(void)
* \brief Spawns a new worker thread
*/
-int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
+tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
{
tThread *new;
Uint stack_contents[4];
new = Threads_CloneThreadZero();
if(!new) {
Warning("Proc_SpawnWorker - Out of heap space!\n");
- return -1;
+ return NULL;
}
// Create the stack contents
new->Status = THREAD_STAT_PREINIT;
Threads_AddActive( new );
- return new->TID;
+ return new;
}
/**
// Check Prospective Space
for( i = USER_STACK_SZ >> 12; i--; )
- if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
+ if( MM_GetPhysAddr( (void*)(base + (i<<12)) ) != 0 )
break;
if(i != -1) return 0;
__asm__ __volatile__ ("mov %%ebp, %0" : "=r" (stack));
while( maxBacktraceDistance -- )
{
+ if( !CheckMem(stack, 8) ) {
+ regs = NULL;
+ break;
+ }
// [ebp] = oldEbp
// [ebp+4] = retaddr
[section .text]
[extern kmain]
+[extern Desctab_Install]
[global start]
start:
; Just show we're here
.higher_half:
mov WORD [0xB8006], 0x0773 ; 's'
+
+ push ebx ; Multiboot Info
+ push eax ; Multiboot Magic Value
+ ; NOTE: These are actually for kmain
+
+ call Desctab_Install
mov WORD [0xB8008], 0x0773 ; 's'
; Call the kernel
- push ebx ; Multiboot Info
- push eax ; Multiboot Magic Value
mov WORD [0xB800A], 0x0732 ; '2'
call kmain
--- /dev/null
+/*
+ * Acess2 Kernel x86 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * vpci.c
+ * - Virtual PCI Bus
+ */
+#include <virtual_pci.h>
+
+// === GLOBALS ===
+ int giVPCI_DeviceCount = 0;
+tVPCI_Device gaVPCI_Devices[0];
+
A_OBJ := start32.ao start64.ao desctab.ao proc.ao
A_OBJ += main.o lib.o proc.o mm_virt.o mm_phys.o
A_OBJ += kernelpanic.o errors.o time.o pci.o
-A_OBJ += vm8086.o
+A_OBJ += vm8086.o vpci.o
+A_OBJ += ../x86/mboot.o
# rme.o
POSTBUILD = objcopy $(BIN) -F elf32-i386 $(BIN)
[BITS 64]
[extern Log]
+[extern Log_Debug]
[extern gGDTPtr]
[extern gGDT]
push rax
push rdx
sub rsp, 8
- mov rcx, rdi ; IRQ Number
- mov rdx, rsi ; Callback
- mov rsi, rax ; Pointer
- mov rdi, csIRQ_Assigned
- call Log
+ mov rcx, rsi ; IRQ Number
+ mov rdx, rdi ; Callback
+ mov rsi, csIRQ_Assigned
+ mov rdi, csIRQ_Tag
+ call Log_Debug
add rsp, 8
pop rdx
pop rax
[section .rodata]
csIRQ_Assigned:
- db "IRQ %p := %p (IRQ %i)",0
+ db "IRQ %i .= %p",0
csIRQ_Fired:
db "IRQ %i fired",0
+csIRQ_Tag:
+ db "IRQ",0
[section .text]
%macro ISR_NOERRNO 1
LogF("Backtrace: %p", IP);
//else
// LogF("Backtrace: %s+0x%x", str, delta);
- if( !MM_GetPhysAddr(BP) )
+ if( !MM_GetPhysAddr( (void*)BP ) )
{
LogF("\nBacktrace: Invalid BP, stopping\n");
return;
}
- while( MM_GetPhysAddr(BP) && MM_GetPhysAddr(BP+8+7) && i < MAX_BACKTRACE )
+ while( MM_GetPhysAddr( (void*)BP) && MM_GetPhysAddr((void*)(BP+8+7)) && i < MAX_BACKTRACE )
{
//str = Debug_GetSymbol(*(Uint*)(ebp+4), &delta);
//if(str == NULL)
#define BITS 64
#define PAGE_SIZE 0x1000
+#ifndef MAX_CPUS
+# define MAX_CPUS 8
+#endif
+
#define STACKED_LOCKS 2 // 0: No, 1: Per-CPU, 2: Per-Thread
#define LOCK_DISABLE_INTS 0
--- /dev/null
+/*
+ * Acess2 Kernel x86_64
+ * - By John Hodge (thePowersGang)
+ *
+ * include/init.h
+ * - Arch-internal init functions
+ */
+#ifndef _ARCH__INIT_H_
+#define _ARCH__INIT_H_
+
+#include <pmemmap.h>
+
+extern void MM_InitPhys(int NPMemRanges, tPMemMapEnt *PMemRanges);
+
+#endif
+
return ret;
}
+EXPORT(memcpy);
+EXPORT(memset);
+
OUTPUT_ARCH(i386:x86-64)
*/
OUTPUT_FORMAT(elf64-x86-64)
-ENTRY(start)
+lstart = start - _kernel_base;
+ENTRY(lstart)
SECTIONS {
. = 0x100000;
/*
- * Acess2 x86_64 Project
+ * Acess2 Kernel x86_64
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Kernel C entrypoint
*/
#include <acess.h>
#include <mboot.h>
#include <init.h>
+#include <archinit.h>
+#include <pmemmap.h>
+
+// === CONSTANTS ===
+#define KERNEL_LOAD 0x100000
+#define MAX_PMEMMAP_ENTS 16
+#define MAX_ARGSTR_POS (0x200000-0x2000)
// === IMPORTS ===
extern void Desctab_Init(void);
extern void MM_InitVirt(void);
extern void Heap_Install(void);
-extern void Threads_Init(void);
extern int Time_Setup(void);
-extern void System_Init(char *Commandline);
-extern void MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
+extern char gKernelEnd[];
// === PROTOTYPES ===
void kmain(Uint MbMagic, void *MbInfoPtr);
// === GLOBALS ==
char *gsBootCmdLine = NULL;
+tBootModule *gaArch_BootModules;
+ int giArch_NumBootModules = 0;
// === CODE ===
void kmain(Uint MbMagic, void *MbInfoPtr)
{
tMBoot_Info *mbInfo;
+ tPMemMapEnt pmemmap[MAX_PMEMMAP_ENTS];
+ int nPMemMapEnts;
- LogF("Acess2 x86_64 v"EXPAND_STR(KERNEL_VERSION)"\n");
- LogF(" Build %i, Git Hash %s\n", BUILD_NUM, gsGitHash);
+ LogF("%s\r\n", gsBuildInfo);
Desctab_Init();
// Adjust Multiboot structure address
mbInfo = (void*)( (Uint)MbInfoPtr + KERNEL_BASE );
gsBootCmdLine = (char*)( (Uint)mbInfo->CommandLine + KERNEL_BASE);
- MM_InitPhys_Multiboot( mbInfo ); // Set up physical memory manager
+ // TODO: ref above?
+ nPMemMapEnts = Multiboot_LoadMemoryMap(mbInfo, KERNEL_BASE, pmemmap, MAX_PMEMMAP_ENTS,
+ KERNEL_LOAD, (tVAddr)&gKernelEnd - KERNEL_BASE
+ );
break;
default:
Panic("Multiboot magic invalid %08x, expected %08x\n",
return ;
}
+ MM_InitPhys( nPMemMapEnts, pmemmap ); // Set up physical memory manager
Log("gsBootCmdLine = '%s'", gsBootCmdLine);
+ switch(MbMagic)
+ {
+ case MULTIBOOT_MAGIC:
+ MM_RefPhys( mbInfo->CommandLine );
+ break;
+ }
+
*(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'D';
Heap_Install();
Log_Log("Arch", "Starting VFS...");
VFS_Init();
+ gaArch_BootModules = Multiboot_LoadModules(mbInfo, KERNEL_BASE, &giArch_NumBootModules);
+
*(Uint16*)(KERNEL_BASE|0xB8000) = 0x1F00|'Z';
// Pass on to Independent Loader
void Arch_LoadBootModules(void)
{
-
+ int i, j, numPages;
+ Log("gsBootCmdLine = '%s'", gsBootCmdLine);
+ for( i = 0; i < giArch_NumBootModules; i ++ )
+ {
+ Log_Log("Arch", "Loading '%s'", gaArch_BootModules[i].ArgString);
+
+ if( !Module_LoadMem( gaArch_BootModules[i].Base,
+ gaArch_BootModules[i].Size, gaArch_BootModules[i].ArgString
+ ) )
+ {
+ Log_Warning("Arch", "Unable to load module");
+ }
+
+ // Unmap and free
+ numPages = (gaArch_BootModules[i].Size + ((Uint)gaArch_BootModules[i].Base&0xFFF) + 0xFFF) >> 12;
+ MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].Base, numPages );
+
+ for( j = 0; j < numPages; j++ )
+ MM_DerefPhys( gaArch_BootModules[i].PBase + (j << 12) );
+
+ if( (tVAddr) gaArch_BootModules[i].ArgString < KERNEL_BASE )
+ MM_UnmapHWPages( (tVAddr)gaArch_BootModules[i].ArgString, 2 );
+ }
+ Log_Log("Arch", "Boot modules loaded");
+ if( gaArch_BootModules )
+ free( gaArch_BootModules );
}
void StartupPrint(const char *String)
*/
#define DEBUG 0
#include <acess.h>
-#include <mboot.h>
+#include <archinit.h>
+#include <pmemmap.h>
#include <mm_virt.h>
#define TRACE_REF 0
extern char gKernelEnd[];
// === PROTOTYPES ===
-void MM_InitPhys_Multiboot(tMBoot_Info *MBoot);
+//void MM_InitPhys(int NPMemRanges, tPMemMapEnt *PMemRanges);
//tPAddr MM_AllocPhysRange(int Num, int Bits);
//tPAddr MM_AllocPhys(void);
//void MM_RefPhys(tPAddr PAddr);
Uint64 giPhysRangeFirst[NUM_MM_PHYS_RANGES]; // First free page in each range
Uint64 giPhysRangeLast[NUM_MM_PHYS_RANGES]; // Last free page in each range
Uint64 giMaxPhysPage = 0; // Maximum Physical page
+Uint64 giTotalMemorySize = 0;
// Only used in init, allows the init code to provide pages for use by
// the allocator before the bitmaps exist.
// 3 entries because the are three calls to MM_AllocPhys in MM_Map
/**
* \brief Initialise the physical memory map using a Multiboot 1 map
*/
-void MM_InitPhys_Multiboot(tMBoot_Info *MBoot)
+void MM_InitPhys(int NPMemRanges, tPMemMapEnt *PMemRanges)
{
- tMBoot_MMapEnt *mmapStart;
- tMBoot_MMapEnt *ent;
Uint64 maxAddr = 0;
int numPages, superPages;
int i;
tVAddr vaddr;
tPAddr paddr, firstFreePage;
- ENTER("pMBoot=%p", MBoot);
+ ENTER("iNPMemRanges pPMemRanges",
+ NPMemRanges, PMemRanges);
// Scan the physical memory map
// Looking for the top of physical memory
- mmapStart = (void *)( KERNEL_BASE | MBoot->MMapAddr );
- LOG("mmapStart = %p", mmapStart);
- ent = mmapStart;
- while( (Uint)ent < (Uint)mmapStart + MBoot->MMapLength )
+ for( i = 0; i < NPMemRanges; i ++ )
{
+ tPMemMapEnt *ent = &PMemRanges[i];
// Adjust for the size of the entry
- ent->Size += 4;
- LOG("ent={Type:%i,Base:0x%x,Length:%x",
- ent->Type, ent->Base, ent->Length);
+ LOG("%i: ent={Type:%i,Base:0x%x,Length:%x}", i, ent->Type, ent->Start, ent->Length);
// If entry is RAM and is above `maxAddr`, change `maxAddr`
- if(ent->Type == 1 && ent->Base + ent->Length > maxAddr)
- maxAddr = ent->Base + ent->Length;
-
- // Go to next entry
- ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size );
+ if(ent->Type == PMEMTYPE_FREE || ent->Type == PMEMTYPE_USED )
+ {
+ if( ent->Start + ent->Length > maxAddr)
+ maxAddr = ent->Start + ent->Length;
+ giTotalMemorySize += ent->Length >> 12;
+ }
}
- // Did we find a valid end?
- if(maxAddr == 0) {
- // No, darn, let's just use the HighMem hack
- giMaxPhysPage = (MBoot->HighMem >> 2) + 256; // HighMem is a kByte value
- }
- else {
- // Goodie, goodie gumdrops
- giMaxPhysPage = maxAddr >> 12;
- }
+ giMaxPhysPage = maxAddr >> 12;
LOG("giMaxPhysPage = 0x%x", giMaxPhysPage);
-
- // Find a contigous section of memory to hold it in
- // - Starting from the end of the kernel
- // - We also need a region for the super bitmap
+
+ // Get counts of pages needed for basic structures
superPages = ((giMaxPhysPage+64*8-1)/(64*8) + 0xFFF) >> 12;
- numPages = (giMaxPhysPage + 7) / 8;
- numPages = (numPages + 0xFFF) >> 12;
+ numPages = ((giMaxPhysPage+7)/8 + 0xFFF) >> 12; // bytes to hold bitmap, divided up to nearest page
LOG("numPages = %i, superPages = %i", numPages, superPages);
- if(maxAddr == 0)
+
+ // --- Allocate Bitmaps ---
+ int todo = numPages*2 + superPages;
+ int mapent = NPMemRanges-1;
+ vaddr = MM_PAGE_BITMAP;
+ paddr = -1;
+ while( todo )
{
- int todo = numPages*2 + superPages;
- // Ok, naieve allocation, just put it after the kernel
- // - Allocated Bitmap
- vaddr = MM_PAGE_BITMAP;
- paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
- while(todo )
+ while(PMemRanges[mapent].Type != PMEMTYPE_FREE && mapent != -1)
+ mapent --;
+ if( paddr + 1 == 0 )
+ paddr = PMemRanges[mapent].Start;
+ if( mapent == -1 ) {
+ // OOM During init, bad thing
+ Log_KernelPanic("PMem", "Out of memory during init");
+ for(;;);
+ }
+
+ // Ensure that the static allocation pool has pages
+ for( i = 0; i < NUM_STATIC_ALLOC; i++)
{
- // Allocate statics
- for( i = 0; i < NUM_STATIC_ALLOC; i++) {
- if(gaiStaticAllocPages[i] != 0) continue;
+ if(gaiStaticAllocPages[i] == 0)
+ {
gaiStaticAllocPages[i] = paddr;
- paddr += 0x1000;
+ // break to ensure we update the address correctly
+ break;
}
-
+ }
+
+ if( i == NUM_STATIC_ALLOC )
+ {
+ // Map
MM_Map(vaddr, paddr);
- vaddr += 0x1000;
- paddr += 0x1000;
-
todo --;
+ // Update virtual pointer
+ vaddr += 0x1000;
if( todo == numPages + superPages )
vaddr = MM_PAGE_DBLBMP;
if( todo == superPages )
vaddr = MM_PAGE_SUPBMP;
+ }
+
+ // Update physical pointer
+ // (underflows are detected at the top of the loop)
+ paddr += 0x1000;
+ if( paddr - PMemRanges[mapent].Start > PMemRanges[mapent].Length )
+ mapent --;
+ else {
+ // NOTE: This hides some actually valid memory, but since the pmm
+ // structures have an "infinite" lifetime, this is of no concequence.
+ PMemRanges[mapent].Start += 0x1000;
+ PMemRanges[mapent].Length -= 0x1000;
}
}
- // Scan for a nice range
- else
- {
- int todo = numPages*2 + superPages;
- paddr = 0;
- vaddr = MM_PAGE_BITMAP;
- // Scan!
- for(
- ent = mmapStart;
- (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
- ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
- )
- {
- int avail;
-
- // RAM only please
- if( ent->Type != 1 )
- continue;
-
- // Let's not put it below the kernel, shall we?
- if( ent->Base + ent->Size < (tPAddr)&gKernelBase )
- continue;
-
- LOG("%x <= %x && %x > %x",
- ent->Base, (tPAddr)&gKernelBase,
- ent->Base + ent->Size, (tPAddr)&gKernelEnd - KERNEL_BASE
- );
- // Check if the kernel is in this range
- if( ent->Base <= (tPAddr)&gKernelBase
- && ent->Base + ent->Length > (tPAddr)&gKernelEnd - KERNEL_BASE )
- {
- avail = ent->Length >> 12;
- avail -= ((tPAddr)&gKernelEnd - KERNEL_BASE - ent->Base) >> 12;
- paddr = (tPAddr)&gKernelEnd - KERNEL_BASE;
- }
- // No? then we can use all of the block
- else
- {
- avail = ent->Length >> 12;
- paddr = ent->Base;
- }
-
- Log("MM_InitPhys_Multiboot: paddr=0x%x, avail=0x%x pg", paddr, avail);
-
- // Map
- while( todo && avail --)
- {
- // Static Allocations
- for( i = 0; i < NUM_STATIC_ALLOC && avail; i++) {
- if(gaiStaticAllocPages[i] != 0) continue;
- gaiStaticAllocPages[i] = paddr;
- paddr += 0x1000;
- avail --;
- }
- if(!avail) break;
-
- // Map
- MM_Map(vaddr, paddr);
- todo --;
- vaddr += 0x1000;
- paddr += 0x1000;
-
- // Alter the destination address when needed
- if(todo == superPages+numPages)
- vaddr = MM_PAGE_DBLBMP;
- if(todo == superPages)
- vaddr = MM_PAGE_SUPBMP;
- }
-
- // Fast quit if there's nothing left to allocate
- if( !todo ) break;
- }
- }
+
+ PMemMap_DumpBlocks(PMemRanges, NPMemRanges);
+
// Save the current value of paddr to simplify the allocation later
firstFreePage = paddr;
LOG("Clearing multi bitmap");
- // Fill the bitmaps
- memset(gaMultiBitmap, 0, (numPages<<12)/8);
- // - initialise to one, then clear the avaliable areas
- memset(gaMainBitmap, -1, (numPages<<12)/8);
- memset(gaSuperBitmap, -1, (numPages<<12)/(8*64));
- LOG("Setting main bitmap");
+ // Fill the bitmaps (set most to "allocated")
+ memset(gaMultiBitmap, 0, numPages<<12);
+ memset(gaMainBitmap, 255, numPages<<12);
// - Clear all Type=1 areas
LOG("Clearing valid regions");
- for(
- ent = mmapStart;
- (Uint)ent < (Uint)mmapStart + MBoot->MMapLength;
- ent = (tMBoot_MMapEnt *)( (Uint)ent + ent->Size )
- )
+ for( i = 0; i < NPMemRanges; i ++ )
{
+ tPMemMapEnt *ent = &PMemRanges[i];
// Check if the type is RAM
- if(ent->Type != 1) continue;
+ if(ent->Type != PMEMTYPE_FREE) continue;
// Main bitmap
- base = ent->Base >> 12;
- size = ent->Size >> 12;
-
- if(base & 63) {
- Uint64 val = -1LL << (base & 63);
- gaMainBitmap[base / 64] &= ~val;
- size -= (base & 63);
- base += 64 - (base & 63);
- }
- memset( &gaMainBitmap[base / 64], 0, size/8 );
- if( size & 7 ) {
- Uint64 val = -1LL << (size & 7);
- val <<= (size/8)&7;
- gaMainBitmap[base / 64] &= ~val;
+ base = ent->Start >> 12;
+ size = ent->Length >> 12;
+
+ LOG("%i: base=%x, size=%x", i, base, size);
+ if( base % 64 + size < 64 )
+ {
+ Uint64 bits = (1ULL << size) - 1;
+ bits <<= base % 64;
+ gaMainBitmap[base / 64] &= ~bits;
}
-
- // Super Bitmap
- base = ent->Base >> 12;
- size = ent->Size >> 12;
- size = (size + (base & 63) + 63) >> 6;
- base = base >> 6;
- if(base & 63) {
- Uint64 val = -1LL << (base & 63);
- gaSuperBitmap[base / 64] &= ~val;
-// size -= (base & 63);
-// base += 64 - (base & 63);
+ else
+ {
+ if(base & 63)
+ {
+ // Keep lower bits
+ Uint64 bits = (1ULL << (base & 63)) - 1;
+ gaMainBitmap[base / 64] &= bits;
+
+ size -= 64 - base % 64;
+ base += 64 - base % 64;
+ }
+ LOG("%i: base=%x, size=%x", i, base, size);
+ memset( &gaMainBitmap[base / 64], 0, (size/64)*8 );
+ base += size & ~(64-1);
+ size -= size & ~(64-1);
+ LOG("%i: base=%x, size=%x", i, base, size);
+ if( size & 63 )
+ {
+ // Unset lower bits (hence the bitwise not)
+ Uint64 val = (1ULL << (size & 63)) - 1;
+ gaMainBitmap[base / 64] &= ~val;
+ }
}
}
- // Reference the used pages
- base = (tPAddr)&gKernelBase >> 12;
- size = firstFreePage >> 12;
- memset( &gaMainBitmap[base / 64], -1, size/8 );
- if( size & 7 ) {
- Uint64 val = -1LL << (size & 7);
- val <<= (size/8)&7;
- gaMainBitmap[base / 64] |= val;
- }
-
// Free the unused static allocs
- for( i = 0; i < NUM_STATIC_ALLOC; i++) {
- if(gaiStaticAllocPages[i] != 0)
- continue;
- gaMainBitmap[ gaiStaticAllocPages[i] >> (12+6) ]
- &= ~(1LL << ((gaiStaticAllocPages[i]>>12)&63));
+ LOG("Freeing unused static allocations");
+ for( i = 0; i < NUM_STATIC_ALLOC; i++)
+ {
+ if(gaiStaticAllocPages[i] == 0)
+ {
+ gaMainBitmap[ gaiStaticAllocPages[i] >> (12+6) ]
+ &= ~(1LL << ((gaiStaticAllocPages[i]>>12)&63));
+ gaiStaticAllocPages[i] = 0;
+ }
}
// Fill the super bitmap
LOG("Filling super bitmap");
memset(gaSuperBitmap, 0, superPages<<12);
- for( base = 0; base < (size+63)/64; base ++)
+ int nsuperbits = giMaxPhysPage / 64; // 64 pages per bit
+ for( i = 0; i < (nsuperbits+63)/64; i ++)
{
- if( gaMainBitmap[ base ] + 1 == 0 )
- gaSuperBitmap[ base/64 ] |= 1LL << (base&63);
+ if( gaMainBitmap[ i ] + 1 == 0 )
+ gaSuperBitmap[ i/64 ] |= 1ULL << (i % 64);
}
- // Set free page counts
+ // Set free page counts for each address class
for( base = 1; base < giMaxPhysPage; base ++ )
{
int rangeID;
// Set last (when the last free page is reached, this won't be
// updated anymore, hence will be correct)
giPhysRangeLast[ rangeID ] = base;
- }
-
+ }
+
LEAVE('-');
}
+void MM_DumpStatistics(void)
+{
+ // TODO: Statistics for x86_64 PMM
+}
+
/**
* \brief Allocate a contiguous range of physical pages with a maximum
* bit size of \a MaxBits
for( i = 0; i < Pages; i++, addr++ )
{
gaMainBitmap[addr >> 6] |= 1LL << (addr & 63);
- if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) )
+ if( MM_GetPhysAddr( &gaiPageReferences[addr] ) )
gaiPageReferences[addr] = 1;
// Log("page %P refcount = %i", MM_GetRefCount(addr<<12));
rangeID = MM_int_GetRangeID(addr << 12);
{
tVAddr ref_base = ((tVAddr)&gaiPageReferences[ page ]) & ~0xFFF;
// Allocate reference page
- if( !MM_GetPhysAddr(ref_base) )
+ if( !MM_GetPhysAddr(&gaiPageReferences[page]) )
{
const int pages_per_refpage = PAGE_SIZE/sizeof(gaiPageReferences[0]);
int i;
PAGE_ALLOC_SET(page);
if( gaMainBitmap[page >> 6] + 1 == 0 )
gaSuperBitmap[page>> 12] |= 1LL << ((page >> 6) & 63);
- if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
+ if( MM_GetPhysAddr( &gaiPageReferences[page] ) )
gaiPageReferences[page] = 1;
}
if( PAddr >> 12 > giMaxPhysPage ) return ;
- if( MM_GetPhysAddr( (tVAddr) &gaiPageReferences[page] ) )
+ if( MM_GetPhysAddr( &gaiPageReferences[page] ) )
{
gaiPageReferences[ page ] --;
if( gaiPageReferences[ page ] == 0 )
if( PAddr > giMaxPhysPage ) return 0;
- if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
+ if( MM_GetPhysAddr( &gaiPageReferences[PAddr] ) ) {
return gaiPageReferences[PAddr];
}
// if( !MM_GetRefCount(PAddr) ) return 1;
- if( !MM_GetPhysAddr(node_page) ) {
+ if( !MM_GetPhysAddr((void*)node_page) ) {
if( !MM_Allocate(node_page) )
return -1;
memset( (void*)node_page, 0, PAGE_SIZE );
// if( !MM_GetRefCount(PAddr) ) return 1;
PAddr >>= 12;
- if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
+ if( !MM_GetPhysAddr( &gapPageNodes[PAddr] ) ) {
*Node = NULL;
return 0;
}
ASSERT(paddr != curpage);
- tmp = (void*)MM_MapTemp(paddr);
+ tmp = MM_MapTemp(paddr);
memcpy( tmp, NextLevel, 0x1000 );
- MM_FreeTemp( (tVAddr)tmp );
+ MM_FreeTemp( tmp );
#if TRACE_COW
Log_Debug("MMVirt", "COW ent at %p (%p) from %P to %P", Ent, NextLevel, curpage, paddr);
#define CANOICAL(addr) ((addr)&0x800000000000?(addr)|0xFFFF000000000000:(addr))
LogF("%016llx => ", CANOICAL(RangeStart));
// LogF("%6llx %6llx %6llx %016llx => ",
-// MM_GetPhysAddr( (tVAddr)&PAGEDIRPTR(RangeStart>>30) ),
-// MM_GetPhysAddr( (tVAddr)&PAGEDIR(RangeStart>>21) ),
-// MM_GetPhysAddr( (tVAddr)&PAGETABLE(RangeStart>>12) ),
+// MM_GetPhysAddr( &PAGEDIRPTR(RangeStart>>30) ),
+// MM_GetPhysAddr( &PAGEDIR(RangeStart>>21) ),
+// MM_GetPhysAddr( &PAGETABLE(RangeStart>>12) ),
// CANOICAL(RangeStart)
// );
if( gMM_ZeroPage && (PAGETABLE(RangeStart>>12) & PADDR_MASK) == gMM_ZeroPage )
expected |= expected_pml4 & PF_NX;
expected |= expected_pdp & PF_NX;
expected |= expected_pd & PF_NX;
- Log("expected (pml4 = %x, pdp = %x, pd = %x)",
- expected_pml4, expected_pdp, expected_pd);
+// Log("expected (pml4 = %x, pdp = %x, pd = %x)",
+// expected_pml4, expected_pdp, expected_pd);
// Dump
MM_int_DumpTablesEnt( rangeStart, curPos - rangeStart, expected );
expected = CHANGEABLE_BITS;
{
tPAddr phys;
- phys = MM_GetPhysAddr(VAddr);
+ phys = MM_GetPhysAddr( (void*)VAddr );
if(!phys) return ;
MM_Unmap(VAddr);
/**
* \brief Get the physical address of a virtual location
*/
-tPAddr MM_GetPhysAddr(tVAddr Addr)
+tPAddr MM_GetPhysAddr(const void *Ptr)
{
+ tVAddr Addr = (tVAddr)Ptr;
tPAddr *ptr;
int ret;
{
for( num = Number; num -- && ret < MM_HWMAP_TOP; ret += 0x1000 )
{
- if( MM_GetPhysAddr(ret) != 0 ) break;
+ if( MM_GetPhysAddr( (void*)ret ) != 0 )
+ break;
}
if( num >= 0 ) continue;
// Log_KernelPanic("MM", "TODO: Implement MM_UnmapHWPages");
while( Number -- )
{
- MM_DerefPhys( MM_GetPhysAddr(VAddr) );
+ MM_DerefPhys( MM_GetPhysAddr((void*)VAddr) );
MM_Unmap(VAddr);
VAddr += 0x1000;
}
}
// --- Tempory Mappings ---
-tVAddr MM_MapTemp(tPAddr PAddr)
+void *MM_MapTemp(tPAddr PAddr)
{
const int max_slots = (MM_TMPMAP_END - MM_TMPMAP_BASE) / PAGE_SIZE;
tVAddr ret = MM_TMPMAP_BASE;
*ent = PAddr | 3;
MM_RefPhys(PAddr);
INVLPG(ret);
- return ret;
+ return (void*)ret;
}
return 0;
}
-void MM_FreeTemp(tVAddr VAddr)
+void MM_FreeTemp(void *Ptr)
{
- MM_Deallocate(VAddr);
+ MM_Deallocate((tVAddr)Ptr);
return ;
}
for( i = 1; i < KERNEL_STACK_SIZE/0x1000; i ++ )
{
tPAddr phys = MM_AllocPhys();
- tVAddr tmpmapping;
+ void *tmpmapping;
MM_MapEx(kstackbase+i*0x1000, phys, 1, 0);
tmpmapping = MM_MapTemp(phys);
- if( MM_GetPhysAddr( kstackbase+i*0x1000 ) )
- memcpy((void*)tmpmapping, (void*)(kstackbase+i*0x1000), 0x1000);
+ if( MM_GetPhysAddr( (void*)(kstackbase+i*0x1000) ) )
+ memcpy(tmpmapping, (void*)(kstackbase+i*0x1000), 0x1000);
else
- memset((void*)tmpmapping, 0, 0x1000);
+ memset(tmpmapping, 0, 0x1000);
// if( i == 0xF )
// Debug_HexDump("MM_Clone: *tmpmapping = ", (void*)tmpmapping, 0x1000);
MM_FreeTemp(tmpmapping);
Log_Error("MM", "MM_NewWorkerStack: StackSize(0x%x) > 0x1000, cbf handling", StackSize);
}
else {
- tVAddr tmp_addr, dest;
+ void *tmp_addr, *dest;
tmp_addr = MM_MapTemp(phys);
- dest = tmp_addr + (0x1000 - StackSize);
- memcpy( (void*)dest, StackData, StackSize );
- Log_Debug("MM", "MM_NewWorkerStack: %p->%p %i bytes (i=%i)", StackData, dest, StackSize, i);
- Log_Debug("MM", "MM_NewWorkerStack: ret = %p", ret);
+ dest = (char*)tmp_addr + (0x1000 - StackSize);
+ memcpy( dest, StackData, StackSize );
MM_FreeTemp(tmp_addr);
}
Uint i;
for( ; base < MM_KSTACK_TOP; base += KERNEL_STACK_SIZE )
{
- if(MM_GetPhysAddr(base+KERNEL_STACK_SIZE-0x1000) != 0)
+ if(MM_GetPhysAddr( (void*)(base+KERNEL_STACK_SIZE-0x1000) ) != 0)
continue;
//Log("MM_NewKStack: Found one at %p", base + KERNEL_STACK_SIZE);
tAPIC *gpMP_LocalAPIC = NULL;
Uint8 gaAPIC_to_CPU[256] = {0};
#endif
-tCPU gaCPUs[MAX_CPUS];
+tCPU gaCPUs[MAX_CPUS] = {
+ {.Current = &gThreadZero}
+ };
tTSS *gTSSs = NULL;
tTSS gTSS0 = {0};
// --- Error Recovery ---
* \fn int Proc_SpawnWorker(void)
* \brief Spawns a new worker thread
*/
-int Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
+tThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data)
{
tThread *new, *cur;
Uint stack_contents[3];
new = Threads_CloneThreadZero();
if(!new) {
Warning("Proc_SpawnWorker - Out of heap space!\n");
- return -1;
+ return NULL;
}
// Create the stack contents
new->Status = THREAD_STAT_PREINIT;
Threads_AddActive( new );
- return new->TID;
+ return new;
}
/**
// Check Prospective Space
for( i = USER_STACK_SZ >> 12; i--; )
{
- if( MM_GetPhysAddr( base + (i<<12) ) != 0 )
+ if( MM_GetPhysAddr( (void*)(base + (i<<12)) ) != 0 )
break;
}
[section .rodata]
csNot64BitCapable:
- db "Not 64-bit Capable",0
+ db "CPU does not support long-mode, please use the x86 build",0
; vim: ft=nasm
--- /dev/null
+/*
+ * Acess2 Kernel x86 Port
+ * - By John Hodge (thePowersGang)
+ *
+ * vpci.c
+ * - Virtual PCI Bus
+ */
+#include <virtual_pci.h>
+
+// === GLOBALS ===
+ int giVPCI_DeviceCount = 0;
+tVPCI_Device gaVPCI_Devices[0];
+
#include <binary.h>\r
\r
#define _COMMON_H\r
-#define SysDebug(...) LOG(v)\r
-#define DISABLE_ELF64\r
+#define SysDebug(v...) LOG(v)\r
+#if BITS <= 32\r
+# define DISABLE_ELF64\r
+#endif\r
void *GetSymbol(const char *Name, size_t *Size);\r
void *GetSymbol(const char *Name, size_t *Size) { Uint val; Binary_GetSymbol(Name, &val); if(Size)*Size=0; return (void*)val; };\r
#define AddLoaded(a,b) do{}while(0)\r
-#define LoadLibrary(a,b,c) 0\r
-#if __STDC_HOSTED__\r
-#warning "Hosted? why!"\r
-#else\r
-#warning "freestanding - outstanding!"\r
-#endif\r
-\r
+#define LoadLibrary(a,b,c) (Log_Debug("ELF", "Module requested lib '%s'",a),0)\r
#include "../../../Usermode/Libraries/ld-acess.so_src/elf.c"\r
\r
#define DEBUG_WARN 1\r
switch(hdr.e_ident[4]) // EI_CLASS\r
{\r
case ELFCLASS32:\r
- return Elf_Load32(fp, (Elf32_Ehdr*)&hdr);\r
+ return Elf_Load32(fp, (void*)&hdr);\r
case ELFCLASS64:\r
return Elf_Load64(fp, &hdr);\r
default:\r
\r
int Elf_Relocate(void *Base)\r
{\r
- return ElfRelocate(Base, (char**){NULL}, "") != NULL;\r
+ return ElfRelocate(Base, (char**){NULL}, "") != NULL;\r
}\r
int Elf_GetSymbol(void *Base, const char *Name, Uint *ret)\r
{\r
pKBinary->Next = glLoadedKernelLibs;
glLoadedKernelLibs = pKBinary;
SHORTREL( &glKBinListLock );
-
- // Relocate Library
- if( !Binary_Relocate( (void*)base ) )
- {
- Log_Warning("Binary", "Relocation of '%s' failed, unloading", File);
- Binary_Unload( (void*)base );
- Binary_Dereference( pBinary );
- LEAVE('n');
- return 0;
- }
-
+
LEAVE('p', base);
return (void*)base;
}
tKernelBin *pKBin;
int numKSyms = ((Uint)&gKernelSymbolsEnd-(Uint)&gKernelSymbols)/sizeof(tKernelSymbol);
+ LOG("numKSyms = %i", numKSyms);
+
// Scan Kernel
for( i = 0; i < numKSyms; i++ )
{
+ LOG("KSym %s = %p", gKernelSymbols[i].Name, gKernelSymbols[i].Value);
if(strcmp(Name, gKernelSymbols[i].Name) == 0) {
*Value = gKernelSymbols[i].Value;
return 1;
_start &= ~(PAGE_SIZE-1);
LOG("_start = %p, _len = 0x%x", _start, _len);
for( ; _len > PAGE_SIZE; _len -= PAGE_SIZE, _start += PAGE_SIZE ) {
- if( MM_GetPhysAddr(_start) != 0 ) {
+ if( MM_GetPhysAddr( (void*)_start ) != 0 ) {
LEAVE('i', 1);
return 1;
}
}
- if( _len == PAGE_SIZE && MM_GetPhysAddr(_start) != 0 ) {
+ if( _len == PAGE_SIZE && MM_GetPhysAddr( (void*)_start ) != 0 ) {
LEAVE('i', 1);
return 1;
}
extern void Threads_Dump(void);
extern void KernelPanic_SetMode(void);
extern void KernelPanic_PutChar(char Ch);
+extern void IPStack_SendDebugText(const char *Text);
// === PROTOTYPES ===
static void Debug_Putchar(char ch);
#if LOCK_DEBUG_OUTPUT
tShortSpinlock glDebug_Lock;
#endif
+// - Disabled because it breaks shit
+ int gbSendNetworkDebug = 0;
// === CODE ===
static void Debug_Putchar(char ch)
{
Debug_PutCharDebug(ch);
+
if( !gbDebug_IsKPanic )
{
if(gbInPutChar) return ;
}
else
KernelPanic_PutChar(ch);
+
+ if( gbSendNetworkDebug )
+ {
+ char str[2] = {ch, 0};
+ IPStack_SendDebugText(str);
+ }
}
static void Debug_Puts(int UseKTerm, const char *Str)
}
else
for( len = 0; Str[len]; len ++ );
-
+
+ if( gbSendNetworkDebug )
+ IPStack_SendDebugText(Str);
+
// Output to the kernel terminal
if( UseKTerm && !gbDebug_IsKPanic && giDebug_KTerm != -1)
{
void Debug_Fmt(int bUseKTerm, const char *format, va_list args)
{
char buf[DEBUG_MAX_LINE_LEN];
- int len;
+// int len;
buf[DEBUG_MAX_LINE_LEN-1] = 0;
- len = vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
+ /*len = */vsnprintf(buf, DEBUG_MAX_LINE_LEN-1, format, args);
//if( len < DEBUG_MAX_LINE )
// do something
Debug_Puts(bUseKTerm, buf);
Debug_Putchar('\n');
Threads_Dump();
+ Heap_Dump();
for(;;) ;
}
// === PROTOTYPES ===
int FIFO_Install(char **Arguments);
int FIFO_IOCtl(tVFS_Node *Node, int Id, void *Data);
-char *FIFO_ReadDir(tVFS_Node *Node, int Id);
+ int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
tVFS_Node *FIFO_FindDir(tVFS_Node *Node, const char *Filename);
- int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
void FIFO_Reference(tVFS_Node *Node);
void FIFO_Close(tVFS_Node *Node);
- int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+ int FIFO_Unlink(tVFS_Node *Node, const char *OldName);
size_t FIFO_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
size_t FIFO_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
tPipe *FIFO_Int_NewPipe(int Size, const char *Name);
.ReadDir = FIFO_ReadDir,
.FindDir = FIFO_FindDir,
.MkNod = FIFO_MkNod,
- .Relink = FIFO_Relink,
+ .Unlink = FIFO_Unlink,
.IOCtl = FIFO_IOCtl
};
tVFS_NodeType gFIFO_PipeNodeType = {
* \fn char *FIFO_ReadDir(tVFS_Node *Node, int Id)
* \brief Reads from the FIFO root
*/
-char *FIFO_ReadDir(tVFS_Node *Node, int Id)
+int FIFO_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX])
{
tPipe *tmp = gFIFO_NamedPipes;
// Entry 0 is Anon Pipes
- if(Id == 0) return strdup("anon");
+ if(Id == 0) {
+ strcpy(Dest, "anon");
+ return 0;
+ }
// Find the id'th node
while(--Id && tmp) tmp = tmp->Next;
- // If node found, return it
- if(tmp) return strdup(tmp->Name);
- // else error return
- return NULL;
+ // If the list ended, error return
+ if(!tmp)
+ return -EINVAL;
+ // Return good
+ strncpy(Dest, tmp->Name, FILENAME_MAX);
+ return 0;
}
/**
/**
* \fn int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
*/
-int FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+tVFS_Node *FIFO_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
{
return 0;
}
}
/**
- * \fn int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
- * \brief Relink a file (Deletes named pipes)
+ * \brief Delete a pipe
*/
-int FIFO_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+int FIFO_Unlink(tVFS_Node *Node, const char *OldName)
{
- tPipe *pipe, *tmp;
+ tPipe *pipe;
if(Node != &gFIFO_DriverInfo.RootNode) return 0;
}
if(!pipe) return 0;
- // Relink a named pipe
- if(NewName) {
- // Check new name
- for(tmp = gFIFO_NamedPipes;
- tmp;
- tmp = tmp->Next)
- {
- if(strcmp(tmp->Name, NewName) == 0) return 0;
- }
- // Create new name
- free(pipe->Name);
- pipe->Name = malloc(strlen(NewName)+1);
- strcpy(pipe->Name, NewName);
- return 1;
- }
-
// Unlink the pipe
if(Node->ImplPtr) {
free(Node->ImplPtr);
/*\r
- * AcessOS/AcessBasic v0.1\r
- * PCI Bus Driver\r
+ * Acess2 Kernel\r
+ * - By John Hodge (thePowersGang)\r
+ * \r
+ * drv/pci.c\r
+ * - PCI Enumeration and Arbitration\r
*/\r
#define DEBUG 0\r
#include <acess.h>\r
#include <fs_devfs.h>\r
#include <drv_pci.h>\r
#include <drv_pci_int.h>\r
+#include <virtual_pci.h>\r
\r
+#define USE_PORT_BITMAP 0\r
#define LIST_DEVICES 1\r
+#define PCI_MAX_BUSSES 8\r
\r
// === STRUCTURES ===\r
typedef struct sPCIDevice\r
int PCI_Install(char **Arguments);\r
int PCI_ScanBus(int ID, int bFill);\r
\r
-char *PCI_int_ReadDirRoot(tVFS_Node *node, int pos);\r
+ int PCI_int_ReadDirRoot(tVFS_Node *node, int pos, char Dest[FILENAME_MAX]);\r
tVFS_Node *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename);\r
Uint32 PCI_int_GetBusAddr(Uint16 Bus, Uint16 Slot, Uint16 Fcn, Uint8 Offset);\r
size_t PCI_int_ReadDevice(tVFS_Node *node, off_t Offset, size_t Length, void *buffer);\r
// === GLOBALS ===\r
MODULE_DEFINE(0, 0x0100, PCI, PCI_Install, NULL, NULL);\r
int giPCI_BusCount = 1;\r
+Uint8 gaPCI_BusNumbers[PCI_MAX_BUSSES];\r
int giPCI_InodeHandle = -1;\r
int giPCI_DeviceCount = 0;\r
tPCIDevice *gPCI_Devices = NULL;\r
.Type = &gPCI_RootNodeType\r
}\r
};\r
+#if USE_PORT_BITMAP\r
Uint32 *gaPCI_PortBitmap = NULL;\r
+#endif\r
Uint32 gaPCI_BusBitmap[256/32];\r
\r
// === CODE ===\r
*/\r
int PCI_Install(char **Arguments)\r
{\r
- int i, ret, bus;\r
+ int ret, bus;\r
void *tmpPtr;\r
\r
+ #if USE_PORT_BITMAP\r
// Build Portmap\r
gaPCI_PortBitmap = malloc( 1 << 13 );\r
if( !gaPCI_PortBitmap ) {\r
return MODULE_ERR_MALLOC;\r
}\r
memset( gaPCI_PortBitmap, 0, 1 << 13 );\r
+ int i;\r
for( i = 0; i < MAX_RESERVED_PORT / 32; i ++ )\r
gaPCI_PortBitmap[i] = -1;\r
for( i = 0; i < MAX_RESERVED_PORT % 32; i ++ )\r
gaPCI_PortBitmap[MAX_RESERVED_PORT / 32] = 1 << i;\r
- \r
+ #endif \r
+\r
// Scan Bus (Bus 0, Don't fill gPCI_Devices)\r
+ giPCI_DeviceCount = 0;\r
+ giPCI_BusCount = 1;\r
+ gaPCI_BusNumbers[0] = 0;\r
for( bus = 0; bus < giPCI_BusCount; bus ++ )\r
{\r
- ret = PCI_ScanBus(bus, 0);\r
- if(ret != MODULE_ERR_OK) return i;\r
+ ret = PCI_ScanBus(gaPCI_BusNumbers[bus], 0);\r
+ if(ret != MODULE_ERR_OK) return ret;\r
}\r
- \r
+ // TODO: PCIe\r
+ // - Add VPCI Devices\r
+ giPCI_DeviceCount += giVPCI_DeviceCount;\r
+ \r
if(giPCI_DeviceCount == 0) {\r
Log_Notice("PCI", "No devices were found");\r
return MODULE_ERR_NOTNEEDED;\r
// Rescan, filling the PCI device array\r
for( bus = 0; bus < giPCI_BusCount; bus ++ )\r
{\r
- PCI_ScanBus(bus, 1);\r
+ PCI_ScanBus(gaPCI_BusNumbers[bus], 1);\r
+ }\r
+ // Insert VPCI Devices\r
+ for( int i = 0; i < giVPCI_DeviceCount; i ++ )\r
+ {\r
+ tPCIDevice *devinfo = &gPCI_Devices[giPCI_DeviceCount];\r
+ \r
+ devinfo->bus = -1;\r
+ devinfo->slot = i;\r
+ devinfo->fcn = 0;\r
+ devinfo->vendor = gaVPCI_Devices[i].Vendor;\r
+ devinfo->device = gaVPCI_Devices[i].Device;\r
+ devinfo->revision = gaVPCI_Devices[i].Class & 0xFF;\r
+ devinfo->class = gaVPCI_Devices[i].Class >> 8;\r
+ snprintf(devinfo->Name, sizeof(devinfo->Name), "%02x.%02x:%x", 0xFF, i, 0);\r
+\r
+ for(int j = 0; j < 256/4; j ++ )\r
+ devinfo->ConfigCache[i] = VPCI_Read(&gaVPCI_Devices[i], j*4, 4);\r
+\r
+ memset(&devinfo->Node, 0, sizeof(devinfo->Node));\r
+ devinfo->Node.Inode = giPCI_DeviceCount;\r
+ devinfo->Node.Size = 256;\r
+ devinfo->Node.NumACLs = 1;\r
+ devinfo->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
+ devinfo->Node.Type = &gPCI_DevNodeType;\r
+\r
+ giPCI_DeviceCount ++;\r
}\r
\r
// Complete Driver Structure\r
if(!PCI_int_EnumDevice(BusID, dev, fcn, &devInfo))\r
continue;\r
\r
- if(devInfo.class == PCI_OC_PCIBRIDGE)\r
- {\r
- #if LIST_DEVICES\r
- if( !bFill )\r
- Log_Log("PCI", "Bridge @ %i,%i:%i (0x%x:0x%x)",\r
- BusID, dev, fcn, devInfo.vendor, devInfo.device);\r
- #endif\r
- //TODO: Handle PCI-PCI Bridges\r
- //PCI_ScanBus(devInfo.???, bFill);\r
- giPCI_BusCount ++;\r
- }\r
- else\r
- {\r
- #if LIST_DEVICES\r
- if( !bFill )\r
- Log_Log("PCI", "Device %i,%i:%i %06x => 0x%04x:0x%04x",\r
- BusID, dev, fcn, devInfo.class, devInfo.vendor, devInfo.device);\r
- #endif\r
- }\r
+ #if LIST_DEVICES\r
+ if( !bFill )\r
+ Log_Log("PCI", "Device %i,%i:%i %06x => 0x%04x:0x%04x Rev %i",\r
+ BusID, dev, fcn, devInfo.class,\r
+ devInfo.vendor, devInfo.device, devInfo.revision);\r
+ #endif\r
\r
if( bFill ) {\r
devInfo.Node.Inode = giPCI_DeviceCount;\r
}\r
giPCI_DeviceCount ++;\r
\r
- // If bit 23 of (soemthing) is set, there are sub-functions\r
+ switch(devInfo.ConfigCache[3] & 0x007F0000)\r
+ {\r
+ case 0x00: // Normal device\r
+ break;\r
+ case 0x01: // PCI-PCI Bridge\r
+ {\r
+ // TODO: Add to list of busses?\r
+ Uint8 sec = (devInfo.ConfigCache[6] & 0x0000FF00) >> 8;\r
+ #if LIST_DEVICES\r
+ if( !bFill ) {\r
+ Uint8 pri = (devInfo.ConfigCache[6] & 0x000000FF) >> 0;\r
+ Log_Log("PCI", "- PCI-PCI Bridge %02x=>%02x", pri, sec);\r
+ }\r
+ #endif\r
+ gaPCI_BusNumbers[giPCI_BusCount++] = sec;\r
+ }\r
+ break;\r
+ case 0x02: // PCI-CardBus Bridge\r
+ break;\r
+ }\r
+\r
+ // If bit 8 of the Header Type register is set, there are sub-functions\r
if(fcn == 0 && !(devInfo.ConfigCache[3] & 0x00800000) )\r
break;\r
}\r
/**\r
* \brief Read from Root of PCI Driver\r
*/\r
-char *PCI_int_ReadDirRoot(tVFS_Node *Node, int Pos)\r
+int PCI_int_ReadDirRoot(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])\r
{\r
ENTER("pNode iPos", Node, Pos);\r
if(Pos < 0 || Pos >= giPCI_DeviceCount) {\r
- LEAVE('n');\r
- return NULL;\r
+ LEAVE_RET('i', -EINVAL);\r
}\r
\r
- LEAVE('s', gPCI_Devices[Pos].Name);\r
- return strdup( gPCI_Devices[Pos].Name );\r
+ LOG("Name = %s", gPCI_Devices[Pos].Name);\r
+ strncpy(Dest, gPCI_Devices[Pos].Name, FILENAME_MAX);\r
+ LEAVE_RET('i', 0);\r
}\r
/**\r
*/\r
tVFS_Node *PCI_int_FindDirRoot(tVFS_Node *node, const char *filename)\r
{\r
- int bus,slot,fcn;\r
int i;\r
- // Validate Filename (Pointer and length)\r
- if(!filename || strlen(filename) != 7)\r
- return NULL;\r
- // Check for spacers\r
- if(filename[2] != '.' || filename[5] != ':')\r
- return NULL;\r
- \r
- // Get Information\r
- if(filename[0] < '0' || filename[0] > '9') return NULL;\r
- bus = (filename[0] - '0')*10;\r
- if(filename[1] < '0' || filename[1] > '9') return NULL;\r
- bus += filename[1] - '0';\r
- if(filename[3] < '0' || filename[3] > '9') return NULL;\r
- slot = (filename[3] - '0')*10;\r
- if(filename[4] < '0' || filename[4] > '9') return NULL;\r
- slot += filename[4] - '0';\r
- if(filename[6] < '0' || filename[6] > '9') return NULL;\r
- fcn = filename[6] - '0';\r
\r
// Find Match\r
for(i=0;i<giPCI_DeviceCount;i++)\r
{\r
- if(gPCI_Devices[i].bus != bus) continue;\r
- if(gPCI_Devices[i].slot != slot) continue;\r
- if(gPCI_Devices[i].fcn != fcn) continue;\r
- \r
- return &gPCI_Devices[i].Node;\r
+ int cmp = strcmp(gPCI_Devices[i].Name, filename);\r
+ if( cmp > 0 ) // Sorted list\r
+ break;\r
+ if( cmp == 0 )\r
+ return &gPCI_Devices[i].Node;\r
}\r
\r
// Error Return\r
if( Offset & (Size - 1) ) return 0;\r
\r
dev = &gPCI_Devices[ID];\r
+ // Detect VPCI devices\r
+ if( dev->bus == -1 ) {\r
+ return VPCI_Read(&gaVPCI_Devices[dev->slot], Offset, Size);\r
+ }\r
+\r
addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
\r
dword = PCI_CfgReadDWord(addr);\r
tPCIDevice *dev;\r
Uint32 dword, addr;\r
int shift;\r
+\r
if( ID < 0 || ID >= giPCI_DeviceCount ) return ;\r
if( Offset < 0 || Offset > 256 ) return ;\r
- \r
+\r
dev = &gPCI_Devices[ID];\r
+\r
+ // Detect VPCI devices\r
+ if( dev->bus == -1 ) {\r
+ VPCI_Write(&gaVPCI_Devices[dev->slot], Offset, Size, Value);\r
+ return ;\r
+ }\r
+\r
addr = PCI_int_GetBusAddr(dev->bus, dev->slot, dev->fcn, Offset);\r
\r
if(Size != 4)\r
vendor_dev = PCI_CfgReadDWord( addr );\r
if((vendor_dev & 0xFFFF) == 0xFFFF) // Invalid Device\r
return 0;\r
+ \r
+ info->bus = bus;\r
+ info->slot = slot;\r
+ info->fcn = fcn;\r
\r
+ // Read configuration\r
info->ConfigCache[0] = vendor_dev;\r
for( i = 1, addr += 4; i < 256/4; i ++, addr += 4 )\r
{\r
info->ConfigCache[i] = PCI_CfgReadDWord(addr);\r
} \r
\r
- info->bus = bus;\r
- info->slot = slot;\r
- info->fcn = fcn;\r
info->vendor = vendor_dev & 0xFFFF;\r
info->device = vendor_dev >> 16;\r
tmp = info->ConfigCache[2];\r
// #endif\r
\r
// Make node name\r
- info->Name[0] = '0' + bus/10;\r
- info->Name[1] = '0' + bus%10;\r
- info->Name[2] = '.';\r
- info->Name[3] = '0' + slot/10;\r
- info->Name[4] = '0' + slot%10;\r
- info->Name[5] = ':';\r
- info->Name[6] = '0' + fcn;\r
- info->Name[7] = '\0';\r
+ snprintf(info->Name, 8, "%02x.%02x:%x", bus, slot, fcn);\r
\r
// Create VFS Node\r
memset( &info->Node, 0, sizeof(tVFS_Node) );\r
info->Node.NumACLs = 1;\r
info->Node.ACLs = &gVFS_ACL_EveryoneRO;\r
\r
- info->Node.Type = &gPCI_RootNodeType;\r
+ info->Node.Type = &gPCI_DevNodeType;\r
\r
return 1;\r
}\r
int SysFS_RemoveFile(int ID);
#endif
-char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Id);
+ int SysFS_Comm_ReadDir(tVFS_Node *Node, int Id, char Dest[FILENAME_MAX]);
tVFS_Node *SysFS_Comm_FindDir(tVFS_Node *Node, const char *Filename);
size_t SysFS_Comm_ReadFile(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
void SysFS_Comm_CloseFile(tVFS_Node *Node);
*/
int SysFS_Install(char **Options)
{
- {
- const char *fmt = "Acess2 "EXPAND_STR(KERNEL_VERSION)" "EXPAND_STR(ARCHDIR)" build %i, hash %s";
- gSysFS_Version_Kernel.Node.Size = sprintf(NULL, fmt, BUILD_NUM, gsGitHash);
- gSysFS_Version_Kernel.Node.ImplPtr = malloc( gSysFS_Version_Kernel.Node.Size + 1 );
- sprintf(gSysFS_Version_Kernel.Node.ImplPtr, fmt, BUILD_NUM, gsGitHash);
- }
+ gSysFS_Version_Kernel.Node.Size = strlen(gsBuildInfo);
+ gSysFS_Version_Kernel.Node.ImplPtr = (void*)gsBuildInfo;
DevFS_AddDevice( &gSysFS_DriverInfo );
return MODULE_ERR_OK;
for( ent = gSysFS_FileList; ent; ent = ent->Next )
{
// It's a reverse sorted list
- if(ent->Node.Inode < ID) return 0;
- if(ent->Node.Inode == ID)
+ if(ent->Node.Inode < (Uint64)ID)
+ return 0;
+ if(ent->Node.Inode == (Uint64)ID)
{
ent->Node.ImplPtr = (void*)Data;
ent->Node.Size = Length;
tSysFS_Ent *ent, *parent, *prev;
prev = NULL;
- for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->Next )
+ for( ent = gSysFS_FileList; ent; prev = ent, ent = ent->ListNext )
{
// It's a reverse sorted list
- if(ent->Node.Inode < ID) return 0;
- if(ent->Node.Inode == ID) break;
+ if(ent->Node.Inode <= (Uint64)ID) break;
+ }
+ if( !ent || ent->Node.Inode != (Uint64)ID) {
+ Log_Notice("SysFS", "ID %i not present", ID);
+ return 0;
}
-
- if(!ent) return 0;
// Set up for next part
file = ent;
file->Node.Size = 0;
file->Node.ImplPtr = NULL;
- // Search parent directory
- for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
+ // Clean out of parent directory
+ while(parent)
{
- if( ent == file ) break;
- }
- if(!ent) {
- Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
- return 0;
+ for( ent = parent->Node.ImplPtr; ent; prev = ent, ent = ent->Next )
+ {
+ if( ent == file ) break;
+ }
+ if(!ent) {
+ Log_Warning("SysFS", "Bookkeeping Error: File in list, but not in directory");
+ return 0;
+ }
+
+ // Remove from parent directory
+ if(prev)
+ prev->Next = ent->Next;
+ else
+ parent->Node.ImplPtr = ent->Next;
+
+ // Free if not in use
+ if(file->Node.ReferenceCount == 0) {
+ free(file);
+ }
+
+ if( parent->Node.ImplPtr )
+ break;
+
+ // Remove parent from the tree
+ file = parent;
+ parent = parent->Parent;
}
- // Remove from parent directory
- if(prev)
- prev->Next = ent->Next;
- else
- parent->Node.ImplPtr = ent->Next;
-
- // Free if not in use
- if(file->Node.ReferenceCount == 0)
- free(file);
-
return 1;
}
* \fn char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
* \brief Reads from a SysFS directory
*/
-char *SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos)
+int SysFS_Comm_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
tSysFS_Ent *child = (tSysFS_Ent*)Node->ImplPtr;
- if(Pos < 0 || Pos >= Node->Size) return NULL;
+ if(Pos < 0 || (Uint64)Pos >= Node->Size)
+ return -EINVAL;
for( ; child; child = child->Next, Pos-- )
{
- if( Pos == 0 ) return strdup(child->Name);
+ if( Pos == 0 ) {
+ strncpy(Dest, child->Name, FILENAME_MAX);
+ return 0;
+ }
}
- return NULL;
+ return -ENOENT;
}
/**
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/vpci.c
+ * - Virtual PCI Bus
+ */
+#include <virtual_pci.h>
+
+// === CODE ===
+Uint32 VPCI_Read(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size)
+{
+ Uint32 tmp_dword = 0;
+
+ if( Size > 4 || Size == 3 || Size == 0 )
+ return 0;
+ if( Offset & (Size - 1) )
+ return 0;
+
+ switch( Offset >> 2 )
+ {
+ case 0: // Vendor[0:15], Device[16:31]
+ tmp_dword = (Dev->Vendor) | (Dev->Device << 16);
+ break;
+ case 2: // Class Code
+ tmp_dword = Dev->Class;
+ break;
+ // 1: Command[0:15], Status[16:31]
+ // 3: Cache Line Size, Latency Timer, Header Type, BIST
+ // 4-9: BARs
+ // 10: Unused (Cardbus CIS Pointer)
+ // 11: Subsystem Vendor ID, Subsystem ID
+ // 12: Expansion ROM Address
+ // 13: Capabilities[0:8], Reserved[9:31]
+ // 14: Reserved
+ // 15: Interrupt Line, Interrupt Pin, Min Grant, Max Latency
+ default:
+ tmp_dword = Dev->Read(Dev->Ptr, Offset >> 2);
+ break;
+ }
+
+ tmp_dword >>= 8*(Offset & 3);
+ switch(Size)
+ {
+ case 4: break;
+ case 2: tmp_dword &= 0xFFFF; break;
+ case 1: tmp_dword &= 0xFF;
+ }
+
+ return tmp_dword;
+}
+
+void VPCI_Write(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size, Uint32 Data)
+{
+ Uint32 tmp_dword;
+ if( Size > 4 || Size == 3 || Size == 0 )
+ return ;
+ if( Offset & (Size - 1) )
+ return ;
+
+ switch(Offset >> 2)
+ {
+ case 0: // Vendor / Device IDs
+ case 2: // Class Code
+ // READ ONLY
+ return ;
+ }
+
+ tmp_dword = Dev->Read(Dev->Ptr, Offset>>2);
+ switch(Size)
+ {
+ case 4: tmp_dword = 0; break;
+ case 2:
+ tmp_dword &= ~(0xFFFF << ((Offset&2)*16));
+ Data |= 0xFFFF;
+ break;
+ case 1:
+ tmp_dword &= ~(0xFF << ((Offset&3)*8));
+ Data |= 0xFF;
+ break;
+ }
+ tmp_dword |= Data << ((Offset&3)*8);
+ Dev->Write(Dev->Ptr, Offset>>2, tmp_dword);
+}
// === PROTOTYPES ===
int VT_Install(char **Arguments);
-char *VT_ReadDir(tVFS_Node *Node, int Pos);
+ int VT_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *VT_FindDir(tVFS_Node *Node, const char *Name);
int VT_Root_IOCtl(tVFS_Node *Node, int Id, void *Data);
size_t VT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
// Semaphore_Init(&gVT_Terminals[i].InputSemaphore, 0, MAX_INPUT_CHARS8, "VTerm", gVT_Terminals[i].Name);
}
- Log_Debug("VTerm", "Registering with DevFS");
// Add to DevFS
DevFS_AddDevice( &gVT_DrvInfo );
* \fn char *VT_ReadDir(tVFS_Node *Node, int Pos)
* \brief Read from the VTerm Directory
*/
-char *VT_ReadDir(tVFS_Node *Node, int Pos)
+int VT_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
- if(Pos < 0) return NULL;
- if(Pos >= NUM_VTS) return NULL;
- return strdup( gVT_Terminals[Pos].Name );
+ if(Pos < 0) return -EINVAL;
+ if(Pos >= NUM_VTS) return -EINVAL;
+ strncpy(Dest, gVT_Terminals[Pos].Name, FILENAME_MAX);
+ return 0;
}
/**
*/
size_t VT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
{
- int pos = 0;
- int avail;
+ int pos, avail;
tVTerm *term = &gVT_Terminals[ Node->Inode ];
Uint32 *codepoint_buf = Buffer;
Uint32 *codepoint_in;
avail = term->InputWrite - term->InputRead;
if(avail < 0)
avail += MAX_INPUT_CHARS8;
- if(avail > Length - pos)
- avail = Length - pos;
+ if(avail > Length)
+ avail = Length;
+ pos = 0;
while( avail -- )
{
((char*)Buffer)[pos] = term->InputBuffer[term->InputRead];
if(avail < 0)
avail += MAX_INPUT_CHARS32;
Length /= 4;
- if(avail > Length - pos)
- avail = Length - pos;
+ if(avail > Length)
+ avail = Length;
codepoint_in = (void*)term->InputBuffer;
codepoint_buf = Buffer;
+ pos = 0;
while( avail -- )
{
codepoint_buf[pos] = codepoint_in[term->InputRead];
/*
* Taken from http://cvs.savannah.gnu.org/viewvc/vgabios/vgafonts.h?root=vgabios&view=markup
+ * Font is public domain
* Altered for Acess2
*/
#define FONT_WIDTH 8
}
// Debug
+ #if 0
switch(NewMode)
{
case TERM_MODE_TEXT:
//case TERM_MODE_3DACCEL:
// return;
}
+ #endif
}
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * drv/zero-one.c
+ * - /Devices/{null,zero,one}
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+
+// === PROTOTYPES ===
+ int CoreDevs_Install(char **Arguments);
+size_t CoreDevs_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
+size_t CoreDevs_Read_Zero(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+size_t CoreDevs_Read_One (tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+size_t CoreDevs_Read_Null(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, 0x0100, CoreDevs, CoreDevs_Install, NULL, NULL);
+tVFS_NodeType gCoreDevs_NT_Null = {
+ .TypeName = "CoreDevs-null",
+ .Read = CoreDevs_Read_Null,
+ .Write = CoreDevs_Write
+};
+tVFS_NodeType gCoreDevs_NT_Zero = {
+ .TypeName = "CoreDevs-zero",
+ .Read = CoreDevs_Read_Zero,
+ .Write = CoreDevs_Write
+};
+tVFS_NodeType gCoreDevs_NT_One = {
+ .TypeName = "CoreDevs-one",
+ .Read = CoreDevs_Read_One,
+ .Write = CoreDevs_Write
+};
+tDevFS_Driver gCoreDevs_Null = {
+ NULL, "null",
+ {
+ .Size = 0,
+ .NumACLs = 1,
+ .ACLs = &gVFS_ACL_EveryoneRW,
+ .Type = &gCoreDevs_NT_Null
+ }
+};
+tDevFS_Driver gCoreDevs_Zero = {
+ NULL, "zero",
+ {
+ .Size = 0,
+ .NumACLs = 1,
+ .ACLs = &gVFS_ACL_EveryoneRW,
+ .Type = &gCoreDevs_NT_Zero
+ }
+};
+tDevFS_Driver gCoreDevs_One = {
+ NULL, "one",
+ {
+ .Size = 0,
+ .NumACLs = 1,
+ .ACLs = &gVFS_ACL_EveryoneRW,
+ .Type = &gCoreDevs_NT_One
+ }
+};
+
+// === CODE ===
+/**
+ * \brief Installs the CoreDevs driver
+ */
+int CoreDevs_Install(char **Options)
+{
+ DevFS_AddDevice( &gCoreDevs_Null );
+ DevFS_AddDevice( &gCoreDevs_Zero );
+ DevFS_AddDevice( &gCoreDevs_One );
+ return MODULE_ERR_OK;
+}
+
+size_t CoreDevs_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
+{
+ return Length; // Ignore
+}
+
+size_t CoreDevs_Read_Zero(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+ memset(Buffer, 0, Length);
+ return Length;
+}
+
+size_t CoreDevs_Read_One (tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+ Uint8 *ptr = Buffer;
+ size_t rem;
+ for( rem = Length; rem --; ptr ++ )
+ *ptr = 0xFF;
+ return Length;
+}
+
+size_t CoreDevs_Read_Null(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+ return 0;
+}
+
+++ /dev/null
-/*
- * Acess2 Kernel
- * - By John Hodge
- *
- * drvutil.c
- * - Common Driver/Filesystem Helper Functions
- */
-#define DEBUG 0
-#include <acess.h>
-#include <api_drv_disk.h>
-#include <api_drv_video.h>
-
-// === TYPES ===
-
-// === PROTOTYPES ===
-//int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
-//size_t DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
-//void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
-//void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
-void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
-//void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
-void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
-void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
-
-// === GLOBALS ===
-tDrvUtil_Video_2DHandlers gDrvUtil_Stub_2DFunctions = {
- NULL,
- DrvUtil_Video_2D_Fill,
- DrvUtil_Video_2D_Blit
-};
-tVideo_IOCtl_Bitmap gDrvUtil_TextModeCursor = {
- 8, 16,
- 0, 0,
- {
- 0, 0, 0 , 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
- 0, 0, 0 , 0, 0, 0, 0, 0,
- 0, 0, 0 , 0, 0, 0, 0, 0
- }
-};
-
-// === CODE ===
-// --- Video Driver Helpers ---
-int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
- tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
-{
- const Uint8 *stream = Buffer;
- int rem = Length;
- int op;
- while( rem )
- {
- rem --;
- op = *stream;
- stream ++;
-
- if(op > NUM_VIDEO_2DOPS) {
- Log_Warning("DrvUtil",
- "DrvUtil_Video_2DStream: Unknown operation %i",
- op);
- return Length-rem;
- }
-
- if(op*sizeof(void*) > SizeofHandlers) {
- Log_Warning("DrvUtil",
- "DrvUtil_Video_2DStream: Driver does not support op %i",
- op);
- return Length-rem;
- }
-
- switch(op)
- {
- case VIDEO_2DOP_NOP: break;
-
- case VIDEO_2DOP_FILL:
- if(rem < 10) return Length-rem;
-
- if(!Handlers->Fill) {
- Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
- " does not support VIDEO_2DOP_FILL");
- return Length-rem;
- }
-
- Handlers->Fill(
- Ent,
- ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
- ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
- ((const Uint32*)stream)[4]
- );
-
- rem -= 10;
- stream += 10;
- break;
-
- case VIDEO_2DOP_BLIT:
- if(rem < 12) return Length-rem;
-
- if(!Handlers->Blit) {
- Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
- " does not support VIDEO_2DOP_BLIT");
- return Length-rem;
- }
-
- Handlers->Blit(
- Ent,
- ((const Uint16*)stream)[0], ((const Uint16*)stream)[1],
- ((const Uint16*)stream)[2], ((const Uint16*)stream)[3],
- ((const Uint16*)stream)[4], ((const Uint16*)stream)[5]
- );
-
- rem -= 12;
- stream += 12;
- break;
-
- }
- }
- return 0;
-}
-
-int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
-{
- Uint8 *dest;
- const Uint32 *src = Buffer;
- int csr_x, csr_y;
- int x, y;
- int bytes_per_px = (FBInfo->Depth + 7) / 8;
- ENTER("pFBInfo xOffset xLength pBuffer",
- FBInfo, Offset, Length, Buffer);
-
- csr_x = FBInfo->CursorX;
- csr_y = FBInfo->CursorY;
-
- DrvUtil_Video_RemoveCursor(FBInfo);
-
- switch( FBInfo->BufferFormat )
- {
- case VIDEO_BUFFMT_TEXT:
- {
- const tVT_Char *chars = Buffer;
- int widthInChars = FBInfo->Width/giVT_CharWidth;
- int heightInChars = FBInfo->Height/giVT_CharHeight;
- int i;
-
- LOG("bytes_per_px = %i", bytes_per_px);
- LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
-
- Length /= sizeof(tVT_Char); Offset /= sizeof(tVT_Char);
-
- x = Offset % widthInChars; y = Offset / widthInChars;
- LOG("x = %i, y = %i", x, y);
-
- // Sanity Check
- if(Offset > heightInChars * widthInChars) LEAVE_RET('i', 0);
- if(y >= heightInChars) LEAVE_RET('i', 0);
-
- if( Offset + Length > heightInChars*widthInChars )
- {
- Length = heightInChars*widthInChars - Offset;
- }
-
- dest = FBInfo->Framebuffer;
- LOG("dest = %p", dest);
- dest += y * giVT_CharHeight * FBInfo->Pitch;
- LOG("dest = %p", dest);
-
- for( i = 0; i < Length; i++ )
- {
- if( y >= heightInChars )
- {
- Log_Notice("DrvUtil", "Stopped at %i", i);
- break;
- }
-
- VT_Font_Render(
- chars->Ch,
- dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
- VT_Colour12toN(chars->BGCol, FBInfo->Depth),
- VT_Colour12toN(chars->FGCol, FBInfo->Depth)
- );
-
- chars ++;
- x ++;
- if( x >= widthInChars )
- {
- x = 0;
- y ++;
- dest += FBInfo->Pitch*giVT_CharHeight;
- LOG("dest = %p", dest);
- }
- }
- Length = i * sizeof(tVT_Char);
- }
- break;
-
- case VIDEO_BUFFMT_FRAMEBUFFER:
- if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
- {
- Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
- return 0;
- }
-
- switch(FBInfo->Depth)
- {
- case 15:
- case 16:
- Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
- break;
- case 24:
- x = Offset % FBInfo->Width;
- y = Offset / FBInfo->Width;
- dest = (Uint8*)FBInfo->Framebuffer + y*FBInfo->Pitch;
- for( ; Length >= 4; Length -= 4 )
- {
- dest[x*3+0] = *src & 0xFF;
- dest[x*3+1] = (*src >> 8) & 0xFF;
- dest[x*3+2] = (*src >> 16) & 0xFF;
- x ++;
- if(x == FBInfo->Width) {
- dest += FBInfo->Pitch;
- x = 0;
- }
- }
- break;
- case 32:
- // Copy to Frambuffer
- if( FBInfo->Pitch != FBInfo->Width*4 )
- {
- Uint32 *px;
- // Pitch isn't 4*Width
- x = Offset % FBInfo->Width;
- y = Offset / FBInfo->Height;
-
- px = (Uint32*)FBInfo->Framebuffer + y*FBInfo->Pitch/4;
-
- for( ; Length >= 4; Length -= 4, x )
- {
- px[x++] = *src ++;
- if( x == FBInfo->Width ) {
- x = 0;
- px += FBInfo->Pitch;
- }
- }
- }
- else
- {
- dest = (Uint8 *)FBInfo->Framebuffer + Offset;
- memcpy(dest, Buffer, Length);
- }
- break;
- default:
- Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depthn %i", FBInfo->Depth);
- break;
- }
- break;
-
- case VIDEO_BUFFMT_2DSTREAM:
- Length = DrvUtil_Video_2DStream(
- FBInfo, Buffer, Length,
- &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
- );
- break;
-
- default:
- LEAVE('i', -1);
- return -1;
- }
-
- DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
-
- LEAVE('x', Length);
- return Length;
-}
-
-int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
-{
- int csrX = Buf->CursorX, csrY = Buf->CursorY;
- size_t size;
-
- ENTER("pBuf pBitmap", Buf, Bitmap);
-
- // Clear old bitmap
- if( Buf->CursorBitmap )
- {
- LOG("Clearing old cursor");
- DrvUtil_Video_RemoveCursor(Buf);
- if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
- {
- free( Buf->CursorSaveBuf );
- Buf->CursorSaveBuf = NULL;
- }
- if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
- free(Buf->CursorBitmap);
- Buf->CursorBitmap = NULL;
- }
-
- // If the new bitmap is null, disable drawing
- if( !Bitmap )
- {
- Buf->CursorX = -1;
- Buf->CursorY = -1;
- LEAVE('i', 0);
- return 0;
- }
-
- // Sanity check the bitmap
- LOG("Sanity checking plox");
- if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
- {
- Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
- errno = -EINVAL;
- LEAVE('i', -1);
- return -1;
- }
-
- // Don't take a copy of the DrvUtil provided cursor
- if( Bitmap == &gDrvUtil_TextModeCursor )
- {
- LOG("No copy (provided cursor)");
- Buf->CursorBitmap = Bitmap;
- }
- else
- {
- LOG("Make copy");
- size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
-
- // Take a copy
- Buf->CursorBitmap = malloc( size );
- memcpy(Buf->CursorBitmap, Bitmap, size);
- }
-
- // Restore cursor position
- LOG("Drawing");
- DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
- LEAVE('i', 0);
- return 0;
-}
-
-void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
-{
- int render_ox=0, render_oy=0, render_w, render_h;
-
- ENTER("pBuf iX iY", Buf, X, Y);
- DrvUtil_Video_RemoveCursor(Buf);
-
- // X < 0 disables the cursor
- if( X < 0 ) {
- Buf->CursorX = -1;
- LEAVE('-');
- return ;
- }
-
- // Sanity checking
- if( X < 0 || Y < 0 || X >= Buf->Width || Y >= Buf->Height ) {
- LEAVE('-');
- return ;
- }
-
- // Ensure the cursor is enabled
- if( !Buf->CursorBitmap ) {
- LEAVE('-');
- return ;
- }
-
- // Save cursor position (for changing the bitmap)
- Buf->CursorX = X; Buf->CursorY = Y;
- // Apply cursor's center offset
- X -= Buf->CursorBitmap->XOfs;
- Y -= Buf->CursorBitmap->YOfs;
-
- // Get the width of the cursor on screen (clipping to right/bottom edges)
- render_w = X > Buf->Width - Buf->CursorBitmap->W ? Buf->Width - X : Buf->CursorBitmap->W;
- render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
-
- // Clipp to left/top edges
- if(X < 0) { render_ox = -X; X = 0; }
- if(Y < 0) { render_oy = -Y; Y = 0; }
-
- // Save values
- Buf->CursorRenderW = render_w; Buf->CursorRenderH = render_h;
- Buf->CursorDestX = X; Buf->CursorDestY = Y;
- Buf->CursorReadX = render_ox; Buf->CursorReadY = render_oy;
-
- LOG("%ix%i at %i,%i offset %i,%i",
- render_w, render_h, X, Y, render_ox, render_oy);
-
- // Call render routine
- DrvUtil_Video_RenderCursor(Buf);
- LEAVE('-');
-}
-
-void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
-{
- int src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
- int render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
- int dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
- int bytes_per_px = (Buf->Depth + 7) / 8;
- int save_pitch = Buf->CursorBitmap->W * bytes_per_px;
- void *dest;
- Uint32 *src;
- int x, y;
-
- dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
- src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
-
- LOG("dest = %p, src = %p", dest, src);
-
- // Allocate save buffer if not already
- if( !Buf->CursorSaveBuf )
- Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
-
- LOG("Saving back");
- // Save behind the cursor
- for( y = 0; y < render_h; y ++ )
- memcpy(
- (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
- (Uint8*)dest + y*Buf->Pitch,
- render_w*bytes_per_px
- );
-
- // Draw the cursor
- switch(Buf->Depth)
- {
- case 15:
- case 16:
- Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
- break;
- case 24:
- LOG("24-bit render");
- for( y = 0; y < render_h; y ++ )
- {
- Uint8 *px;
- px = dest;
- for(x = 0; x < render_w; x ++, px += 3)
- {
- Uint32 value = src[x];
- // TODO: Should I implement alpha blending?
- if(value & 0xFF000000)
- {
- px[0] = value & 0xFF;
- px[1] = (value >> 8) & 0xFF;
- px[2] = (value >> 16) & 0xFF;
- }
- else
- ;
- }
- src += Buf->CursorBitmap->W;
- dest = (Uint8*)dest + Buf->Pitch;
- }
- break;
- case 32:
- LOG("32-bit render");
- for( y = 0; y < render_h; y ++ )
- {
- Uint32 *px;
- px = dest;
- for(x = 0; x < render_w; x ++, px ++)
- {
- Uint32 value = src[x];
- // TODO: Should I implement alpha blending?
- if(value & 0xFF000000)
- *px = value;
- else
- ; // NOP, completely transparent
- }
- LOG("row %i/%i (%p-%P) done", y+1, render_h, dest, MM_GetPhysAddr(dest));
- src += Buf->CursorBitmap->W;
- dest = (Uint8*)dest + Buf->Pitch;
- }
- break;
- default:
- Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
- Buf->CursorX = -1;
- break;
- }
-}
-
-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 ;
- if( !Buf->CursorSaveBuf ) 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;
-
- // Copy each line back
- for( y = 0; y < Buf->CursorRenderH; y ++ )
- {
- memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
- src += save_pitch;
- dest += Buf->Pitch;
- }
-
- // Set the cursor as removed
- Buf->CursorX = -1;
-}
-
-void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
-{
- tDrvUtil_Video_BufInfo *FBInfo = Ent;
-
- // TODO: Handle non-32bit modes
- if( FBInfo->Depth != 32 ) return;
-
- // TODO: Be less hacky
- int pitch = FBInfo->Pitch/4;
- Uint32 *buf = (Uint32*)FBInfo->Framebuffer + Y*pitch + X;
- while( H -- ) {
- Uint32 *tmp;
- int i;
- tmp = buf;
- for(i=W;i--;tmp++) *tmp = Colour;
- buf += pitch;
- }
-}
-
-void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
-{
- tDrvUtil_Video_BufInfo *FBInfo = Ent;
- int scrnpitch = FBInfo->Pitch;
- int bytes_per_px = (FBInfo->Depth + 7) / 8;
- int dst = DstY*scrnpitch + DstX;
- int src = SrcY*scrnpitch + SrcX;
- int tmp;
-
- //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
- // Ent, DstX, DstY, SrcX, SrcY, W, H);
-
- if(SrcX + W > FBInfo->Width) W = FBInfo->Width - SrcX;
- if(DstX + W > FBInfo->Width) W = FBInfo->Width - DstX;
- if(SrcY + H > FBInfo->Height) H = FBInfo->Height - SrcY;
- if(DstY + H > FBInfo->Height) H = FBInfo->Height - DstY;
-
- //Debug("W = %i, H = %i", W, H);
-
- if( dst > src ) {
- // Reverse copy
- dst += H*scrnpitch;
- src += H*scrnpitch;
- while( H -- ) {
- dst -= scrnpitch;
- src -= scrnpitch;
- tmp = W*bytes_per_px;
- for( tmp = W; tmp --; ) {
- *((Uint8*)FBInfo->Framebuffer + dst + tmp) = *((Uint8*)FBInfo->Framebuffer + src + tmp);
- }
- }
- }
- else if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px) {
- memmove((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, H*FBInfo->Pitch);
- }
- else {
- // Normal copy is OK
- while( H -- ) {
- memcpy((Uint8*)FBInfo->Framebuffer + dst, (Uint8*)FBInfo->Framebuffer + src, W*bytes_per_px);
- dst += scrnpitch;
- src += scrnpitch;
- }
- }
- //Log("Vesa_2D_Blit: RETURN");
-}
-
-
-// --- Disk Driver Helpers ---
-Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,
- tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, void *Argument)
-{
- Uint8 tmp[BlockSize]; // C99
- Uint64 block = Start / BlockSize;
- int offset = Start - block * BlockSize;
- int leading = BlockSize - offset;
- Uint64 num;
- int tailings;
- Uint64 ret;
-
- ENTER("XStart XLength pBuffer pReadBlocks XBlockSize pArgument",
- Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
-
- // Non aligned start, let's fix that!
- if(offset != 0)
- {
- if(leading > Length) leading = Length;
- LOG("Reading %i bytes from Block1+%i", leading, offset);
- ret = ReadBlocks(block, 1, tmp, Argument);
- if(ret != 1) {
- LEAVE('i', 0);
- return 0;
- }
- memcpy( Buffer, &tmp[offset], leading );
-
- if(leading == Length) {
- LEAVE('i', leading);
- return leading;
- }
-
- Buffer = (Uint8*)Buffer + leading;
- block ++;
- num = ( Length - leading ) / BlockSize;
- tailings = Length - num * BlockSize - leading;
- }
- else {
- num = Length / BlockSize;
- tailings = Length % BlockSize;
- }
-
- // Read central blocks
- if(num)
- {
- LOG("Reading %i blocks", num);
- ret = ReadBlocks(block, num, Buffer, Argument);
- if(ret != num ) {
- LEAVE('X', leading + ret * BlockSize);
- return leading + ret * BlockSize;
- }
- }
-
- // Read last tailing block
- if(tailings != 0)
- {
- LOG("Reading %i bytes from last block", tailings);
- block += num;
- Buffer = (Uint8*)Buffer + num * BlockSize;
- ret = ReadBlocks(block, 1, tmp, Argument);
- if(ret != 1) {
- LEAVE('X', leading + num * BlockSize);
- return leading + num * BlockSize;
- }
- memcpy( Buffer, tmp, tailings );
- }
-
- LEAVE('X', Length);
- return Length;
-}
-
-Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,
- tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
- Uint64 BlockSize, void *Argument)
-{
- Uint8 tmp[BlockSize]; // C99
- Uint64 block = Start / BlockSize;
- int offset = Start - block * BlockSize;
- int leading = BlockSize - offset;
- Uint64 num;
- int tailings;
- Uint64 ret;
-
- ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize pArgument",
- Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
-
- // Non aligned start, let's fix that!
- if(offset != 0)
- {
- if(leading > Length) leading = Length;
- LOG("Writing %i bytes to Block1+%i", leading, offset);
- // Read a copy of the block
- ret = ReadBlocks(block, 1, tmp, Argument);
- if(ret != 1) {
- LEAVE('i', 0);
- return 0;
- }
- // Modify
- memcpy( &tmp[offset], Buffer, leading );
- // Write Back
- ret = WriteBlocks(block, 1, tmp, Argument);
- if(ret != 1) {
- LEAVE('i', 0);
- return 0;
- }
-
- if(leading == Length) {
- LEAVE('i', leading);
- return leading;
- }
-
- Buffer = (Uint8*)Buffer + leading;
- block ++;
- num = ( Length - leading ) / BlockSize;
- tailings = Length - num * BlockSize - leading;
- }
- else {
- num = Length / BlockSize;
- tailings = Length % BlockSize;
- }
-
- // Read central blocks
- if(num)
- {
- LOG("Writing %i blocks", num);
- ret = WriteBlocks(block, num, Buffer, Argument);
- if(ret != num ) {
- LEAVE('X', leading + ret * BlockSize);
- return leading + ret * BlockSize;
- }
- }
-
- // Read last tailing block
- if(tailings != 0)
- {
- LOG("Writing %i bytes to last block", tailings);
- block += num;
- Buffer = (Uint8*)Buffer + num * BlockSize;
- // Read
- ret = ReadBlocks(block, 1, tmp, Argument);
- if(ret != 1) {
- LEAVE('X', leading + num * BlockSize);
- return leading + num * BlockSize;
- }
- // Modify
- memcpy( tmp, Buffer, tailings );
- // Write
- ret = WriteBlocks(block, 1, tmp, Argument);
- if(ret != 1) {
- LEAVE('X', leading + num * BlockSize);
- return leading + num * BlockSize;
- }
-
- }
-
- LEAVE('X', Length);
- return Length;
-}
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge
+ *
+ * drvutil_disk.c
+ * - Storage Driver Helper Functions
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <api_drv_disk.h>
+
+// --- Disk Driver Helpers ---
+size_t DrvUtil_ReadBlock(Uint64 Start, size_t Length, void *Buffer,
+ tDrvUtil_Read_Callback ReadBlocks, size_t BlockSize, void *Argument)
+{
+ Uint8 tmp[BlockSize]; // C99
+ Uint64 block = Start / BlockSize;
+ int offset = Start - block * BlockSize;
+ size_t leading = BlockSize - offset;
+ Uint64 num;
+ int tailings;
+ size_t ret;
+
+ ENTER("XStart XLength pBuffer pReadBlocks XBlockSize pArgument",
+ Start, Length, Buffer, ReadBlocks, BlockSize, Argument);
+
+ // Non aligned start, let's fix that!
+ if(offset != 0)
+ {
+ if(leading > Length) leading = Length;
+ LOG("Reading %i bytes from Block1+%i", leading, offset);
+ ret = ReadBlocks(block, 1, tmp, Argument);
+ if(ret != 1) {
+ LEAVE('i', 0);
+ return 0;
+ }
+ memcpy( Buffer, &tmp[offset], leading );
+
+ if(leading == Length) {
+ LEAVE('i', leading);
+ return leading;
+ }
+
+ Buffer = (Uint8*)Buffer + leading;
+ block ++;
+ num = ( Length - leading ) / BlockSize;
+ tailings = Length - num * BlockSize - leading;
+ }
+ else {
+ num = Length / BlockSize;
+ tailings = Length % BlockSize;
+ leading = 0;
+ }
+
+ // Read central blocks
+ if(num)
+ {
+ LOG("Reading %i blocks", num);
+ ret = ReadBlocks(block, num, Buffer, Argument);
+ if(ret != num ) {
+ LOG("Incomplete read (%i != %i)", ret, num);
+ LEAVE('X', leading + ret * BlockSize);
+ return leading + ret * BlockSize;
+ }
+ }
+
+ // Read last tailing block
+ if(tailings != 0)
+ {
+ LOG("Reading %i bytes from last block", tailings);
+ block += num;
+ Buffer = (Uint8*)Buffer + num * BlockSize;
+ ret = ReadBlocks(block, 1, tmp, Argument);
+ if(ret != 1) {
+ LEAVE('X', leading + num * BlockSize);
+ return leading + num * BlockSize;
+ }
+ memcpy( Buffer, tmp, tailings );
+ }
+
+ LEAVE('X', Length);
+ return Length;
+}
+
+size_t DrvUtil_WriteBlock(Uint64 Start, size_t Length, const void *Buffer,
+ tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,
+ size_t BlockSize, void *Argument)
+{
+ Uint8 tmp[BlockSize]; // C99
+ Uint64 block = Start / BlockSize;
+ size_t offset = Start - block * BlockSize;
+ size_t leading = BlockSize - offset;
+ Uint64 num;
+ int tailings;
+ size_t ret;
+
+ ENTER("XStart XLength pBuffer pReadBlocks pWriteBlocks XBlockSize pArgument",
+ Start, Length, Buffer, ReadBlocks, WriteBlocks, BlockSize, Argument);
+
+ // Non aligned start, let's fix that!
+ if(offset != 0)
+ {
+ if(leading > Length) leading = Length;
+ LOG("Writing %i bytes to Block1+%i", leading, offset);
+ // Read a copy of the block
+ ret = ReadBlocks(block, 1, tmp, Argument);
+ if(ret != 1) {
+ LEAVE('i', 0);
+ return 0;
+ }
+ // Modify
+ memcpy( &tmp[offset], Buffer, leading );
+ // Write Back
+ ret = WriteBlocks(block, 1, tmp, Argument);
+ if(ret != 1) {
+ LEAVE('i', 0);
+ return 0;
+ }
+
+ if(leading == Length) {
+ LEAVE('i', leading);
+ return leading;
+ }
+
+ Buffer = (Uint8*)Buffer + leading;
+ block ++;
+ num = ( Length - leading ) / BlockSize;
+ tailings = Length - num * BlockSize - leading;
+ }
+ else {
+ num = Length / BlockSize;
+ tailings = Length % BlockSize;
+ }
+
+ // Read central blocks
+ if(num)
+ {
+ LOG("Writing %i blocks", num);
+ ret = WriteBlocks(block, num, Buffer, Argument);
+ if(ret != num ) {
+ LEAVE('X', leading + ret * BlockSize);
+ return leading + ret * BlockSize;
+ }
+ }
+
+ // Read last tailing block
+ if(tailings != 0)
+ {
+ LOG("Writing %i bytes to last block", tailings);
+ block += num;
+ Buffer = (Uint8*)Buffer + num * BlockSize;
+ // Read
+ ret = ReadBlocks(block, 1, tmp, Argument);
+ if(ret != 1) {
+ LEAVE('X', leading + num * BlockSize);
+ return leading + num * BlockSize;
+ }
+ // Modify
+ memcpy( tmp, Buffer, tailings );
+ // Write
+ ret = WriteBlocks(block, 1, tmp, Argument);
+ if(ret != 1) {
+ LEAVE('X', leading + num * BlockSize);
+ return leading + num * BlockSize;
+ }
+
+ }
+
+ LEAVE('X', Length);
+ return Length;
+}
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge
+ *
+ * drvutil.c
+ * - Video Driver Helper Functions
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <api_drv_video.h>
+
+// === TYPES ===
+
+// === PROTOTYPES ===
+//int DrvUtil_Video_2DStream(void *Ent, void *Buffer, int Length, tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers);
+//size_t DrvUtil_Video_WriteLFB(int Mode, tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, void *Src);
+//void DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap);
+//void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y);
+void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf);
+//void DrvUtil_Video_RemoveCursor(tDrvUtil_Video_BufInfo *Buf);
+void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour);
+void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H);
+
+// === GLOBALS ===
+tDrvUtil_Video_2DHandlers gDrvUtil_Stub_2DFunctions = {
+ NULL,
+ DrvUtil_Video_2D_Fill,
+ DrvUtil_Video_2D_Blit
+};
+tVideo_IOCtl_Bitmap gDrvUtil_TextModeCursor = {
+ 8, 16,
+ 0, 0,
+ {
+ 0, 0, 0 , 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0,-1, 0xFF000000, 0, 0, 0, 0, 0,
+ 0, 0, 0 , 0, 0, 0, 0, 0,
+ 0, 0, 0 , 0, 0, 0, 0, 0
+ }
+};
+
+// === CODE ===
+// --- Video Driver Helpers ---
+int DrvUtil_Video_2DStream(void *Ent, const void *Buffer, int Length,
+ tDrvUtil_Video_2DHandlers *Handlers, int SizeofHandlers)
+{
+ const Uint8 *stream = Buffer;
+ int rem = Length;
+ int op;
+
+ Uint16 tmp[6];
+
+ while( rem )
+ {
+ rem --;
+ op = *stream;
+ stream ++;
+
+ if(op > NUM_VIDEO_2DOPS) {
+ Log_Warning("DrvUtil",
+ "DrvUtil_Video_2DStream: Unknown operation %i",
+ op);
+ return Length-rem;
+ }
+
+ if(op*sizeof(void*) > SizeofHandlers) {
+ Log_Warning("DrvUtil",
+ "DrvUtil_Video_2DStream: Driver does not support op %i",
+ op);
+ return Length-rem;
+ }
+
+ switch(op)
+ {
+ case VIDEO_2DOP_NOP: break;
+
+ case VIDEO_2DOP_FILL:
+ if(rem < 12) return Length-rem;
+ memcpy(tmp, stream, 6*2);
+
+ if(!Handlers->Fill) {
+ Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
+ " does not support VIDEO_2DOP_FILL");
+ return Length-rem;
+ }
+
+ Handlers->Fill(
+ Ent,
+ tmp[0], tmp[1], tmp[2], tmp[3],
+ tmp[4] | ((Uint32)tmp[5] << 16)
+ );
+
+ rem -= 12;
+ stream += 12;
+ break;
+
+ case VIDEO_2DOP_BLIT:
+ if(rem < 12) return Length-rem;
+ memcpy(tmp, stream, 6*2);
+
+ if(!Handlers->Blit) {
+ Log_Warning("DrvUtil", "DrvUtil_Video_2DStream: Driver"
+ " does not support VIDEO_2DOP_BLIT");
+ return Length-rem;
+ }
+
+ Handlers->Blit(
+ Ent,
+ tmp[0], tmp[1], tmp[2], tmp[3],
+ tmp[4], tmp[5]
+ );
+
+ rem -= 12;
+ stream += 12;
+ break;
+
+ }
+ }
+ return 0;
+}
+
+int DrvUtil_Video_WriteLFB(tDrvUtil_Video_BufInfo *FBInfo, size_t Offset, size_t Length, const void *Buffer)
+{
+ Uint8 *dest;
+ const Uint32 *src = Buffer;
+ int csr_x, csr_y;
+ int x, y;
+ int bytes_per_px = (FBInfo->Depth + 7) / 8;
+ size_t ofs;
+ ENTER("pFBInfo xOffset xLength pBuffer",
+ FBInfo, Offset, Length, Buffer);
+
+ csr_x = FBInfo->CursorX;
+ csr_y = FBInfo->CursorY;
+
+ if( FBInfo->BackBuffer )
+ dest = FBInfo->BackBuffer;
+ else
+ dest = FBInfo->Framebuffer;
+
+ DrvUtil_Video_RemoveCursor(FBInfo);
+
+ switch( FBInfo->BufferFormat )
+ {
+ case VIDEO_BUFFMT_TEXT:
+ {
+ const tVT_Char *chars = Buffer;
+ int widthInChars = FBInfo->Width/giVT_CharWidth;
+ int heightInChars = FBInfo->Height/giVT_CharHeight;
+ int i;
+
+ LOG("bytes_per_px = %i", bytes_per_px);
+ LOG("widthInChars = %i, heightInChars = %i", widthInChars, heightInChars);
+
+ Length /= sizeof(tVT_Char); Offset /= sizeof(tVT_Char);
+
+ x = Offset % widthInChars; y = Offset / widthInChars;
+ LOG("x = %i, y = %i", x, y);
+
+ // Sanity Check
+ if(Offset > heightInChars * widthInChars) LEAVE_RET('i', 0);
+ if(y >= heightInChars) LEAVE_RET('i', 0);
+
+ if( Offset + Length > heightInChars*widthInChars )
+ {
+ Length = heightInChars*widthInChars - Offset;
+ }
+
+ LOG("dest = %p", dest);
+ ofs = y * giVT_CharHeight * FBInfo->Pitch;
+ dest += ofs;
+
+ for( i = 0; i < Length; i++ )
+ {
+ if( y >= heightInChars )
+ {
+ Log_Notice("DrvUtil", "Stopped at %i", i);
+ break;
+ }
+
+ VT_Font_Render(
+ chars->Ch,
+ dest + x*giVT_CharWidth*bytes_per_px, FBInfo->Depth, FBInfo->Pitch,
+ VT_Colour12toN(chars->BGCol, FBInfo->Depth),
+ VT_Colour12toN(chars->FGCol, FBInfo->Depth)
+ );
+
+ chars ++;
+ x ++;
+ if( x >= widthInChars )
+ {
+ x = 0;
+ y ++;
+ dest += FBInfo->Pitch*giVT_CharHeight;
+ LOG("dest = %p", dest);
+ }
+ }
+ if( x > 0 )
+ dest += FBInfo->Pitch*giVT_CharHeight;
+ Length = i * sizeof(tVT_Char);
+
+ break; }
+
+ case VIDEO_BUFFMT_FRAMEBUFFER:
+ if(FBInfo->Width*FBInfo->Height*4 < Offset+Length)
+ {
+ Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Framebuffer Overflow");
+ return 0;
+ }
+
+ switch(FBInfo->Depth)
+ {
+ case 15:
+ case 16:
+ Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in LFB write");
+ dest = NULL;
+ break;
+ case 24:
+ x = Offset % FBInfo->Width;
+ y = Offset / FBInfo->Width;
+ ofs = y*FBInfo->Pitch;
+ dest += ofs;
+ for( ; Length >= 4; Length -= 4 )
+ {
+ dest[x*3+0] = *src & 0xFF;
+ dest[x*3+1] = (*src >> 8) & 0xFF;
+ dest[x*3+2] = (*src >> 16) & 0xFF;
+ x ++;
+ if(x == FBInfo->Width) {
+ dest += FBInfo->Pitch;
+ x = 0;
+ }
+ }
+ break;
+ case 32:
+ // Copy to Frambuffer
+ if( FBInfo->Pitch != FBInfo->Width*4 )
+ {
+ Uint32 *px;
+ // Pitch isn't 4*Width
+ x = Offset % FBInfo->Width;
+ y = Offset / FBInfo->Height;
+
+ ofs = y*FBInfo->Pitch;
+ dest += ofs;
+ px = (void*)dest;
+
+ for( ; Length >= 4; Length -= 4 )
+ {
+ px[x++] = *src ++;
+ if( x == FBInfo->Width ) {
+ x = 0;
+ dest += FBInfo->Pitch;
+ px = (void*)dest;
+ }
+ }
+ if( x > 0 ) {
+ dest += FBInfo->Pitch;
+ }
+ }
+ else
+ {
+ ofs = Offset;
+ dest += ofs;
+ memcpy(dest, Buffer, Length);
+ dest += Length;
+ }
+ break;
+ default:
+ Log_Warning("DrvUtil", "DrvUtil_Video_WriteLFB - Unknown bit depth %i", FBInfo->Depth);
+ dest = NULL;
+ break;
+ }
+ break;
+
+ case VIDEO_BUFFMT_2DSTREAM:
+ Length = DrvUtil_Video_2DStream(
+ FBInfo, Buffer, Length,
+ &gDrvUtil_Stub_2DFunctions, sizeof(gDrvUtil_Stub_2DFunctions)
+ );
+ dest = NULL;
+ break;
+
+ default:
+ LEAVE('i', -1);
+ return -1;
+ }
+ if( FBInfo->BackBuffer && dest ) {
+ void *_dst = (char*)FBInfo->Framebuffer + ofs;
+ void *_src = (char*)FBInfo->BackBuffer + ofs;
+ size_t len = ((tVAddr)dest - (tVAddr)FBInfo->BackBuffer) - ofs;
+ // Log_Debug("DrvUtil", "Copy from BB %p to FB %p 0x%x bytes", _src, _dst, len);
+ memcpy(_dst, _src, len);
+ }
+
+ DrvUtil_Video_DrawCursor(FBInfo, csr_x, csr_y);
+
+ LEAVE('x', Length);
+ return Length;
+}
+
+int DrvUtil_Video_SetCursor(tDrvUtil_Video_BufInfo *Buf, tVideo_IOCtl_Bitmap *Bitmap)
+{
+ int csrX = Buf->CursorX, csrY = Buf->CursorY;
+ size_t size;
+
+ ENTER("pBuf pBitmap", Buf, Bitmap);
+
+ // Clear old bitmap
+ if( Buf->CursorBitmap )
+ {
+ LOG("Clearing old cursor");
+ DrvUtil_Video_RemoveCursor(Buf);
+ if( !Bitmap || Bitmap->W != Buf->CursorBitmap->W || Bitmap->H != Buf->CursorBitmap->H )
+ {
+ free( Buf->CursorSaveBuf );
+ Buf->CursorSaveBuf = NULL;
+ }
+ if( Buf->CursorBitmap != &gDrvUtil_TextModeCursor)
+ free(Buf->CursorBitmap);
+ Buf->CursorBitmap = NULL;
+ }
+
+ // If the new bitmap is null, disable drawing
+ if( !Bitmap )
+ {
+ Buf->CursorX = -1;
+ Buf->CursorY = -1;
+ LEAVE('i', 0);
+ return 0;
+ }
+
+ // Sanity check the bitmap
+ LOG("Sanity checking plox");
+ if( !CheckMem(Bitmap, sizeof(*Bitmap)) || !CheckMem(Bitmap->Data, Bitmap->W*Bitmap->H*sizeof(Uint32)) )
+ {
+ Log_Warning("DrvUtil", "DrvUtil_Video_SetCursor: Bitmap (%p) is in invalid memory", Bitmap);
+ errno = -EINVAL;
+ LEAVE('i', -1);
+ return -1;
+ }
+
+ // Don't take a copy of the DrvUtil provided cursor
+ if( Bitmap == &gDrvUtil_TextModeCursor )
+ {
+ LOG("No copy (provided cursor)");
+ Buf->CursorBitmap = Bitmap;
+ }
+ else
+ {
+ LOG("Make copy");
+ size = sizeof(tVideo_IOCtl_Bitmap) + Bitmap->W*Bitmap->H*4;
+
+ // Take a copy
+ Buf->CursorBitmap = malloc( size );
+ memcpy(Buf->CursorBitmap, Bitmap, size);
+ }
+
+ // Restore cursor position
+ LOG("Drawing");
+ DrvUtil_Video_DrawCursor(Buf, csrX, csrY);
+ LEAVE('i', 0);
+ return 0;
+}
+
+void DrvUtil_Video_DrawCursor(tDrvUtil_Video_BufInfo *Buf, int X, int Y)
+{
+ int render_ox=0, render_oy=0, render_w, render_h;
+
+ ENTER("pBuf iX iY", Buf, X, Y);
+ DrvUtil_Video_RemoveCursor(Buf);
+
+ // X < 0 disables the cursor
+ if( X < 0 ) {
+ Buf->CursorX = -1;
+ LEAVE('-');
+ return ;
+ }
+
+ // Sanity checking
+ if( X < 0 || Y < 0 || X >= Buf->Width || Y >= Buf->Height ) {
+ LEAVE('-');
+ return ;
+ }
+
+ // Ensure the cursor is enabled
+ if( !Buf->CursorBitmap ) {
+ LEAVE('-');
+ return ;
+ }
+
+ // Save cursor position (for changing the bitmap)
+ Buf->CursorX = X; Buf->CursorY = Y;
+ // Apply cursor's center offset
+ X -= Buf->CursorBitmap->XOfs;
+ Y -= Buf->CursorBitmap->YOfs;
+
+ // Get the width of the cursor on screen (clipping to right/bottom edges)
+ render_w = X > Buf->Width - Buf->CursorBitmap->W ? Buf->Width - X : Buf->CursorBitmap->W;
+ render_h = Y > Buf->Height - Buf->CursorBitmap->H ? Buf->Height - Y : Buf->CursorBitmap->H;
+
+ // Clipp to left/top edges
+ if(X < 0) { render_ox = -X; X = 0; }
+ if(Y < 0) { render_oy = -Y; Y = 0; }
+
+ // Save values
+ Buf->CursorRenderW = render_w; Buf->CursorRenderH = render_h;
+ Buf->CursorDestX = X; Buf->CursorDestY = Y;
+ Buf->CursorReadX = render_ox; Buf->CursorReadY = render_oy;
+
+ LOG("%ix%i at %i,%i offset %i,%i",
+ render_w, render_h, X, Y, render_ox, render_oy);
+
+ // Call render routine
+ DrvUtil_Video_RenderCursor(Buf);
+ LEAVE('-');
+}
+
+void DrvUtil_Video_RenderCursor(tDrvUtil_Video_BufInfo *Buf)
+{
+ int src_x = Buf->CursorReadX, src_y = Buf->CursorReadY;
+ int render_w = Buf->CursorRenderW, render_h = Buf->CursorRenderH;
+ int dest_x = Buf->CursorDestX, dest_y = Buf->CursorDestY;
+ int bytes_per_px = (Buf->Depth + 7) / 8;
+ int save_pitch = Buf->CursorBitmap->W * bytes_per_px;
+ void *dest;
+ Uint32 *src;
+ int x, y;
+
+ dest = (Uint8*)Buf->Framebuffer + dest_y*Buf->Pitch + dest_x*bytes_per_px;
+ src = Buf->CursorBitmap->Data + src_y * Buf->CursorBitmap->W + src_x;
+
+ LOG("dest = %p, src = %p", dest, src);
+
+ // Allocate save buffer if not already
+ if( !Buf->CursorSaveBuf )
+ Buf->CursorSaveBuf = malloc( Buf->CursorBitmap->W*Buf->CursorBitmap->H*bytes_per_px );
+
+ LOG("Saving back");
+ // Save behind the cursor
+ for( y = 0; y < render_h; y ++ )
+ memcpy(
+ (Uint8*)Buf->CursorSaveBuf + y*save_pitch,
+ (Uint8*)dest + y*Buf->Pitch,
+ render_w*bytes_per_px
+ );
+
+ // Draw the cursor
+ switch(Buf->Depth)
+ {
+ case 15:
+ case 16:
+ Log_Warning("DrvUtil", "TODO: Support 15/16 bpp modes in cursor draw");
+ break;
+ case 24:
+ LOG("24-bit render");
+ for( y = 0; y < render_h; y ++ )
+ {
+ Uint8 *px;
+ px = dest;
+ for(x = 0; x < render_w; x ++, px += 3)
+ {
+ Uint32 value = src[x];
+ // TODO: Should I implement alpha blending?
+ if(value & 0xFF000000)
+ {
+ px[0] = value & 0xFF;
+ px[1] = (value >> 8) & 0xFF;
+ px[2] = (value >> 16) & 0xFF;
+ }
+ else
+ ;
+ }
+ src += Buf->CursorBitmap->W;
+ dest = (Uint8*)dest + Buf->Pitch;
+ }
+ break;
+ case 32:
+ LOG("32-bit render");
+ for( y = 0; y < render_h; y ++ )
+ {
+ Uint32 *px;
+ px = dest;
+ for(x = 0; x < render_w; x ++, px ++)
+ {
+ Uint32 value = src[x];
+ // TODO: Should I implement alpha blending?
+ if(value & 0xFF000000)
+ *px = value;
+ else
+ ; // NOP, completely transparent
+ }
+ LOG("row %i/%i (%p-%P) done", y+1, render_h, dest, MM_GetPhysAddr(dest));
+ src += Buf->CursorBitmap->W;
+ dest = (Uint8*)dest + Buf->Pitch;
+ }
+ break;
+ default:
+ Log_Error("DrvUtil", "RenderCursor - Unknown bit depth %i", Buf->Depth);
+ Buf->CursorX = -1;
+ break;
+ }
+}
+
+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 ;
+ if( !Buf->CursorSaveBuf ) 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;
+
+ // Copy each line back
+ for( y = 0; y < Buf->CursorRenderH; y ++ )
+ {
+ memcpy( dest, src, Buf->CursorRenderW * bytes_per_px );
+ src += save_pitch;
+ dest += Buf->Pitch;
+ }
+
+ // Set the cursor as removed
+ Buf->CursorX = -1;
+}
+
+void DrvUtil_Video_2D_Fill(void *Ent, Uint16 X, Uint16 Y, Uint16 W, Uint16 H, Uint32 Colour)
+{
+ tDrvUtil_Video_BufInfo *FBInfo = Ent;
+
+ switch( FBInfo->Depth )
+ {
+ case 32: {
+ // TODO: Be less hacky
+ size_t pitch = FBInfo->Pitch/4;
+ size_t ofs = Y*pitch + X;
+ Uint32 *buf = (Uint32*)FBInfo->Framebuffer + ofs;
+ Uint32 *cbuf = NULL;
+ if( FBInfo->BackBuffer )
+ cbuf = (Uint32*)FBInfo->BackBuffer + ofs;
+ while( H -- )
+ {
+ Uint32 *line;
+ line = buf;
+ for(int i = W; i--; line++)
+ *line = Colour;
+ buf += pitch;
+ if( cbuf ) {
+ line = cbuf;
+ for(int i = W; i--; line++ )
+ *line = Colour;
+ cbuf += pitch;
+ }
+ }
+ break; }
+ default:
+ // TODO: Handle non-32bit modes
+ Log_Warning("DrvUtil", "TODO: <32bpp _Fill");
+ break;
+ }
+}
+
+void DrvUtil_Video_2D_Blit(void *Ent, Uint16 DstX, Uint16 DstY, Uint16 SrcX, Uint16 SrcY, Uint16 W, Uint16 H)
+{
+ tDrvUtil_Video_BufInfo *FBInfo = Ent;
+ int scrnpitch = FBInfo->Pitch;
+ int bytes_per_px = (FBInfo->Depth + 7) / 8;
+ int dst = DstY*scrnpitch + DstX;
+ int src = SrcY*scrnpitch + SrcX;
+ int tmp;
+ Uint8 *framebuffer = FBInfo->Framebuffer;
+ Uint8 *backbuffer = FBInfo->BackBuffer;
+ Uint8 *sourcebuffer = (FBInfo->BackBuffer ? FBInfo->BackBuffer : FBInfo->Framebuffer);
+
+ //Log("Vesa_2D_Blit: (Ent=%p, DstX=%i, DstY=%i, SrcX=%i, SrcY=%i, W=%i, H=%i)",
+ // Ent, DstX, DstY, SrcX, SrcY, W, H);
+
+ if(SrcX + W > FBInfo->Width) W = FBInfo->Width - SrcX;
+ if(DstX + W > FBInfo->Width) W = FBInfo->Width - DstX;
+ if(SrcY + H > FBInfo->Height) H = FBInfo->Height - SrcY;
+ if(DstY + H > FBInfo->Height) H = FBInfo->Height - DstY;
+
+ //Debug("W = %i, H = %i", W, H);
+
+ if(W == FBInfo->Width && FBInfo->Pitch == FBInfo->Width*bytes_per_px)
+ {
+ memmove(framebuffer + dst, sourcebuffer + src, H*FBInfo->Pitch);
+ if( backbuffer )
+ memmove(backbuffer + dst, sourcebuffer + src, H*FBInfo->Pitch);
+ }
+ else if( dst > src )
+ {
+ // Reverse copy
+ dst += H*scrnpitch;
+ src += H*scrnpitch;
+ while( H -- )
+ {
+ dst -= scrnpitch;
+ src -= scrnpitch;
+ tmp = W*bytes_per_px;
+ for( tmp = W; tmp --; )
+ {
+ size_t src_o = src + tmp;
+ size_t dst_o = src + tmp;
+ framebuffer[dst_o] = sourcebuffer[src_o];
+ if( backbuffer )
+ backbuffer[dst_o] = sourcebuffer[src_o];
+ }
+ }
+ }
+ else {
+ // Normal copy is OK
+ while( H -- )
+ {
+ memcpy(framebuffer + dst, sourcebuffer + src, W*bytes_per_px);
+ if( backbuffer )
+ memcpy(backbuffer + dst, sourcebuffer + src, W*bytes_per_px);
+ dst += scrnpitch;
+ src += scrnpitch;
+ }
+ }
+ //Log("Vesa_2D_Blit: RETURN");
+}
+
+
size_t Bytes;
if( __Bytes == 0 ) {
- //return NULL; // TODO: Return a known un-mapped range.
- return INVLPTR;
+ return NULL; // TODO: Return a known un-mapped range.
+// return INVLPTR;
}
// Get required size
#endif
Mutex_Release(&glHeap); // Release spinlock
#if WARNINGS
- Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
+ Log_Warning("Heap", "Size of heap address %p is invalid - not aligned (0x%x) [at paddr 0x%x]",
+ head, head->Size, MM_GetPhysAddr(&head->Size));
Heap_Dump();
#endif
return NULL;
// Sanity check
if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
{
- Log_Warning("Heap", "free - Passed a non-heap address by %p (%p < %p < %p)\n",
+ Log_Warning("Heap", "free - Passed a non-heap address by %p (%p < %p < %p)",
__builtin_return_address(0), gHeapStart, Ptr, gHeapEnd);
return;
}
{
tHeapHead *head, *badHead;
tHeapFoot *foot = NULL;
+ static int in_heap_dump;
+ if( in_heap_dump ) return;
+
+ in_heap_dump = 1;
+
head = gHeapStart;
while( (Uint)head < (Uint)gHeapEnd )
{
foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
#if VERBOSE_DUMP
Log_Log("Heap", "%p (0x%P): 0x%08x (%i) %4C",
- head, MM_GetPhysAddr((tVAddr)head), head->Size, head->ValidSize, &head->Magic);
+ head, MM_GetPhysAddr(head), head->Size, head->ValidSize, &head->Magic);
Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
if(head->File) {
Log_Log("Heap", "%sowned by %s:%i",
}
// If the heap is valid, ok!
- if( (tVAddr)head == (tVAddr)gHeapEnd )
+ if( (tVAddr)head == (tVAddr)gHeapEnd ) {
+ in_heap_dump = 0;
return ;
+ }
// Check for a bad return
- if( (tVAddr)head >= (tVAddr)gHeapEnd )
+ if( (tVAddr)head >= (tVAddr)gHeapEnd ) {
+ in_heap_dump = 0;
return ;
+ }
#if !VERBOSE_DUMP
Log_Log("Heap", "%p (%P): 0x%08lx %i %4C",
- head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
+ head, MM_GetPhysAddr(head), head->Size, head->ValidSize, &head->Magic);
if(foot)
Log_Log("Heap", "Foot %p = {Head:%p,Magic:%4C}", foot, foot->Head, &foot->Magic);
if(head->File) {
while( (tVAddr)head >= (tVAddr)badHead )
{
Log_Log("Heap", "%p (%P): 0x%08lx %i %4C",
- head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic);
+ head, MM_GetPhysAddr(head), head->Size, head->ValidSize, &head->Magic);
Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic);
if(head->File)
Log_Log("Heap", "%sowned by %s:%i",
#if 1
if( head->Magic == MAGIC_FREE )
Log_Debug("Heap", "%p (%P) - 0x%x free",
- head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size);
+ head->Data, MM_GetPhysAddr(&head->Data), head->Size);
else
Log_Debug("Heap", "%p (%P) - 0x%x (%i) Owned by %s:%i (%lli ms old)",
- head->Data, MM_GetPhysAddr((tVAddr)&head->Data), head->Size, head->ValidSize, head->File, head->Line,
+ head->Data, MM_GetPhysAddr(&head->Data), head->Size, head->ValidSize, head->File, head->Line,
now() - head->AllocateTime
);
#endif
#define PACKED __attribute__((packed))
//! Mark a function as not returning
#define NORETURN __attribute__((noreturn))
+//! Mark a function that its return value should be used
+#define WARN_UNUSED_RET __attribute__((warn_unused_result))
//! Mark a function (or variable) as deprecated
#define DEPRECATED __attribute__((deprecated))
//! Mark a parameter as unused
extern char __buildnum[];
#define BUILD_NUM ((int)(Uint)&__buildnum)
-extern const char gsGitHash[];
+extern const char gsGitHash[];
+extern const char gsBuildInfo[];
#define VER2(major,minor) ((((major)&0xFF)<<8)|((minor)&0xFF))
/**
* \param Addr Address of the page to get the physical address of
* \return Physical page mapped at \a Addr
*/
-extern tPAddr MM_GetPhysAddr(tVAddr Addr);
+extern tPAddr MM_GetPhysAddr(const void *Addr);
/**
* \brief Set the access flags on a page
* \param VAddr Virtual address of the page
* \return Virtual address of page in memory
* \note There is only a limited ammount of slots avaliable
*/
-extern tVAddr MM_MapTemp(tPAddr PAddr);
+extern void *MM_MapTemp(tPAddr PAddr);
/**
* \brief Free a temporarily mapped page
* \param VAddr Allocate virtual addres of page
*/
-extern void MM_FreeTemp(tVAddr VAddr);
+extern void MM_FreeTemp(void *Ptr);
/**
* \brief Map a physcal address range into the virtual address space
* \param PAddr Physical address to map in
#ifdef __BIG_ENDIAN__
#define LittleEndian16(_val) SwapEndian16(_val)
#define LittleEndian32(_val) SwapEndian32(_val)
+#define LittleEndian64(_val) SwapEndian32(_val)
#define BigEndian16(_val) (_val)
#define BigEndian32(_val) (_val)
+#define BigEndian64(_val) (_val)
#else
#define LittleEndian16(_val) (_val)
#define LittleEndian32(_val) (_val)
+#define LittleEndian64(_val) (_val)
#define BigEndian16(_val) SwapEndian16(_val)
#define BigEndian32(_val) SwapEndian32(_val)
+#define BigEndian64(_val) SwapEndian64(_val)
#endif
extern Uint16 SwapEndian16(Uint16 Val);
extern Uint32 SwapEndian32(Uint32 Val);
+extern Uint64 SwapEndian64(Uint64 Val);
/**
* \}
*/
extern char *_strdup(const char *File, int Line, const char *Str);
extern char **str_split(const char *__str, char __ch);
extern char *strchr(const char *__s, int __c);
+extern char *strrchr(const char *__s, int __c);
extern int strpos(const char *Str, char Ch);
extern int strpos8(const char *str, Uint32 search);
extern void itoa(char *buf, Uint64 num, int base, int minLength, char pad);
* \}
*/
+#include <ctype.h>
+
/**
* \brief Get a random number
* \return Random number
*/
/**
* \brief Create a timestamp from a time
+ * \note Days/Months are zero-based (e.g. December is 11, and has a day range of 0-30)
*/
extern tTime timestamp(int sec, int mins, int hrs, int day, int month, int year);
/**
* \brief Extract the date/time from a timestamp
+ * \note Days/Months are zero-based (e.g. December is 11, and has a day range of 0-30)
*/
extern void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
/**
* \name Threads and Processes
* \{
*/
-extern int Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
+extern struct sThread *Proc_SpawnWorker(void (*Fcn)(void*), void *Data);
extern int Proc_Spawn(const char *Path);
extern int Proc_SysSpawn(const char *Binary, const char **ArgV, const char **EnvP, int nFD, int *FDs);
extern int Proc_Execve(const char *File, const char **ArgV, const char **EnvP, int DataSize);
* \param Argument An argument to pass to \a ReadBlocks\r
* \return Number of bytes read\r
*/\r
-extern Uint64 DrvUtil_ReadBlock(Uint64 Start, Uint64 Length, void *Buffer,\r
- tDrvUtil_Read_Callback ReadBlocks, Uint64 BlockSize, void *Argument);\r
+extern size_t DrvUtil_ReadBlock(Uint64 Start, size_t Length, void *Buffer,\r
+ tDrvUtil_Read_Callback ReadBlocks, size_t BlockSize, void *Argument);\r
/**\r
* \brief Writes a range to a block device using aligned writes\r
* \param Start Base byte offset\r
* \param Argument An argument to pass to \a ReadBlocks and \a WriteBlocks\r
* \return Number of bytes written\r
*/\r
-extern Uint64 DrvUtil_WriteBlock(Uint64 Start, Uint64 Length, const void *Buffer,\r
+extern size_t DrvUtil_WriteBlock(Uint64 Start, size_t Length, const void *Buffer,\r
tDrvUtil_Read_Callback ReadBlocks, tDrvUtil_Write_Callback WriteBlocks,\r
- Uint64 BlockSize, void *Argument);\r
+ size_t BlockSize, void *Argument);\r
\r
/**\r
* \}\r
* \brief Bit depth of the framebuffer\r
*/\r
short Depth;\r
+ /**\r
+ * \brief Cached copy of the screens state (only used if not NULL)\r
+ */\r
+ void *BackBuffer;\r
/*\r
* \}\r
*/\r
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/bootmod.h
+ * - Common boot modules type
+ */
+#ifndef _BOOTMOD_H_
+#define _BOOTMOD_H_
+
+typedef struct sBootModule tBootModule;
+
+struct sBootModule {
+ tPAddr PBase;
+ void *Base;
+ Uint Size;
+ char *ArgString;
+};
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * ctype.h
+ * -
+ */
+#ifndef _ACESS__CTYPE_H_
+#define _ACESS__CTYPE_H_
+
+extern int isalnum(int c);
+extern int isalpha(int c);
+extern int isascii(int c);
+extern int isblank(int c);
+extern int iscntrl(int c);
+extern int isdigit(int c);
+extern int isgraph(int c);
+extern int islower(int c);
+extern int isprint(int c);
+extern int ispunct(int c);
+extern int isspace(int c);
+extern int isupper(int c);
+extern int isxdigit(int c);
+
+extern int toupper(int c);
+extern int tolower(int c);
+
+#endif
+
EINVAL, // Invalid Paramater
ENOMEM, // No free memory
EACCES, // Not permitted
+ EBUSY, // Resource is busy
ENOTFOUND, // Item not found
EREADONLY, // Read only
ENOTIMPL, // Not implemented
EEXIST, // Already exists
ENFILE, // Too many open files
ENOTDIR, // Not a directory
+ EIO, // IO Error
+ EINTR, // Operation interrupted (signal)
EALREADY, // Operation was a NOP
EINTERNAL, // Internal Error
#include <threads.h>
+/**
+ * \name Event Values
+ * \{
+ */
+//! Fired when a VFS wait is ready [used in select(2)]
#define THREAD_EVENT_VFS 0x00000001
+//! Fired when an IPC Message arrives
#define THREAD_EVENT_IPCMSG 0x00000002
+//! Fired when a signal (e.g. SIGINT) is asserted
#define THREAD_EVENT_SIGNAL 0x00000004
+//! Timer event fire
#define THREAD_EVENT_TIMER 0x00000008
+//! General purpose event for short waits
+//! e.g. waiting for an IRQ in a Read() call
#define THREAD_EVENT_SHORTWAIT 0x00000010
+#define THREAD_EVENT_USER1 0x10000000
+#define THREAD_EVENT_USER2 0x20000000
+#define THREAD_EVENT_USER3 0x40000000
+#define THREAD_EVENT_USER4 0x80000000
+/**
+ * \}
+ */
+
// === FUNCTIONS ===
extern void Threads_PostEvent(tThread *Thread, Uint32 EventMask);
extern void Threads_ClearEvent(Uint32 EventMask);
* \brief Achitecture defined thread/process management functions
*/
+#include <threads.h>
#include <threads_int.h>
/**
*/
extern void MM_DumpTables(tVAddr Start, tVAddr End);
+/**
+ * \brief Dump physical memory usage statistics to the debug channel
+ */
+extern void MM_DumpStatistics(void);
+
/**
* \brief Check if a buffer is valid (and all user if originally user)
* \param Addr Base address
extern void Arch_LoadBootModules(void);
extern void StartupPrint(const char *String);
+extern void System_Init(char *Commandline);
+extern void Threads_Init(void);
#endif
*/
#ifndef _MBOOT_H
#define _MBOOT_H
+#include <acess.h>
#define MULTIBOOT_MAGIC 0x2BADB002
+#include <pmemmap.h>
+#include <bootmod.h>
+
// === TYPES ===
typedef struct {
Uint32 Flags;
Uint32 Type; //1:RAM,Else Reserved
} __attribute__ ((packed)) tMBoot_MMapEnt;
+extern int Multiboot_LoadMemoryMap(tMBoot_Info *MBInfo, tVAddr MapOffset, tPMemMapEnt *Map, const int MapSize, tPAddr KStart, tPAddr KEnd);
+extern tBootModule *Multiboot_LoadModules(tMBoot_Info *MBInfo, tVAddr MapOffset, int *ModuleCount);
+
#endif
struct sModule *Next; //!< Next module in list (not to be touched by the driver)
const char *Name; //!< Module Name/Identifier
int (*Init)(char **Arguments); //!< Module initialiser / entrypoint
- void (*Deinit)(void); //!< Cleanup Function
+ int (*Deinit)(void); //!< Cleanup Function
const char **Dependencies; //!< NULL terminated list of dependencies
} PACKED tModule;
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * pmemmap.h
+ * - Physical Memory Map definitions
+ */
+#ifndef _PMEMMAP_H_
+#define _PMEMMAP_H_
+
+typedef struct sPMemMapEnt tPMemMapEnt;
+
+enum ePMemMapEntType
+{
+ PMEMTYPE_FREE, // Free RAM
+ PMEMTYPE_USED, // Used by Kernel / Modules
+ PMEMTYPE_RESERVED, // Unavaliable
+ PMEMTYPE_NVRAM, // Non-volatile
+ PMEMTYPE_UNMAPPED // Nothing on these lines
+};
+
+struct sPMemMapEnt
+{
+ Uint64 Start;
+ Uint64 Length;
+ enum ePMemMapEntType Type;
+ Uint16 NUMADomain;
+};
+
+extern void PMemMap_DumpBlocks(tPMemMapEnt *map, int NEnts);
+extern int PMemMap_SplitBlock(tPMemMapEnt *map, int NEnts, int MaxEnts, int Block, Uint64 Offset);
+extern int PMemMap_CompactMap(tPMemMapEnt *map, int NEnts, int MaxEnts);
+extern int PMemMap_ValidateMap(tPMemMapEnt *map, int NEnts, int MaxEnts);
+extern int PMemMap_MarkRangeUsed(tPMemMapEnt *map, int NEnts, int MaxEnts, Uint64 Base, Uint64 Size);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 Kernel
+ *
+ * rwmutex.c
+ * - Reader-Writer Mutex (Multiple Readers, One Writer)
+ */
+#ifndef _RWLOCK_H
+#define _RWLOCK_H
+
+#include <acess.h>
+
+typedef struct sRWLock tRWLock;
+
+struct sRWLock
+{
+ tShortSpinlock Protector; //!< Protector for the lock strucure
+ const char *Name; //!< Human-readable name
+ int Level; // Number of readers active
+ struct sThread *volatile Owner; //!< Owner of the lock (set upon getting the lock)
+ struct sThread *ReaderWaiting; //!< Waiting threads (readers)
+ struct sThread *ReaderWaitingLast; //!< Waiting threads
+
+ struct sThread *WriterWaiting; //!< Waiting threads (writers)
+ struct sThread *WriterWaitingLast; //!< Waiting threads
+};
+
+/**
+ * \brief Acquire a heavy mutex
+ * \param Mutex Mutex to acquire
+ * \return zero on success, -1 if terminated
+ *
+ * This type of mutex checks if the mutex is avaliable, and acquires it
+ * if it is. Otherwise, the current thread is added to the mutex's wait
+ * queue and the thread suspends. When the holder of the mutex completes,
+ * the oldest thread (top thread) on the queue is given the lock and
+ * restarted.
+ */
+extern int RWLock_AcquireRead(tRWLock *Lock);
+
+extern int RWLock_AcquireWrite(tRWLock *Lock);
+
+/**
+ * \brief Release a held mutex
+ * \param Mutex Mutex to release
+ * \note Releasing a non-held mutex has no effect
+ */
+extern void RWLock_Release(tRWLock *Lock);
+
+#endif
/*
- * Internal Threading header
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/threads_int.h
+ * - Internal Threading header
* - Only for use by stuff that needs access to the thread type.
*/
#ifndef _THREADS_INT_H_
#include <threads.h>
#include <proc.h>
+#include <timers_int.h>
typedef struct sProcess tProcess;
// --- event.c
Uint32 EventState;
+ // --- timer.c
+ tTimer ThreadTimer;
};
-enum {
+enum eThreadStatus {
THREAD_STAT_NULL, // Invalid process
THREAD_STAT_ACTIVE, // Running and schedulable process
THREAD_STAT_SLEEPING, // Message Sleep
THREAD_STAT_MUTEXSLEEP, // Mutex Sleep
+ THREAD_STAT_RWLOCKSLEEP, // Read-Writer lock Sleep
THREAD_STAT_SEMAPHORESLEEP, // Semaphore Sleep
THREAD_STAT_QUEUESLEEP, // Queue
THREAD_STAT_EVENTSLEEP, // Event sleep
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * include/timers_int.h
+ * - Timer internal header
+ * - Only for use by code that needs access to timer internals
+ */
+#ifndef _KERNEL__TIMERS_INT_H_
+#define _KERNEL__TIMERS_INT_H_
+
+#include <timers.h>
+
+// === TYPEDEFS ===
+struct sTimer {
+ tTimer *Next;
+ Sint64 FiresAfter;
+ void (*Callback)(void*);
+ void *Argument;
+// tMutex Lock;
+ BOOL bActive;
+};
+
+#endif
+
int MM_int_GetRangeID( tPAddr Addr );
int MM_int_GetMapEntry( void *Data, int Index, tPAddr *Start, tPAddr *Length );
void MM_Tpl_InitPhys(int MaxRAMPage, void *MemoryMap);
+void MM_DumpStatistics(void);
// === GLOBALS ===
tMutex glPhysicalPages;
bitmap_page &= ~(PAGE_SIZE-1);
// Only need to allocate bitmaps
- if( !MM_GetPhysAddr( bitmap_page ) ) {
+ if( !MM_GetPhysAddr( (void*)bitmap_page ) ) {
if( !MM_Allocate( bitmap_page ) ) {
Log_KernelPanic("PMM", "Out of memory during init, this is bad");
return ;
LEAVE('-');
}
+void MM_DumpStatistics(void)
+{
+ // TODO: PM Statistics for tpl_mm_phys_bitmap
+}
+
/**
* \brief Allocate a contiguous range of physical pages with a maximum
* bit size of \a MaxBits
LOG("if( MM_GetPhysAddr( %p ) )", &gaiPageReferences[addr]);
// Mark as referenced if the reference count page is valid
- if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[addr] ) ) {
+ if( MM_GetPhysAddr( &gaiPageReferences[addr] ) ) {
gaiPageReferences[addr] = 1;
}
}
tPAddr ret = 0;
for( ret = 0; ret < giMaxPhysPage; ret ++ )
{
- if( !MM_GetPhysAddr( (tVAddr)&gaPageBitmaps[ret/32] ) ) {
+ if( !MM_GetPhysAddr( &gaPageBitmaps[ret/32] ) ) {
ret += PAGE_SIZE*8;
continue ;
}
if( gaPageBitmaps[page / 32] == 0 )
gaSuperBitmap[page / (32*32)] &= ~(1LL << ((page / 32) & 31));
#endif
- if( MM_GetPhysAddr( refpage ) )
+ if( MM_GetPhysAddr( (void*)refpage ) )
gaiPageReferences[page] = 1;
}
else
{
// Reference again
- if( !MM_GetPhysAddr( refpage ) )
+ if( !MM_GetPhysAddr( (void*)refpage ) )
{
int pages_per_page, basepage, i;
if( MM_Allocate(refpage) == 0 ) {
int MM_GetRefCount(tPAddr PAddr)
{
PAddr >>= 12;
- if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[PAddr] ) ) {
+ if( MM_GetPhysAddr( &gaiPageReferences[PAddr] ) ) {
return gaiPageReferences[PAddr];
}
ENTER("PPAddr", PAddr);
- if( MM_GetPhysAddr( (tVAddr)&gaiPageReferences[page] ) )
+ if( MM_GetPhysAddr( &gaiPageReferences[page] ) )
{
if( gaiPageReferences[page] > 0 )
gaiPageReferences[ page ] --;
else
gaPageBitmaps[ page / 32 ] |= 1 << (page&31);
// Clear node if needed
- if( MM_GetPhysAddr( (tVAddr)&gapPageNodes[page] ) ) {
+ if( MM_GetPhysAddr( &gapPageNodes[page] ) ) {
gapPageNodes[page] = NULL;
// TODO: Catch when all pages in this range are not using nodes
}
if( !MM_GetRefCount(PAddr) ) return 1;
- if( !MM_GetPhysAddr(node_page) ) {
+ if( !MM_GetPhysAddr( (void*)node_page ) ) {
if( !MM_Allocate(node_page) )
return -1;
memset( (void*)node_page, 0, PAGE_SIZE );
if( !MM_GetRefCount(PAddr) ) return 1;
PAddr >>= 12;
- if( !MM_GetPhysAddr( (tVAddr)&gapPageNodes[PAddr] ) ) {
+ if( !MM_GetPhysAddr( &gapPageNodes[PAddr] ) ) {
*Node = NULL;
return 0;
}
LEAVE('-');
}
+void MM_DumpStatistics(void)
+{
+ // TODO: PM Statistics for tpl_mm_phys_bitmap
+}
+
/**
* \brief Allocate a contiguous range of physical pages with a maximum
* bit size of \a MaxBits
#define _VFS_H
#include <acess.h>
+#include <mutex.h>
/**
* \brief Thread list datatype for VFS_Select
* is unmapped. Nice for read-only files and memory-only files (or
* pseudo-readonly filesystems)
*/
-#define VFS_FFLAG_NOWRITEBACK
+#define VFS_FFLAG_NOWRITEBACK 0x1000
+
+/**
+ * \brief "Dirty Metadata" Flag
+ *
+ * Indicates that the node's metadata has been altered since the flag was last
+ * cleared. Tells the driver that it should update the inode at the next flush.
+ */
+#define VFS_FFLAG_DIRTY 0x8000
/**
* \}
*/
*/
typedef struct sVFS_Node
{
+ /**
+ * \brief Functions associated with the node
+ */
+ tVFS_NodeType *Type;
+
/**
* \name Identifiers
* \brief Fields used by the driver to identify what data this node
/**
* \}
*/
-
- /**
- * \brief Functions associated with the node
- */
- tVFS_NodeType *Type;
} tVFS_Node;
/**
* \brief Read from a directory
* \param Node Pointer to this node
* \param Pos Offset in the directory
- * \return Pointer to the name of the item on the heap (will be freed
- * by the caller). If the directory end has been reached, NULL
- * will be returned.
- * If an item is required to be skipped either &::NULLNode,
- * ::VFS_SKIP or ::VFS_SKIPN(0...1023) will be returned.
+ * \param Dest Destination for filename
+ * \return Zero on success, negative on error or +ve for ignore entry
*/
- char *(*ReadDir)(struct sVFS_Node *Node, int Pos);
+ int (*ReadDir)(struct sVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
/**
* \brief Create a node in a directory
* \param Node Pointer to this node
* \param Name Name of the new child
* \param Flags Flags to apply to the new child (directory or symlink)
- * \return Zero on Success, non-zero on error (see errno.h)
+ * \return Created node or NULL on error
*/
- int (*MkNod)(struct sVFS_Node *Node, const char *Name, Uint Flags);
+ tVFS_Node *(*MkNod)(struct sVFS_Node *Node, const char *Name, Uint Flags);
/**
* \brief Relink (Rename/Remove) a file/directory
* \param Node Pointer to this node
* \param OldName Name of the item to move/delete
- * \param NewName New name (or NULL if unlinking is wanted)
* \return Zero on Success, non-zero on error (see errno.h)
*/
- int (*Relink)(struct sVFS_Node *Node, const char *OldName, const char *NewName);
+ int (*Unlink)(struct sVFS_Node *Node, const char *OldName);
/**
* \brief Link a node to a name
* \param Node Pointer to this node (directory)
- * \param Child Node to create a new link to
* \param NewName Name for the new link
+ * \param Child Node to create a new link to
* \retur Zeron on success, non-zero on error (see errno.h)
*/
- int (*Link)(struct sVFS_Node *Node, struct sVFS_Node *Child, const char *NewName);
+ int (*Link)(struct sVFS_Node *Node, const char *NewName, struct sVFS_Node *Child);
/**
* \}
*/
Uint Flags;
+ /**
+ * \brief Detect if a volume is accessible using this driver
+ * \return Boolean success (with higher numbers being higher priority)
+ *
+ * E.g. FAT would return 1 as it's the lowest common denominator while ext2 might return 2,
+ * because it can be embedded in a FAT volume (and is a more fully featured filesystem).
+ */
+ int (*Detect)(int FD);
+
/**
* \brief Callback to mount a device
*/
* \brief Dereferences (and removes if needed) a node from the cache
* \param Handle A handle returned by Inode_GetHandle()
* \param Inode Value of the Inode field of the ::tVFS_Node you want to remove
+ * \return -1: Error (not present), 0: Not freed, 1: Freed
*/
-extern void Inode_UncacheNode(int Handle, Uint64 Inode);
+extern int Inode_UncacheNode(int Handle, Uint64 Inode);
/**
* \fn void Inode_ClearCache(int Handle)
* \brief Clears the cache for a handle
typedef Uint32 tMount;
// === CONSTANTS ===
+#define FILENAME_MAX 256
//! Maximum size of a Memory Path generated by VFS_GetMemPath
#define VFS_MEMPATH_SIZE (3 + (BITS/4)*2)
/**
#define VFS_OPENFLAG_NOLINK 0x40
//! Create the file if it doesn't exist
#define VFS_OPENFLAG_CREATE 0x80
+//! Treat as a directory
+#define VFS_OPENFLAG_DIRECTORY 0x100
//! Open as a user
#define VFS_OPENFLAG_USER 0x8000
/**
* \param Buffer Destination of read data
* \return Number of read bytes
*/
-extern Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer);
+extern size_t VFS_Read(int FD, size_t Length, void *Buffer);
/**
* \brief Writes data to a file
* \param FD File handle returned by ::VFS_Open
* \param Buffer Source of written data
* \return Number of bytes written
*/
-extern Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer);
+extern size_t VFS_Write(int FD, size_t Length, const void *Buffer);
/**
* \brief Reads from a specific offset in the file
* \param Buffer Source of read data
* \return Number of bytes read
*/
-extern Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer);
+extern size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer);
/**
* \brief Writes to a specific offset in the file
* \param FD File handle returned by ::VFS_Open
* \param Buffer Source of written data
* \return Number of bytes written
*/
-extern Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer);
+extern size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer);
/**
* \brief Sends an IOCtl request to the driver
* \return 1 on succes, -1 on error
*/
extern int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
+/**
+ * \brief Unmount a mounted filesystem
+ * \param Mountpoint Location of the mount
+ * \return 0 on success, errno on error
+ */
+extern int VFS_Unmount(const char *Mountpoint);
+/**
+ * \brief Attemt to unmount all fileystems
+ * \return Number of unmounted filesytems, -1 if none left to unmount
+ * \note Can return 0 when there are stil volumes mounted if there are open handles
+ */
+extern int VFS_UnmountAll(void);
+
/**
* \brief Create a new directory
* \param Path Path to new directory (absolute or relative)
/**
* \brief Read from a directory
* \param FD File handle returned by ::VFS_Open
- * \param Dest Destination array for the file name (max 255 bytes)
+ * \param Dest Destination array for the file name (max FILENAME_MAX bytes)
* \return Boolean Success
*/
-extern int VFS_ReadDir(int FD, char *Dest);
+extern int VFS_ReadDir(int FD, char Dest[FILENAME_MAX]);
/**
* \brief Wait for an aciton on a file descriptor
* \param MaxHandle Maximum set handle in \a *Handles
#define _VFS_INT_H
#include "vfs.h"
+#include <rwlock.h>
// === TYPES ===
typedef struct sVFS_Mount {
char *Options;
tVFS_Driver *Filesystem;
tVFS_Node *RootNode;
+
+ int OpenHandleCount;
+
char StrData[];
} tVFS_Mount;
} tVFS_MMapPage;
// === GLOBALS ===
+extern tRWLock glVFS_MountList;
extern tVFS_Mount *gVFS_Mounts;
+extern tVFS_Driver *gVFS_Drivers;
// === PROTOTYPES ===
+extern void VFS_Deinit(void);
// --- open.c ---
extern char *VFS_GetAbsPath(const char *Path);
extern tVFS_Node *VFS_ParsePath(const char *Path, char **TruePath, tVFS_Mount **MountPoint);
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * virtual_pci.h
+ * - Virtual PCI bus definitions
+ */
+#ifndef _VIRTUAL_PCI_H_
+#define _VIRTUAL_PCI_H_
+#include <acess.h>
+
+typedef struct sVPCI_Device tVPCI_Device;
+
+struct sVPCI_Device
+{
+ void *Ptr;
+
+ // Vendor/Device is defined at runtime as 0x0ACE:0x[ARCH][ARCH][IDX][IDX]
+ Uint16 Vendor;
+ Uint16 Device;
+ // Class code (Class, Subclass, Programming Interface, Revision)
+ Uint32 Class;
+
+ Uint32 BARs[6];
+ Uint8 IRQ;
+
+ /**
+ * \param Ptr Value in sVPCI_Device.Ptr
+ * \param Data Data to write to the specified address
+ */
+ void (*Write)(void *Ptr, Uint8 DWord, Uint32 Data);
+ Uint32 (*Read)(void *Ptr, Uint8 DWord);
+};
+
+extern int giVPCI_DeviceCount;
+extern tVPCI_Device gaVPCI_Devices[];
+
+extern Uint32 VPCI_Read(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size);
+extern void VPCI_Write(tVPCI_Device *Dev, Uint8 Offset, Uint8 Size, Uint32 Data);
+#endif
+
* Common Library Functions
*/
#include <acess.h>
-#include <hal_proc.h>
// === CONSTANTS ===
-#define RANDOM_SEED 0xACE55052
-#define RANDOM_A 0x00731ADE
-#define RANDOM_C 12345
-#define RANDOM_SPRUCE 0xf12b039
// Jan Feb Mar Apr May Jun Jul Aug Sept Oct Nov Dec
const short DAYS_BEFORE[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
#define UNIX_TO_2K ((30*365*3600*24) + (7*3600*24)) //Normal years + leap years
// === PROTOTYPES ===
#if 0
- int atoi(const char *string);
- int ParseInt(const char *string, int *Val);
-void itoa(char *buf, Uint64 num, int base, int minLength, char pad);
- int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
- int snprintf(char *__s, size_t __n, const char *__format, ...);
- int sprintf(char *__s, const char *__format, ...);
-#endif
- int tolower(int c);
-#if 0
- int strucmp(const char *Str1, const char *Str2);
-char *strchr(const char *__s, int __c);
- int strpos(const char *Str, char Ch);
Uint8 ByteSum(void *Ptr, int Size);
-size_t strlen(const char *__s);
-char *strcpy(char *__str1, const char *__str2);
-char *strncpy(char *__str1, const char *__str2, size_t max);
- int strcmp(const char *str1, const char *str2);
- int strncmp(const char *str1, const char *str2, size_t num);
-char *_strdup(const char *File, int Line, const char *Str);
char **str_split(const char *__str, char __ch);
int strpos8(const char *str, Uint32 Search);
int ReadUTF8(Uint8 *str, Uint32 *Val);
int DivUp(int num, int dem);
Sint64 timestamp(int sec, int mins, int hrs, int day, int month, int year);
void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
- int rand(void);
-
- int CheckString(char *String);
- int CheckMem(void *Mem, int NumBytes);
int ModUtil_LookupString(char **Array, char *Needle);
int ModUtil_SetIdent(char *Dest, char *Value);
int Hex(char *Dest, size_t Size, const Uint8 *SourceData);
int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString);
+
+Uint16 SwapEndian16(Uint16 Val);
+Uint32 SwapEndian32(Uint16 Val);
+Uint64 SwapEndian64(Uint16 Val);
#endif
// === EXPORTS ===
-EXPORT(atoi);
-EXPORT(itoa);
-EXPORT(vsnprintf);
-EXPORT(snprintf);
-EXPORT(sprintf);
-EXPORT(tolower);
-EXPORT(strucmp);
-EXPORT(strchr);
-EXPORT(strpos);
EXPORT(ByteSum);
-EXPORT(strlen);
-EXPORT(strcpy);
-EXPORT(strncpy);
-EXPORT(strcat);
-EXPORT(strncat);
-EXPORT(strcmp);
-EXPORT(strncmp);
-//EXPORT(strdup);
-EXPORT(_strdup); // Takes File/Line too
EXPORT(str_split);
EXPORT(strpos8);
EXPORT(DivUp);
EXPORT(ReadUTF8);
EXPORT(WriteUTF8);
EXPORT(timestamp);
-EXPORT(CheckString);
-EXPORT(CheckMem);
EXPORT(ModUtil_LookupString);
EXPORT(ModUtil_SetIdent);
+EXPORT(Hex);
EXPORT(UnHex);
EXPORT(SwapEndian16);
EXPORT(SwapEndian32);
-EXPORT(memmove);
+EXPORT(SwapEndian64);
// === CODE ===
-/**
- * \brief Convert a string into an integer
- */
-int atoi(const char *string)
-{
- int ret = 0;
- ParseInt(string, &ret);
- return ret;
-}
-int ParseInt(const char *string, int *Val)
-{
- int ret = 0;
- int bNeg = 0;
- const char *orig_string = string;
-
- //Log("atoi: (string='%s')", string);
-
- // Clear non-numeric characters
- while( !('0' <= *string && *string <= '9') && *string != '-' ) string++;
- if( *string == '-' ) {
- bNeg = 1;
- while( !('0' <= *string && *string <= '9') ) string++;
- }
-
- if(*string == '0')
- {
- string ++;
- if(*string == 'x')
- {
- // Hex
- string ++;
- for( ;; string ++ )
- {
- if('0' <= *string && *string <= '9') {
- ret *= 16;
- ret += *string - '0';
- }
- else if('A' <= *string && *string <= 'F') {
- ret *= 16;
- ret += *string - 'A' + 10;
- }
- else if('a' <= *string && *string <= 'f') {
- ret *= 16;
- ret += *string - 'a' + 10;
- }
- else
- break;
- }
- }
- else // Octal
- {
- for( ; '0' <= *string && *string <= '7'; string ++ )
- {
- ret *= 8;
- ret += *string - '0';
- }
- }
- }
- else // Decimal
- {
- for( ; '0' <= *string && *string <= '9'; string++)
- {
- ret *= 10;
- ret += *string - '0';
- }
- // Error check
- if( ret == 0 ) return 0;
- }
-
- if(bNeg) ret = -ret;
-
- //Log("atoi: RETURN %i", ret);
-
- if(Val) *Val = ret;
-
- return string - orig_string;
-}
-
-static const char cUCDIGITS[] = "0123456789ABCDEF";
-/**
- * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
- * \brief Convert an integer into a character string
- */
-void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
-{
- char tmpBuf[64+1];
- int pos=0, i;
- Uint64 rem;
-
- // Sanity check
- if(!buf) return;
-
- // Sanity Check
- if(base > 16 || base < 2) {
- buf[0] = 0;
- return;
- }
-
- // Convert
- while(num > base-1) {
- num = DivMod64U(num, base, &rem); // Shift `num` and get remainder
- tmpBuf[pos] = cUCDIGITS[ rem ];
- pos++;
- }
- tmpBuf[pos++] = cUCDIGITS[ num ]; // Last digit of `num`
-
- // Put in reverse
- i = 0;
- minLength -= pos;
- while(minLength-- > 0) buf[i++] = pad;
- while(pos-- > 0) buf[i++] = tmpBuf[pos]; // Reverse the order of characters
- buf[i] = 0;
-}
-
-/**
- * \brief Append a character the the vsnprintf output
- */
-#define PUTCH(c) _putch(c)
-#define GETVAL() do {\
- if(isLongLong) val = va_arg(args, Uint64);\
- else val = va_arg(args, unsigned int);\
- }while(0)
-/**
- * \brief VArg String Number Print Formatted
- */
-int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
-{
- char c, pad = ' ';
- int minSize = 0, precision = -1, len;
- char tmpBuf[34]; // For Integers
- const char *p = NULL;
- int isLongLong = 0;
- Uint64 val;
- size_t pos = 0;
- // Flags
- int bPadLeft = 0;
-
- auto void _putch(char ch);
-
- void _putch(char ch)
- {
- if(pos < __maxlen)
- {
- if(__s) __s[pos] = ch;
- pos ++;
- }
- }
-
- while((c = *__format++) != 0)
- {
- // Non control character
- if(c != '%') { PUTCH(c); continue; }
-
- c = *__format++;
- if(c == '\0') break;
-
- // Literal %
- if(c == '%') { PUTCH('%'); continue; }
-
- // Pointer - Done first for debugging
- if(c == 'p') {
- Uint ptr = va_arg(args, Uint);
- PUTCH('*'); PUTCH('0'); PUTCH('x');
- for( len = BITS/4; len --; )
- PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
- continue ;
- }
-
- // - Padding Side Flag
- if(c == '-') {
- bPadLeft = 1;
- c = *__format++;
- }
-
- // - Padding
- if(c == '0') {
- pad = '0';
- c = *__format++;
- }
- else
- pad = ' ';
-
- // - Minimum length
- if(c == '*') { // Dynamic length
- minSize = va_arg(args, unsigned int);
- c = *__format++;
- }
- else if('1' <= c && c <= '9')
- {
- minSize = 0;
- while('0' <= c && c <= '9')
- {
- minSize *= 10;
- minSize += c - '0';
- c = *__format++;
- }
- }
- else
- minSize = 0;
-
- // - Precision
- precision = -1;
- if( c == '.' ) {
- c = *__format++;
-
- if(c == '*') { // Dynamic length
- precision = va_arg(args, unsigned int);
- c = *__format++;
- }
- else if('1' <= c && c <= '9')
- {
- precision = 0;
- while('0' <= c && c <= '9')
- {
- precision *= 10;
- precision += c - '0';
- c = *__format++;
- }
- }
- }
-
- // - Default, Long or LongLong?
- isLongLong = 0;
- if(c == 'l') // Long is actually the default on x86
- {
- c = *__format++;
- if(c == 'l') {
- c = *__format++;
- isLongLong = 1;
- }
- }
-
- // - Now get the format code
- p = tmpBuf;
- switch(c)
- {
- case 'd':
- case 'i':
- GETVAL();
- if( isLongLong && val >> 63 ) {
- PUTCH('-');
- val = -val;
- }
- else if( !isLongLong && val >> 31 ) {
- PUTCH('-');
- val = -(Sint32)val;
- }
- itoa(tmpBuf, val, 10, minSize, pad);
- goto printString;
- case 'u': // Unsigned
- GETVAL();
- itoa(tmpBuf, val, 10, minSize, pad);
- goto printString;
- case 'P': // Physical Address
- PUTCH('0');
- PUTCH('x');
- if(sizeof(tPAddr) > 4) isLongLong = 1;
- GETVAL();
- itoa(tmpBuf, val, 16, minSize, pad);
- goto printString;
- case 'X': // Hex
- if(BITS == 64)
- isLongLong = 1; // TODO: Handle non-x86 64-bit archs
- GETVAL();
- itoa(tmpBuf, val, 16, minSize, pad);
- goto printString;
-
- case 'x': // Lower case hex
- GETVAL();
- itoa(tmpBuf, val, 16, minSize, pad);
- goto printString;
- case 'o': // Octal
- GETVAL();
- itoa(tmpBuf, val, 8, minSize, pad);
- goto printString;
- case 'b':
- GETVAL();
- itoa(tmpBuf, val, 2, minSize, pad);
- goto printString;
-
- case 'B': //Boolean
- val = va_arg(args, unsigned int);
- if(val) p = "True";
- else p = "False";
- goto printString;
-
- // String - Null Terminated Array
- case 's':
- p = va_arg(args, char*); // Get Argument
- if( !p || !CheckString(p) ) p = "(inval)"; // Avoid #PFs
- printString:
- if(!p) p = "(null)";
- len = strlen(p);
- if( !bPadLeft ) while(len++ < minSize) PUTCH(pad);
- while(*p && precision--) PUTCH(*p++);
- if( bPadLeft ) while(len++ < minSize) PUTCH(pad);
- break;
-
- case 'C': // Non-Null Terminated Character Array
- p = va_arg(args, char*);
- if( !CheckMem(p, minSize) ) continue; // No #PFs please
- if(!p) goto printString;
- while(minSize--) PUTCH(*p++);
- break;
-
- // Single Character
- case 'c':
- default:
- GETVAL();
- PUTCH( (Uint8)val );
- break;
- }
- }
-
- if(__s && pos != __maxlen)
- __s[pos] = '\0';
-
- return pos;
-}
-#undef PUTCH
-
-/**
- */
-int snprintf(char *__s, size_t __n, const char *__format, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, __format);
- ret = vsnprintf(__s, __n, __format, args);
- va_end(args);
-
- return ret;
-}
-
-/**
- */
-int sprintf(char *__s, const char *__format, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, __format);
- ret = vsnprintf(__s, -1, __format, args);
- va_end(args);
-
- return ret;
-}
-
-/**
- * \fn int tolower(int c)
- * \brief Converts a character to lower case
- */
-int tolower(int c)
-{
- if('A' <= c && c <= 'Z')
- return c - 'A' + 'a';
- return c;
-}
-
-/**
- * \fn int strucmp(const char *Str1, const char *Str2)
- * \brief Compare \a Str1 and \a Str2 case-insensitively
- */
-int strucmp(const char *Str1, const char *Str2)
-{
- while(*Str1 && tolower(*Str1) == tolower(*Str2))
- Str1++, Str2++;
- return tolower(*Str1) - tolower(*Str2);
-}
-
-/**
- * \brief Locate a byte in a string
- */
-char *strchr(const char *__s, int __c)
-{
- for( ; *__s; __s ++ )
- {
- if( *__s == __c ) return (char*)__s;
- }
- return NULL;
-}
-
-/**
- * \fn int strpos(const char *Str, char Ch)
- * \brief Search a string for an ascii character
- */
-int strpos(const char *Str, char Ch)
-{
- int pos;
- for(pos=0;Str[pos];pos++)
- {
- if(Str[pos] == Ch) return pos;
- }
- return -1;
-}
-
/**
* \fn Uint8 ByteSum(void *Ptr, int Size)
* \brief Adds the bytes in a memory region and returns the sum
return sum;
}
-/**
- * \fn size_t strlen(const char *__str)
- * \brief Get the length of string
- */
-size_t strlen(const char *__str)
-{
- size_t ret = 0;
- while(*__str++) ret++;
- return ret;
-}
-
-/**
- * \brief Copy a string to a new location
- */
-char *strcpy(char *__str1, const char *__str2)
-{
- while(*__str2)
- *__str1++ = *__str2++;
- *__str1 = '\0'; // Terminate String
- return __str1;
-}
-
-/**
- * \brief Copy a string to a new location
- * \note Copies at most `max` chars
- */
-char *strncpy(char *__str1, const char *__str2, size_t __max)
-{
- while(*__str2 && __max-- >= 1)
- *__str1++ = *__str2++;
- if(__max)
- *__str1 = '\0'; // Terminate String
- return __str1;
-}
-
-/**
- * \brief Append a string to another
- */
-char *strcat(char *__dest, const char *__src)
-{
- while(*__dest++);
- __dest--;
- while(*__src)
- *__dest++ = *__src++;
- *__dest = '\0';
- return __dest;
-}
-
-/**
- * \brief Append at most \a n chars to a string from another
- * \note At most n+1 chars are written (the dest is always zero terminated)
- */
-char *strncat(char *__dest, const char *__src, size_t n)
-{
- while(*__dest++);
- while(*__src && n-- >= 1)
- *__dest++ = *__src++;
- *__dest = '\0';
- return __dest;
-}
-
-/**
- * \fn int strcmp(const char *str1, const char *str2)
- * \brief Compare two strings return the difference between
- * the first non-matching characters.
- */
-int strcmp(const char *str1, const char *str2)
-{
- while(*str1 && *str1 == *str2)
- str1++, str2++;
- return *str1 - *str2;
-}
-
-/**
- * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
- * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
- */
-int strncmp(const char *Str1, const char *Str2, size_t num)
-{
- if(num == 0) return 0; // TODO: Check what should officially happen here
- while(--num && *Str1 && *Str1 == *Str2)
- Str1++, Str2++;
- return *Str1-*Str2;
-}
-
-#if 0
-/**
- * \fn char *strdup(const char *Str)
- * \brief Duplicates a string
- */
-char *strdup(const char *Str)
-{
- char *ret;
- ret = malloc(strlen(Str)+1);
- if( !ret ) return NULL;
- strcpy(ret, Str);
- return ret;
-}
-#else
-
-/**
- * \fn char *_strdup(const char *File, int Line, const char *Str)
- * \brief Duplicates a string
- */
-char *_strdup(const char *File, int Line, const char *Str)
-{
- char *ret;
- ret = Heap_Allocate(File, Line, strlen(Str)+1);
- if( !ret ) return NULL;
- strcpy(ret, Str);
- return ret;
-}
-#endif
-
/**
* \brief Split a string using the passed character
* \return NULL terminated array of strings on the heap
{
// ASCII Range
if(Search < 128) {
- if(str[pos] == Search) return pos;
+ if(str[pos] == (char)Search) return pos;
continue;
}
if(*(Uint8*)(str+pos) < 128) continue;
*/
int ReadUTF8(const Uint8 *str, Uint32 *Val)
{
+ Uint32 outval;
+
*Val = 0xFFFD; // Assume invalid character
// ASCII
// Two Byte
if( (*str & 0xE0) == 0xC0 ) {
- *Val = (*str & 0x1F) << 6; // Upper 6 Bits
+ outval = (*str & 0x1F) << 6; // Upper 6 Bits
str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F); // Lower 6 Bits
+ if( (*str & 0xC0) != 0x80) return 2; // Validity check
+ outval |= (*str & 0x3F); // Lower 6 Bits
+ *Val = outval;
return 2;
}
// Three Byte
if( (*str & 0xF0) == 0xE0 ) {
- *Val = (*str & 0x0F) << 12; // Upper 4 Bits
+ outval = (*str & 0x0F) << 12; // Upper 4 Bits
str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F) << 6; // Middle 6 Bits
+ if( (*str & 0xC0) != 0x80) return 2; // Validity check
+ outval |= (*str & 0x3F) << 6; // Middle 6 Bits
str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F); // Lower 6 Bits
+ if( (*str & 0xC0) != 0x80) return 3; // Validity check
+ outval |= (*str & 0x3F); // Lower 6 Bits
+ *Val = outval;
return 3;
}
// Four Byte
if( (*str & 0xF1) == 0xF0 ) {
- *Val = (*str & 0x07) << 18; // Upper 3 Bits
+ outval = (*str & 0x07) << 18; // Upper 3 Bits
str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F) << 12; // Middle-upper 6 Bits
+ if( (*str & 0xC0) != 0x80) return 2; // Validity check
+ outval |= (*str & 0x3F) << 12; // Middle-upper 6 Bits
str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F) << 6; // Middle-lower 6 Bits
+ if( (*str & 0xC0) != 0x80) return 3; // Validity check
+ outval |= (*str & 0x3F) << 6; // Middle-lower 6 Bits
str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F); // Lower 6 Bits
+ if( (*str & 0xC0) != 0x80) return 4; // Validity check
+ outval |= (*str & 0x3F); // Lower 6 Bits
+ *Val = outval;
return 4;
}
*day += TS; // Plus offset from leap handling above
}
-/**
- * \fn int rand()
- * \brief Pseudo random number generator
- */
-int rand(void)
-{
- #if 0
- static Uint state = RANDOM_SEED;
- Uint old = state;
- // Get the next state value
- giRandomState = (RANDOM_A*state + RANDOM_C);
- // Check if it has changed, and if it hasn't, change it
- if(state == old) state += RANDOM_SPRUCE;
- return state;
- #else
- // http://en.wikipedia.org/wiki/Xorshift
- // 2010-10-03
- static Uint32 x = 123456789;
- static Uint32 y = 362436069;
- static Uint32 z = 521288629;
- static Uint32 w = 88675123;
- Uint32 t;
-
- t = x ^ (x << 11);
- x = y; y = z; z = w;
- return w = w ^ (w >> 19) ^ t ^ (t >> 8);
- #endif
-}
-
-/* *
- * \name Memory Validation
- * \{
- */
-/**
- * \brief Checks if a string resides fully in valid memory
- */
-int CheckString(const char *String)
-{
- tVAddr addr;
- int bUser;
-
- addr = (tVAddr)String;
-
- if( !MM_GetPhysAddr( addr ) )
- return 0;
-
- // Check 1st page
- bUser = MM_IsUser( addr );
-
- while( *(char*)addr )
- {
- if( (addr & (PAGE_SIZE-1)) == 0 )
- {
- if(bUser && !MM_IsUser(addr) )
- return 0;
- if(!bUser && !MM_GetPhysAddr(addr) )
- return 0;
- }
- addr ++;
- }
- return 1;
-}
-
-/**
- * \brief Check if a sized memory region is valid memory
- * \return Boolean success
- */
-int CheckMem(const void *Mem, int NumBytes)
-{
- return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
-}
-/* *
- * \}
- */
-
/**
* \brief Search a string array for \a Needle
* \note Helper function for eTplDrv_IOCtl::DRV_IOCTL_LOOKUP
int Hex(char *Dest, size_t Size, const Uint8 *SourceData)
{
- int i;
+ size_t i;
for( i = 0; i < Size; i ++ )
{
sprintf(Dest + i*2, "%02x", SourceData[i]);
*/
int UnHex(Uint8 *Dest, size_t DestSize, const char *SourceString)
{
- int i;
-
+ size_t i;
for( i = 0; i < DestSize*2; i += 2 )
{
Uint8 val = 0;
{
return ((Val&0xFF)<<24) | ((Val&0xFF00)<<8) | ((Val>>8)&0xFF00) | ((Val>>24)&0xFF);
}
-
-void *memmove(void *__dest, const void *__src, size_t len)
+Uint64 SwapEndian64(Uint64 Val)
{
- size_t block_size;
- char *dest = __dest;
- const char *src = __src;
- void *ret = __dest;
-
- if( len == 0 || dest == src )
- return dest;
-
- if( (tVAddr)dest > (tVAddr)src + len )
- return memcpy(dest, src, len);
- if( (tVAddr)dest + len < (tVAddr)src )
- return memcpy(dest, src, len);
-
- // NOTE: Assumes memcpy works forward
- if( (tVAddr)dest < (tVAddr)src )
- return memcpy(dest, src, len);
-
- if( (tVAddr)dest < (tVAddr)src )
- block_size = (tVAddr)src - (tVAddr)dest;
- else
- block_size = (tVAddr)dest - (tVAddr)src;
-
- block_size &= ~0xF;
-
- while(len >= block_size)
- {
- memcpy(dest, src, block_size);
- len -= block_size;
- dest += block_size;
- src += block_size;
- }
- memcpy(dest, src, len);
- return ret;
-
+ return SwapEndian32(Val >> 32) | ((Uint64)SwapEndian32(Val) << 32);
}
-
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * libc.c
+ * - Kernel-land C Library
+ */
+#include <acess.h>
+#include <hal_proc.h> // For MM_*
+
+// === CONSTANTS ===
+#define RANDOM_SEED 0xACE55052
+#define RANDOM_A 0x00731ADE
+#define RANDOM_C 12345
+#define RANDOM_SPRUCE 0xf12b039
+
+// === PROTOTYPES ===
+#if 0
+ int atoi(const char *string);
+ int ParseInt(const char *string, int *Val);
+void itoa(char *buf, Uint64 num, int base, int minLength, char pad);
+ int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args);
+ int snprintf(char *__s, size_t __n, const char *__format, ...);
+ int sprintf(char *__s, const char *__format, ...);
+ int strucmp(const char *Str1, const char *Str2);
+char *strchr(const char *__s, int __c);
+ int strpos(const char *Str, char Ch);
+size_t strlen(const char *__s);
+char *strcpy(char *__str1, const char *__str2);
+char *strncpy(char *__str1, const char *__str2, size_t max);
+char *strcat(char *dest, const char *source);
+ int strcmp(const char *str1, const char *str2);
+ int strncmp(const char *str1, const char *str2, size_t num);
+char *_strdup(const char *File, int Line, const char *Str);
+ int rand(void);
+void *memmove(void *__dest, const void *__src, size_t len);
+
+ int CheckString(char *String);
+ int CheckMem(void *Mem, int NumBytes);
+#endif
+
+// === EXPORTS ===
+EXPORT(atoi);
+EXPORT(itoa);
+EXPORT(vsnprintf);
+EXPORT(snprintf);
+EXPORT(sprintf);
+EXPORT(tolower);
+
+EXPORT(strucmp);
+EXPORT(strchr);
+EXPORT(strrchr);
+EXPORT(strpos);
+EXPORT(strlen);
+EXPORT(strcpy);
+EXPORT(strncpy);
+EXPORT(strcat);
+EXPORT(strncat);
+EXPORT(strcmp);
+EXPORT(strncmp);
+//EXPORT(strdup);
+EXPORT(_strdup); // Takes File/Line too
+EXPORT(rand);
+EXPORT(memmove);
+
+EXPORT(CheckString);
+EXPORT(CheckMem);
+
+// === CODE ===
+/**
+ * \brief Convert a string into an integer
+ */
+int atoi(const char *string)
+{
+ int ret = 0;
+ ParseInt(string, &ret);
+ return ret;
+}
+int ParseInt(const char *string, int *Val)
+{
+ int ret = 0;
+ int bNeg = 0;
+ const char *orig_string = string;
+
+ //Log("atoi: (string='%s')", string);
+
+ // Clear non-numeric characters
+ while( !('0' <= *string && *string <= '9') && *string != '-' ) string++;
+ if( *string == '-' ) {
+ bNeg = 1;
+ while( !('0' <= *string && *string <= '9') ) string++;
+ }
+
+ if(*string == '0')
+ {
+ string ++;
+ if(*string == 'x')
+ {
+ // Hex
+ string ++;
+ for( ;; string ++ )
+ {
+ if('0' <= *string && *string <= '9') {
+ ret *= 16;
+ ret += *string - '0';
+ }
+ else if('A' <= *string && *string <= 'F') {
+ ret *= 16;
+ ret += *string - 'A' + 10;
+ }
+ else if('a' <= *string && *string <= 'f') {
+ ret *= 16;
+ ret += *string - 'a' + 10;
+ }
+ else
+ break;
+ }
+ }
+ else // Octal
+ {
+ for( ; '0' <= *string && *string <= '7'; string ++ )
+ {
+ ret *= 8;
+ ret += *string - '0';
+ }
+ }
+ }
+ else // Decimal
+ {
+ for( ; '0' <= *string && *string <= '9'; string++)
+ {
+ ret *= 10;
+ ret += *string - '0';
+ }
+ // Error check
+ if( ret == 0 ) return 0;
+ }
+
+ if(bNeg) ret = -ret;
+
+ //Log("atoi: RETURN %i", ret);
+
+ if(Val) *Val = ret;
+
+ return string - orig_string;
+}
+
+static const char cUCDIGITS[] = "0123456789ABCDEF";
+/**
+ * \fn void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
+ * \brief Convert an integer into a character string
+ */
+void itoa(char *buf, Uint64 num, int base, int minLength, char pad)
+{
+ char tmpBuf[64+1];
+ int pos=0, i;
+ Uint64 rem;
+
+ // Sanity check
+ if(!buf) return;
+
+ // Sanity Check
+ if(base > 16 || base < 2) {
+ buf[0] = 0;
+ return;
+ }
+
+ // Convert
+ while(num > base-1) {
+ num = DivMod64U(num, base, &rem); // Shift `num` and get remainder
+ tmpBuf[pos] = cUCDIGITS[ rem ];
+ pos++;
+ }
+ tmpBuf[pos++] = cUCDIGITS[ num ]; // Last digit of `num`
+
+ // Put in reverse
+ i = 0;
+ minLength -= pos;
+ while(minLength-- > 0) buf[i++] = pad;
+ while(pos-- > 0) buf[i++] = tmpBuf[pos]; // Reverse the order of characters
+ buf[i] = 0;
+}
+
+/**
+ * \brief Append a character the the vsnprintf output
+ */
+#define PUTCH(c) _putch(c)
+#define GETVAL() do {\
+ if(isLongLong) val = va_arg(args, Uint64);\
+ else val = va_arg(args, unsigned int);\
+ }while(0)
+/**
+ * \brief VArg String Number Print Formatted
+ */
+int vsnprintf(char *__s, size_t __maxlen, const char *__format, va_list args)
+{
+ char c, pad = ' ';
+ int minSize = 0, precision = -1, len;
+ char tmpBuf[34]; // For Integers
+ const char *p = NULL;
+ int isLongLong = 0;
+ Uint64 val;
+ size_t pos = 0;
+ // Flags
+ int bPadLeft = 0;
+
+ auto void _putch(char ch);
+
+ void _putch(char ch)
+ {
+ if(pos < __maxlen)
+ {
+ if(__s) __s[pos] = ch;
+ }
+ pos ++;
+ }
+
+ while((c = *__format++) != 0)
+ {
+ // Non control character
+ if(c != '%') { PUTCH(c); continue; }
+
+ c = *__format++;
+ if(c == '\0') break;
+
+ // Literal %
+ if(c == '%') { PUTCH('%'); continue; }
+
+ // Pointer - Done first for debugging
+ if(c == 'p') {
+ Uint ptr = va_arg(args, Uint);
+ PUTCH('*'); PUTCH('0'); PUTCH('x');
+ for( len = BITS/4; len --; )
+ PUTCH( cUCDIGITS[ (ptr>>(len*4))&15 ] );
+ continue ;
+ }
+
+ // - Padding Side Flag
+ if(c == '-') {
+ bPadLeft = 1;
+ c = *__format++;
+ }
+
+ // - Padding
+ if(c == '0') {
+ pad = '0';
+ c = *__format++;
+ }
+ else
+ pad = ' ';
+
+ // - Minimum length
+ if(c == '*') { // Dynamic length
+ minSize = va_arg(args, unsigned int);
+ c = *__format++;
+ }
+ else if('1' <= c && c <= '9')
+ {
+ minSize = 0;
+ while('0' <= c && c <= '9')
+ {
+ minSize *= 10;
+ minSize += c - '0';
+ c = *__format++;
+ }
+ }
+ else
+ minSize = 0;
+
+ // - Precision
+ precision = -1;
+ if( c == '.' ) {
+ c = *__format++;
+
+ if(c == '*') { // Dynamic length
+ precision = va_arg(args, unsigned int);
+ c = *__format++;
+ }
+ else if('1' <= c && c <= '9')
+ {
+ precision = 0;
+ while('0' <= c && c <= '9')
+ {
+ precision *= 10;
+ precision += c - '0';
+ c = *__format++;
+ }
+ }
+ }
+
+ // - Default, Long or LongLong?
+ isLongLong = 0;
+ if(c == 'l') // Long is actually the default on x86
+ {
+ c = *__format++;
+ if(c == 'l') {
+ c = *__format++;
+ isLongLong = 1;
+ }
+ }
+
+ // - Now get the format code
+ p = tmpBuf;
+ switch(c)
+ {
+ case 'd':
+ case 'i':
+ GETVAL();
+ if( isLongLong && val >> 63 ) {
+ PUTCH('-');
+ val = -val;
+ }
+ else if( !isLongLong && val >> 31 ) {
+ PUTCH('-');
+ val = -(Sint32)val;
+ }
+ itoa(tmpBuf, val, 10, minSize, pad);
+ goto printString;
+ case 'u': // Unsigned
+ GETVAL();
+ itoa(tmpBuf, val, 10, minSize, pad);
+ goto printString;
+ case 'P': // Physical Address
+ PUTCH('0');
+ PUTCH('x');
+ if(sizeof(tPAddr) > 4) isLongLong = 1;
+ GETVAL();
+ itoa(tmpBuf, val, 16, minSize, pad);
+ goto printString;
+ case 'X': // Hex
+ if(BITS == 64)
+ isLongLong = 1; // TODO: Handle non-x86 64-bit archs
+ GETVAL();
+ itoa(tmpBuf, val, 16, minSize, pad);
+ goto printString;
+
+ case 'x': // Lower case hex
+ GETVAL();
+ itoa(tmpBuf, val, 16, minSize, pad);
+ goto printString;
+ case 'o': // Octal
+ GETVAL();
+ itoa(tmpBuf, val, 8, minSize, pad);
+ goto printString;
+ case 'b':
+ GETVAL();
+ itoa(tmpBuf, val, 2, minSize, pad);
+ goto printString;
+
+ case 'B': //Boolean
+ val = va_arg(args, unsigned int);
+ if(val) p = "True";
+ else p = "False";
+ goto printString;
+
+ // String - Null Terminated Array
+ case 's':
+ p = va_arg(args, char*); // Get Argument
+ if( !p || !CheckString(p) ) p = "(inval)"; // Avoid #PFs
+ printString:
+ if(!p) p = "(null)";
+ len = strlen(p);
+ if( !bPadLeft ) while(len++ < minSize) PUTCH(pad);
+ while(*p && precision--) PUTCH(*p++);
+ if( bPadLeft ) while(len++ < minSize) PUTCH(pad);
+ break;
+
+ case 'C': // Non-Null Terminated Character Array
+ p = va_arg(args, char*);
+ if( !CheckMem(p, minSize) ) continue; // No #PFs please
+ if(!p) goto printString;
+ while(minSize--) PUTCH(*p++);
+ break;
+
+ // Single Character
+ case 'c':
+ default:
+ GETVAL();
+ PUTCH( (Uint8)val );
+ break;
+ }
+ }
+
+ if(__s && pos != __maxlen)
+ __s[pos] = '\0';
+
+ return pos;
+}
+#undef PUTCH
+
+/**
+ */
+int snprintf(char *__s, size_t __n, const char *__format, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, __format);
+ ret = vsnprintf(__s, __n, __format, args);
+ va_end(args);
+
+ return ret;
+}
+
+/**
+ */
+int sprintf(char *__s, const char *__format, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, __format);
+ ret = vsnprintf(__s, -1, __format, args);
+ va_end(args);
+
+ return ret;
+}
+
+/*
+ * ==================
+ * ctype.h
+ * ==================
+ */
+int isalnum(int c)
+{
+ return isalpha(c) || isdigit(c);
+}
+int isalpha(int c)
+{
+ return isupper(c) || islower(c);
+}
+int isascii(int c)
+{
+ return (0 <= c && c < 128);
+}
+int isblank(int c)
+{
+ if(c == '\t') return 1;
+ if(c == ' ') return 1;
+ return 0;
+}
+int iscntrl(int c)
+{
+ // TODO: Check iscntrl
+ if(c < ' ') return 1;
+ return 0;
+}
+int isdigit(int c)
+{
+ return ('0' <= c && c <= '9');
+}
+int isgraph(int c)
+{
+ // TODO: Check isgraph
+ return 0;
+}
+int islower(int c)
+{
+ return ('a' <= c && c <= 'z');
+}
+int isprint(int c)
+{
+ if( ' ' <= c && c <= 0x7F ) return 1;
+ return 0;
+}
+int ispunct(int c)
+{
+ switch(c)
+ {
+ case '.': case ',':
+ case '?': case '!':
+ return 1;
+ default:
+ return 0;
+ }
+}
+int isspace(int c)
+{
+ if(c == ' ') return 1;
+ if(c == '\t') return 1;
+ if(c == '\v') return 1;
+ if(c == '\n') return 1;
+ if(c == '\r') return 1;
+ return 0;
+}
+int isupper(int c)
+{
+ return ('a' <= c && c <= 'z');
+}
+int isxdigit(int c)
+{
+ return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F');
+}
+
+int toupper(int c)
+{
+ if( islower(c) )
+ return c - 0x20;
+ else
+ return c;
+}
+int tolower(int c)
+{
+ if( isupper(c) )
+ return c + 0x20;
+ else
+ return c;
+}
+
+/**
+ * \fn int strucmp(const char *Str1, const char *Str2)
+ * \brief Compare \a Str1 and \a Str2 case-insensitively
+ */
+int strucmp(const char *Str1, const char *Str2)
+{
+ while(*Str1 && tolower(*Str1) == tolower(*Str2))
+ Str1++, Str2++;
+ return tolower(*Str1) - tolower(*Str2);
+}
+
+/**
+ * \brief Locate a byte in a string
+ */
+char *strchr(const char *__s, int __c)
+{
+ for( ; *__s; __s ++ )
+ {
+ if( *__s == __c ) return (char*)__s;
+ }
+ return NULL;
+}
+
+char *strrchr(const char *__s, int __c)
+{
+ size_t ofs = strlen(__s);
+ while(--ofs && __s[ofs] != __c);
+ if( __s[ofs] == __c )
+ return (char*)__s + ofs;
+ return NULL;
+}
+
+/**
+ * \fn int strpos(const char *Str, char Ch)
+ * \brief Search a string for an ascii character
+ */
+int strpos(const char *Str, char Ch)
+{
+ int pos;
+ for(pos=0;Str[pos];pos++)
+ {
+ if(Str[pos] == Ch) return pos;
+ }
+ return -1;
+}
+
+/**
+ * \fn size_t strlen(const char *__str)
+ * \brief Get the length of string
+ */
+size_t strlen(const char *__str)
+{
+ size_t ret = 0;
+ while(*__str++) ret++;
+ return ret;
+}
+
+/**
+ * \brief Copy a string to a new location
+ */
+char *strcpy(char *__str1, const char *__str2)
+{
+ while(*__str2)
+ *__str1++ = *__str2++;
+ *__str1 = '\0'; // Terminate String
+ return __str1;
+}
+
+/**
+ * \brief Copy a string to a new location
+ * \note Copies at most `max` chars
+ */
+char *strncpy(char *__str1, const char *__str2, size_t __max)
+{
+ while(*__str2 && __max-- >= 1)
+ *__str1++ = *__str2++;
+ if(__max)
+ *__str1 = '\0'; // Terminate String
+ return __str1;
+}
+
+/**
+ * \brief Append a string to another
+ */
+char *strcat(char *__dest, const char *__src)
+{
+ while(*__dest++);
+ __dest--;
+ while(*__src)
+ *__dest++ = *__src++;
+ *__dest = '\0';
+ return __dest;
+}
+
+/**
+ * \brief Append at most \a n chars to a string from another
+ * \note At most n+1 chars are written (the dest is always zero terminated)
+ */
+char *strncat(char *__dest, const char *__src, size_t n)
+{
+ while(*__dest++);
+ while(*__src && n-- >= 1)
+ *__dest++ = *__src++;
+ *__dest = '\0';
+ return __dest;
+}
+
+/**
+ * \fn int strcmp(const char *str1, const char *str2)
+ * \brief Compare two strings return the difference between
+ * the first non-matching characters.
+ */
+int strcmp(const char *str1, const char *str2)
+{
+ while(*str1 && *str1 == *str2)
+ str1++, str2++;
+ return *str1 - *str2;
+}
+
+/**
+ * \fn int strncmp(const char *Str1, const char *Str2, size_t num)
+ * \brief Compare strings \a Str1 and \a Str2 to a maximum of \a num characters
+ */
+int strncmp(const char *Str1, const char *Str2, size_t num)
+{
+ if(num == 0) return 0; // TODO: Check what should officially happen here
+ while(--num && *Str1 && *Str1 == *Str2)
+ Str1++, Str2++;
+ return *Str1-*Str2;
+}
+
+#if 0
+/**
+ * \fn char *strdup(const char *Str)
+ * \brief Duplicates a string
+ */
+char *strdup(const char *Str)
+{
+ char *ret;
+ ret = malloc(strlen(Str)+1);
+ if( !ret ) return NULL;
+ strcpy(ret, Str);
+ return ret;
+}
+#else
+
+/**
+ * \fn char *_strdup(const char *File, int Line, const char *Str)
+ * \brief Duplicates a string
+ */
+char *_strdup(const char *File, int Line, const char *Str)
+{
+ char *ret;
+ ret = Heap_Allocate(File, Line, strlen(Str)+1);
+ if( !ret ) return NULL;
+ strcpy(ret, Str);
+ return ret;
+}
+#endif
+
+/**
+ * \fn int rand()
+ * \brief Pseudo random number generator
+ */
+int rand(void)
+{
+ #if 0
+ static Uint state = RANDOM_SEED;
+ Uint old = state;
+ // Get the next state value
+ giRandomState = (RANDOM_A*state + RANDOM_C);
+ // Check if it has changed, and if it hasn't, change it
+ if(state == old) state += RANDOM_SPRUCE;
+ return state;
+ #else
+ // http://en.wikipedia.org/wiki/Xorshift
+ // 2010-10-03
+ static Uint32 x = 123456789;
+ static Uint32 y = 362436069;
+ static Uint32 z = 521288629;
+ static Uint32 w = 88675123;
+ Uint32 t;
+
+ t = x ^ (x << 11);
+ x = y; y = z; z = w;
+ return w = w ^ (w >> 19) ^ t ^ (t >> 8);
+ #endif
+}
+
+void *memmove(void *__dest, const void *__src, size_t len)
+{
+ char *dest = __dest;
+ const char *src = __src;
+ void *ret = __dest;
+
+ if( len == 0 || dest == src )
+ return dest;
+
+ if( (tVAddr)dest > (tVAddr)src + len )
+ return memcpy(dest, src, len);
+ if( (tVAddr)dest + len < (tVAddr)src )
+ return memcpy(dest, src, len);
+
+ // NOTE: Assumes memcpy works forward
+ if( (tVAddr)dest < (tVAddr)src )
+ return memcpy(dest, src, len);
+
+ #if 0
+ size_t block_size;
+ if( (tVAddr)dest < (tVAddr)src )
+ block_size = (tVAddr)src - (tVAddr)dest;
+ else
+ block_size = (tVAddr)dest - (tVAddr)src;
+
+ block_size &= ~0xF;
+
+ while(len >= block_size)
+ {
+ memcpy(dest, src, block_size);
+ len -= block_size;
+ dest += block_size;
+ src += block_size;
+ }
+ memcpy(dest, src, len);
+ return ret;
+ #else
+ for( int i = len; i--; )
+ {
+ dest[i] = src[i];
+ }
+ return ret;
+ #endif
+
+}
+
+// NOTE: Strictly not libc, but lib.c is used by userland code too
+/**
+ * \name Memory Validation
+ * \{
+ */
+/**
+ * \brief Checks if a string resides fully in valid memory
+ */
+int CheckString(const char *String)
+{
+ tVAddr addr;
+ int bUser;
+
+ addr = (tVAddr)String;
+
+ if( !MM_GetPhysAddr( (void*)addr ) )
+ return 0;
+
+ // Check 1st page
+ bUser = MM_IsUser( addr );
+
+ while( *(char*)addr )
+ {
+ if( (addr & (PAGE_SIZE-1)) == 0 )
+ {
+ if(bUser && !MM_IsUser(addr) )
+ return 0;
+ if(!bUser && !MM_GetPhysAddr((void*)addr) )
+ return 0;
+ }
+ addr ++;
+ }
+ return 1;
+}
+
+/**
+ * \brief Check if a sized memory region is valid memory
+ * \return Boolean success
+ */
+int CheckMem(const void *Mem, int NumBytes)
+{
+ return MM_IsValidBuffer( (tVAddr)Mem, NumBytes );
+}
+/* *
+ * \}
+ */
+
// === GLOBALS ===
tShortSpinlock glLogOutput;
-#if USE_RING_BUFFER
+#if CACHE_MESSAGES
+# if USE_RING_BUFFER
Uint8 gaLog_RingBufferData[sizeof(tRingBuffer)+RING_BUFFER_SIZE];
tRingBuffer *gpLog_RingBuffer = (void*)gaLog_RingBufferData;
-#else
+# else
tMutex glLog;
tLogList gLog;
tLogList gLog_Levels[NUM_LOG_LEVELS];
-#endif
+# endif // USE_RING_BUFFER
+#endif // CACHE_MESSAGES
// === CODE ===
/**
*/
void Log_Int_PrintMessage(tLogEntry *Entry)
{
+ if( CPU_HAS_LOCK(&glLogOutput) )
+ return ; // TODO: Error?
SHORTLOCK( &glLogOutput );
LogF("%s%014lli%s [%-8s] %i - %s",
csaLevelColours[Entry->Level],
#define USE_EDI 0
#define USE_UDI 0
+#define MODULE_FLAG_LOADERROR 0x1
// === PROTOTYPES ===
int Module_int_Initialise(tModule *Module, const char *ArgString);
"Module %p (%s) is for another architecture (%i)",
Module, Module->Name, Module->Arch
);
+ LEAVE('i', MODULE_ERR_BADMODULE);
+ return MODULE_ERR_BADMODULE;
+ }
+
+ LOG("Module->Flags = %x", Module->Flags);
+ if(Module->Flags & MODULE_FLAG_LOADERROR ) {
+ Log_Warning("Module", "%s has already attempted to load and encountered errors", Module->Name);
+ LEAVE('i', MODULE_ERR_MISC);
+ return MODULE_ERR_MISC;
}
deps = Module->Dependencies;
Log_Warning("Module", "Unable to load, reason: Miscelanious");
break;
case MODULE_ERR_NOTNEEDED:
- Log_Debug("Module", "Unable to load, reason: Module not needed");
+// Log_Debug("Module", "Unable to load, reason: Module not needed");
break;
case MODULE_ERR_MALLOC:
Log_Warning("Module", "Unable to load, reason: Error in malloc/realloc/calloc, probably not good");
Log_Warning("Module", "Unable to load reason - Unknown code %i", ret);
break;
}
+ Module->Flags |= MODULE_FLAG_LOADERROR;
LEAVE_RET('i', ret);
return ret;
}
{
void *base;
tModule *info;
+ tModuleLoader *loader = NULL;
// Load Binary
base = Binary_LoadKernel(Path);
Log_Warning("Module", "Module_LoadFile - Unable to load '%s'", Path);
return 0;
}
+
+ // TODO: I need a way of relocating the dependencies before everything else, so
+ // they can be resolved before any other link errors
+ if( !Binary_Relocate(base) ) {
+ Log_Warning("Module", "Relocation of module %s failed", Path);
+ Binary_Unload(base);
+ return 0;
+ }
// Check for Acess Driver
if( Binary_FindSymbol(base, "DriverInfo", (Uint*)&info ) == 0 )
{
- tModuleLoader *tmp;
- for( tmp = gModule_Loaders; tmp; tmp = tmp->Next)
- {
- if( tmp->Detector(base) == 0 ) continue;
-
- return tmp->Loader(base);
- }
-
- #if USE_EDI
- // Check for EDI Driver
- if( Binary_FindSymbol(base, "driver_init", NULL ) != 0 )
+ for( loader = gModule_Loaders; loader; loader = loader->Next)
{
- return Module_InitEDI( base ); // And intialise
+ if( loader->Detector(base) )
+ break;
}
- #endif
// Unknown module type?, return error
+ if( !loader ) {
+ Binary_Unload(base);
+ Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
+ return 0;
+ }
+ }
+
+ if( !Module_int_ResolveDeps(info) ) {
+ Log_Warning("Module", "Dependencies not met for '%s'", Path);
Binary_Unload(base);
- #if USE_EDI
- Log_Warning("Module", "Module '%s' has neither a Module Info struct, nor an EDI entrypoint", Path);
- #else
- Log_Warning("Module", "Module '%s' does not have a Module Info struct", Path);
- #endif
return 0;
}
-
+
// Initialise (and register)
- if( Module_int_Initialise( info, ArgString ) )
+ if( loader ? loader->Loader(base) : Module_int_Initialise( info, ArgString ) )
{
Binary_Unload(base);
return 0;
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * pmemmap.c
+ * - Physical memory map manipulation
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <pmemmap.h>
+
+// === CODE ===
+void PMemMap_DumpBlocks(tPMemMapEnt *map, int NEnts)
+{
+ for( int i = 0; i < NEnts; i ++ )
+ {
+ Log_Debug("PMemMap", "%i: %i 0x%02x %08llx+%llx",
+ i, map[i].Type, map[i].NUMADomain,
+ map[i].Start, map[i].Length
+ );
+ }
+}
+
+int PMemMap_SplitBlock(tPMemMapEnt *map, int NEnts, int MaxEnts, int Block, Uint64 Offset)
+{
+ LOG("Splitting %i (%llx+%llx) at %llx", Block, map[Block].Start, map[Block].Length, Offset);
+
+ Uint64 _len = map[Block].Length;
+ map[Block].Length = Offset;
+ if( NEnts == MaxEnts ) {
+ // out of space
+ return NEnts;
+ }
+ if( Block < NEnts ) {
+ LOG("Moving %i entries from %i to %i", (NEnts - Block-1), Block+1, Block);
+ memmove(&map[Block+2], &map[Block+1], (NEnts - Block)*sizeof(map[0]));
+ }
+ Block ++;
+ NEnts ++;
+
+ // New (free) block
+ map[Block].Start = map[Block-1].Start + Offset;
+ map[Block].Length = _len - Offset;
+ map[Block].Type = map[Block-1].Type;
+ map[Block].NUMADomain = map[Block-1].NUMADomain;
+ LOG("- New %i %02x %llx+%llx", map[Block].Type, map[Block].NUMADomain, map[Block].Start, map[Block].Length);
+
+ return NEnts;
+}
+
+int PMemMap_CompactMap(tPMemMapEnt *map, int NEnts, int MaxEnts)
+{
+ for( int i = 1; i < NEnts; i ++ )
+ {
+ // Check if the ranges are contiguous
+ if( map[i-1].Start + map[i-1].Length < map[i].Start )
+ continue ;
+ // Check if the type is the same
+ if( map[i-1].Type != map[i].Type )
+ continue ;
+ // Check if the NUMA Domains are the same
+ if( map[i-1].NUMADomain != map[i].NUMADomain )
+ continue ;
+
+ // Ok, they should be together
+ map[i-1].Length += map[i].Length;
+ memmove(&map[i], &map[i+1], (NEnts - (i+1))*sizeof(map[0]));
+ LOG("Joined %i and %i into %llx+%llx", i-1, i, map[i-1].Start, map[i-1].Length);
+
+ // Counteract the i++ in the loop iterator
+ i --;
+ NEnts --;
+ }
+ return NEnts;
+}
+
+int PMemMap_ValidateMap(tPMemMapEnt *map, int NEnts, int MaxEnts)
+{
+ // Sort the pmem map
+ int bNeedsSort = 0;
+ for( int i = 1; i < NEnts; i ++ )
+ {
+ if( map[i-1].Start > map[i].Start ) {
+ bNeedsSort = 1;
+ break;
+ }
+ }
+ if( bNeedsSort )
+ {
+ // Use a selection/swap sort
+ for( int i = 0; i < NEnts; i ++ )
+ {
+ int sel = i;
+ for( int j = i+1; j < NEnts; j ++ )
+ {
+ if( map[j].Start < map[sel].Start )
+ sel = j;
+ }
+ if( sel != i ) {
+ LOG("Swapping %i and %i", i, sel);
+ LOG(" - %llx+%llx", map[i].Start, map[i].Length);
+ LOG(" - %llx+%llx", map[sel].Start, map[sel].Length);
+ tPMemMapEnt tmp = map[i];
+ map[i] = map[sel];
+ map[sel] = tmp;
+ }
+ }
+ }
+
+ // Ensure that the map has no overlaps
+ for( int i = 1; i < NEnts; i ++ )
+ {
+ if( map[i-1].Start + map[i-1].Length <= map[i].Start )
+ continue ;
+ // Oops, overlap!
+ Log_Notice("Arch", "Map ranges %llx+%llx and %llx+%llx overlap",
+ map[i-1].Start, map[i-1].Length,
+ map[i].Start, map[i].Length
+ );
+ }
+
+ NEnts = PMemMap_CompactMap(map, NEnts, MaxEnts);
+ return NEnts;
+}
+
+
+int PMemMap_MarkRangeUsed(tPMemMapEnt *map, int NEnts, int MaxEnts, Uint64 Base, Uint64 Size)
+{
+ int first;
+
+ Size = (Size + 0xFFF) & ~0xFFF;
+ Base = Base & ~0xFFF;
+
+ first = -1;
+ for( int i = 0; i < NEnts; i ++ )
+ {
+ if( map[i].Start + map[i].Length > Base ) {
+ first = i;
+ break;
+ }
+ }
+ if( first == -1 ) {
+ // Not in map
+ LOG("%llx+%llx not in map (past end)", Base, Size);
+ return NEnts;
+ }
+
+ if( map[first].Start > Base ) {
+ // Not in map
+ LOG("%llx+%llx not in map (in hole)", Base, Size);
+ return NEnts;
+ }
+
+ // Detect single
+ if( map[first].Start <= Base && Base + Size <= map[first].Start + map[first].Length )
+ {
+ // Split before
+ if( map[first].Start < Base )
+ {
+ if( NEnts == MaxEnts ) {
+ // out of space... oops
+ return NEnts;
+ }
+ NEnts = PMemMap_SplitBlock(map, NEnts, MaxEnts, first, Base - map[first].Start);
+ first ++;
+ }
+
+ // map[first].Start == Base
+ // Split after
+ if( map[first].Length > Size )
+ {
+ if( NEnts == MaxEnts ) {
+ // out of space
+ return NEnts;
+ }
+ NEnts = PMemMap_SplitBlock(map, NEnts, MaxEnts, first, Size);
+ }
+
+ // map[first] is now exactly the block
+ map[first].Type = PMEMTYPE_USED;
+
+ return PMemMap_CompactMap(map, NEnts, MaxEnts);
+ }
+ else
+ {
+ // Wait... this should never happen, right?
+ Log_Notice("Arch", "Module %llx+%llx overlaps two or more ranges",
+ Base, Size);
+ PMemMap_DumpBlocks(map, NEnts);
+ // TODO: Error?
+ return NEnts;
+ }
+}
+
+
+
--- /dev/null
+/*
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * rwlock.c
+ * - Reader-Writer Lockes
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <threads_int.h>
+#include <rwlock.h>
+
+// === PROTOTYPES ===
+//
+// Acquire as a reader (see rwlock.h for documentation)
+//
+int RWLock_AcquireRead(tRWLock *Lock)
+{
+ tThread *us;
+ LOG("Acquire RWLock Read %p", Lock);
+ // Get protector
+ SHORTLOCK( &Lock->Protector );
+
+ // Check if the lock is already held by a writer
+ if( Lock->Owner )
+ {
+ LOG("Waiting");
+ SHORTLOCK( &glThreadListLock );
+
+ // - Remove from active list
+ us = Threads_RemActive();
+ us->Next = NULL;
+ // - Mark as sleeping
+ us->Status = THREAD_STAT_RWLOCKSLEEP;
+ us->WaitPointer = Lock;
+
+ // - Add to waiting
+ if(Lock->ReaderWaiting)
+ Lock->ReaderWaitingLast->Next = us;
+ else
+ Lock->ReaderWaiting = us;
+ Lock->ReaderWaitingLast = us;
+
+ #if DEBUG_TRACE_STATE
+ Log("%p (%i %s) waiting on rwlock %p",
+ us, us->TID, us->ThreadName, Lock);
+ #endif
+
+ SHORTREL( &glThreadListLock );
+ SHORTREL( &Lock->Protector );
+ while(us->Status == THREAD_STAT_RWLOCKSLEEP) Threads_Yield();
+ // We're only woken when we get the lock
+ // TODO: Handle when this isn't the case
+ us->WaitPointer = NULL;
+ }
+ // Ooh, no problems then!
+ else
+ {
+ Lock->Level++;
+ SHORTREL( & Lock->Protector );
+ }
+ LOG("Obtained");
+
+ return 0;
+}
+
+int RWLock_AcquireWrite(tRWLock *Lock)
+{
+ tThread *us;
+
+ LOG("Acquire RWLock Write %p", Lock);
+
+ SHORTLOCK(&Lock->Protector);
+ if( Lock->Owner || Lock->Level != 0 )
+ {
+ LOG("Waiting");
+ SHORTLOCK(&glThreadListLock);
+
+ us = Threads_RemActive();
+ us->Next = NULL;
+ us->Status = THREAD_STAT_RWLOCKSLEEP;
+ us->WaitPointer = Lock;
+
+ if( Lock->WriterWaiting )
+ Lock->WriterWaitingLast->Next = us;
+ else
+ Lock->WriterWaiting = us;
+ Lock->WriterWaitingLast = us;
+
+ SHORTREL( &glThreadListLock );
+ SHORTREL( &Lock->Protector );
+
+ while(us->Status == THREAD_STAT_RWLOCKSLEEP) Threads_Yield();
+ us->WaitPointer = NULL;
+ }
+ else
+ {
+ // Nothing else is using the lock, nice :)
+ Lock->Owner = Proc_GetCurThread();
+ SHORTREL(&Lock->Protector);
+ }
+ LOG("Obtained");
+ return 0;
+}
+
+// Release a mutex
+void RWLock_Release(tRWLock *Lock)
+{
+ LOG("Release RWLock %p", Lock);
+ SHORTLOCK( &Lock->Protector );
+
+ if( Lock->Owner != Proc_GetCurThread() )
+ Lock->Level --;
+
+ // Writers first
+ if( Lock->WriterWaiting )
+ {
+ Lock->Owner = Lock->WriterWaiting; // Set owner
+ Lock->WriterWaiting = Lock->WriterWaiting->Next; // Next!
+
+ // Wake new owner
+ if( Lock->Owner->Status != THREAD_STAT_ACTIVE )
+ Threads_AddActive(Lock->Owner);
+ }
+ else
+ {
+ Lock->Owner = NULL;
+
+ while( Lock->ReaderWaiting ) {
+ Lock->Level ++;
+ Threads_AddActive(Lock->ReaderWaiting);
+ Lock->ReaderWaiting = Lock->ReaderWaiting->Next;
+ }
+ }
+ SHORTREL( &Lock->Protector );
+}
+
+// === EXPORTS ===
+EXPORT(RWLock_AcquireRead);
+EXPORT(RWLock_AcquireWrite);
+EXPORT(RWLock_Release);
// -- Get the physical address of a page
case SYS_GETPHYS:
- ret = MM_GetPhysAddr(Regs->Arg1);
+ ret = MM_GetPhysAddr( (void*)Regs->Arg1 );
break;
// -- Map an address
ret = -1;
break;
}
- // Sanity check the paths
- if(!Syscall_ValidString((char*)Regs->Arg1)
- || !Syscall_ValidString((char*)Regs->Arg2)
- || !Syscall_ValidString((char*)Regs->Arg3)
- || !Syscall_ValidString((char*)Regs->Arg4) ) {
- err = -EINVAL;
- ret = -1;
- break;
+
+ if( !Regs->Arg1 )
+ {
+ if( !Syscall_ValidString((char*)Regs->Arg2) ) {
+ err = -EINVAL;
+ ret = -1;
+ break;
+ }
+
+ ret = VFS_Unmount((char*)Regs->Arg2);
+ }
+ else
+ {
+ // Sanity check the paths
+ if(!Syscall_ValidString((char*)Regs->Arg1)
+ || !Syscall_ValidString((char*)Regs->Arg2)
+ || (Regs->Arg3 && !Syscall_ValidString((char*)Regs->Arg3))
+ || !Syscall_ValidString((char*)Regs->Arg4) ) {
+ err = -EINVAL;
+ ret = -1;
+ break;
+ }
+ ret = VFS_Mount(
+ (char*)Regs->Arg1, // Device
+ (char*)Regs->Arg2, // Mount point
+ (char*)Regs->Arg3, // Filesystem
+ (char*)Regs->Arg4 // Options
+ );
}
- ret = VFS_Mount(
- (char*)Regs->Arg1, // Device
- (char*)Regs->Arg2, // Mount point
- (char*)Regs->Arg3, // Filesystem
- (char*)Regs->Arg4 // Options
- );
break;
// Wait on a set of handles
* system.c
* - Architecture Independent System Init
*/
-#define DEBUG 0
+#define DEBUG 1
#include <acess.h>
+#include <hal_proc.h>
// === IMPORTS ===
extern void Arch_LoadBootModules(void);
// - Execute the Config Script
Log_Log("Config", "Spawning init '%s'", gsInitBinary);
- Proc_Spawn(gsInitBinary);
+ if(Proc_Clone(CLONE_VM|CLONE_NOUSER) == 0)
+ {
+ const char *args[] = {gsInitBinary, 0};
+ Proc_Execve(gsInitBinary, args, &args[1], 0);
+ 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)");
// - Symbolic Link <link>=<destination>
if(value[0] == '/')
{
- Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
+// Log_Log("Config", "Symbolic link '%s' pointing to '%s'", Arg, value);
VFS_Symlink(Arg, value);
}
// - Mount <mountpoint>=<fs>:<device>
}
// Create Mountpoint
if( (fd = VFS_Open(Arg, 0)) == -1 ) {
- Log_Log("Config", "Creating directory '%s'", Arg, value);
+// Log_Log("Config", "Creating directory '%s'", Arg, value);
VFS_MkDir( Arg );
} else {
VFS_Close(fd);
}
// Mount
- Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
+// Log_Log("Config", "Mounting '%s' to '%s' ('%s')", dev, Arg, value);
VFS_Mount(dev, Arg, value, "");
}
}
tThread *thread;
// Search global list
- for(thread = gAllThreads;
- thread;
- thread = thread->GlobalNext)
+ for( thread = gAllThreads; thread; thread = thread->GlobalNext )
{
if(thread->TID == TID)
return thread;
}
- Log("Unable to find TID %i on main list\n", TID);
+ Log_Notice("Threads", "Unable to find TID %i on main list\n", TID);
return NULL;
}
#define DEBUG 0
#include <acess.h>
#include <timers.h>
+#include <timers_int.h>
#include <events.h>
#include <hal_proc.h> // Proc_GetCurThread
#include <workqueue.h>
-
-// === TYPEDEFS ===
-struct sTimer {
- tTimer *Next;
- Sint64 FiresAfter;
- void (*Callback)(void*);
- void *Argument;
-// tMutex Lock;
- BOOL bActive;
-};
+#include <threads_int.h> // Used to get thread timer
// === PROTOTYPES ===
void Timer_CallbackThread(void *Unused);
*/
void Time_Delay(int Delay)
{
- tTimer *t;
- t = Time_AllocateTimer(NULL, NULL);
+ tTimer *t = &Proc_GetCurThread()->ThreadTimer;
+ Time_InitTimer(t, NULL, NULL);
Time_ScheduleTimer(t, Delay);
Threads_WaitEvents(THREAD_EVENT_TIMER);
- Time_FreeTimer(t);
}
// === EXPORTS ===
* Acess2 VFS
* - Directory Management Functions
*/
+#define SANITY 1
#define DEBUG 0
#include <acess.h>
#include <vfs.h>
*/
int VFS_MkNod(const char *Path, Uint Flags)
{
+ tVFS_Mount *mountpt;
char *absPath, *name;
int pos = 0, oldpos = 0;
int next = 0;
tVFS_Node *parent;
- int ret;
+ tVFS_Node *ret;
ENTER("sPath xFlags", Path, Flags);
// Check for root
if(absPath[0] == '\0')
- parent = VFS_ParsePath("/", NULL, NULL);
+ parent = VFS_ParsePath("/", NULL, &mountpt);
else
- parent = VFS_ParsePath(absPath, NULL, NULL);
+ parent = VFS_ParsePath(absPath, NULL, &mountpt);
LOG("parent = %p", parent);
if(!parent) {
- LEAVE('i', -1);
- return -1; // Error Check
+ errno = ENOENT;
+ goto _error;
}
-
+
// Permissions Check
if( !VFS_CheckACL(parent, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
- _CloseNode(parent);
- free(absPath);
- LEAVE('i', -1);
- return -1;
+ errno = EACCES;
+ goto _error;
}
LOG("parent = %p", parent);
if(!parent->Type || !parent->Type->MkNod) {
- Warning("VFS_MkNod - Directory has no MkNod method");
- LEAVE('i', -1);
- return -1;
+ Log_Warning("VFS", "VFS_MkNod - Directory has no MkNod method");
+ errno = ENOTDIR;
+ goto _error;
}
// Create node
ret = parent->Type->MkNod(parent, name, Flags);
+ _CloseNode(ret);
// Free allocated string
free(absPath);
// Free Parent
+ ASSERT(mountpt->OpenHandleCount>0);
+ mountpt->OpenHandleCount --;
_CloseNode(parent);
-
- // Error Check
- if(ret == 0) {
- LEAVE('i', -1);
- return -1;
- }
-
- LEAVE('i', 0);
- return 0;
+
+ // Return whatever the driver said
+ LEAVE('i', ret==NULL);
+ return ret==NULL;
+
+_error:
+ _CloseNode(parent);
+ ASSERT(mountpt->OpenHandleCount>0);
+ mountpt->OpenHandleCount --;
+ free(absPath);
+ LEAVE('i', -1);
+ return -1;
}
/**
realLink = VFS_GetAbsPath( Link );
if(!realLink) {
Log_Warning("VFS", "Path '%s' is badly formed", Link);
+ errno = EINVAL;
LEAVE('i', -1);
return -1;
}
if( VFS_MkNod(Name, VFS_FFLAG_SYMLINK) != 0 ) {
Log_Warning("VFS", "Unable to create link node '%s'", Name);
free(realLink);
+ // errno is set by VFS_MkNod
LEAVE('i', -2);
return -2; // Make link node
}
// Write link address
fp = VFS_Open(Name, VFS_OPENFLAG_WRITE|VFS_OPENFLAG_NOLINK);
+ if( fp == -1 ) {
+ Log_Warning("VFS", "Unable to open newly created symlink '%s'", Name);
+ free(realLink);
+ LEAVE('i', -3);
+ return -3;
+ }
VFS_Write(fp, strlen(realLink), realLink);
VFS_Close(fp);
int VFS_ReadDir(int FD, char *Dest)
{
tVFS_Handle *h = VFS_GetHandle(FD);
- char *tmp;
+ int rv;
//ENTER("ph pDest", h, Dest);
return 0;
}
- if(h->Node->Size != -1 && h->Position >= h->Node->Size) {
+ if(h->Node->Size != (Uint64)-1 && h->Position >= h->Node->Size) {
//LEAVE('i', 0);
return 0;
}
do {
- tmp = h->Node->Type->ReadDir(h->Node, h->Position);
- if((Uint)tmp < (Uint)VFS_MAXSKIP)
- h->Position += (Uint)tmp;
+ rv = h->Node->Type->ReadDir(h->Node, h->Position, Dest);
+ if(rv > 0)
+ h->Position += rv;
else
h->Position ++;
- } while(tmp != NULL && (Uint)tmp < (Uint)VFS_MAXSKIP);
+ } while(rv > 0);
- //LOG("tmp = '%s'", tmp);
-
- if(!tmp) {
+ if(rv < 0) {
//LEAVE('i', 0);
return 0;
}
- strcpy(Dest, tmp);
- free(tmp);
-
//LEAVE('i', 1);
return 1;
}
void DevFS_DelDevice(tDevFS_Driver *Device);
#endif
tVFS_Node *DevFS_InitDevice(const char *Device, const char **Options);
-char *DevFS_ReadDir(tVFS_Node *Node, int Pos);
+void DevFS_Unmount(tVFS_Node *RootNode);
+ int DevFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *DevFS_FindDir(tVFS_Node *Node, const char *Name);
// === GLOBALS ===
tVFS_Driver gDevFS_Info = {
- "devfs", 0, DevFS_InitDevice, NULL, NULL
+ .Name = "devfs",
+ .InitDevice = DevFS_InitDevice,
+ .Unmount = DevFS_Unmount
};
tVFS_NodeType gDevFS_DirType = {
.TypeName = "DevFS-Dir",
return &gDevFS_RootNode;
}
+void DevFS_Unmount(tVFS_Node *RootNode)
+{
+
+}
+
/**
* \fn char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
*/
-char *DevFS_ReadDir(tVFS_Node *Node, int Pos)
+int DevFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
tDevFS_Driver *dev;
- if(Pos < 0) return NULL;
+ if(Pos < 0) return -EINVAL;
for(dev = gDevFS_Drivers;
dev && Pos--;
dev = dev->Next
);
- if(dev)
- return strdup(dev->Name);
- else
- return NULL;
+ if(dev) {
+ strncpy(Dest, dev->Name, FILENAME_MAX);
+ return 0;
+ }
+ else {
+ return -ENOENT;
+ }
}
/**
// === PROTOTYPES ===
tVFS_Node *Root_InitDevice(const char *Device, const char **Options);
- int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+tVFS_Node *Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
tVFS_Node *Root_FindDir(tVFS_Node *Node, const char *Name);
-char *Root_ReadDir(tVFS_Node *Node, int Pos);
+ int Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
size_t Root_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
size_t Root_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
tRamFS_File *Root_int_AllocFile(void);
// === GLOBALS ===
tVFS_Driver gRootFS_Info = {
- "rootfs", 0, Root_InitDevice, NULL, NULL
+ .Name = "rootfs",
+ .InitDevice = Root_InitDevice
};
tRamFS_File RootFS_Files[MAX_FILES];
tVFS_ACL RootFS_DirACLs[3] = {
// Create Root Node
root = &RootFS_Files[0];
-
+
+ root->Name[0] = '/';
+ root->Name[1] = '\0';
root->Node.ImplPtr = root;
root->Node.CTime
root->Node.NumACLs = 3;
root->Node.ACLs = RootFS_DirACLs;
+ root->Node.Flags = VFS_FFLAG_DIRECTORY;
root->Node.Type = &gRootFS_DirType;
return &root->Node;
* \fn int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
* \brief Create an entry in the root directory
*/
-int Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+tVFS_Node *Root_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
{
tRamFS_File *parent = Node->ImplPtr;
tRamFS_File *child;
- tRamFS_File *prev = (tRamFS_File *) &parent->Data.FirstChild;
+ tRamFS_File *prev = NULL;
ENTER("pNode sName xFlags", Node, Name, Flags);
- LOG("%i > %i", strlen(Name)+1, sizeof(child->Name));
- if(strlen(Name) + 1 > sizeof(child->Name))
- LEAVE_RET('i', 0);
+ LOG("Sanity check name length - %i > %i", strlen(Name)+1, sizeof(child->Name));
+ if(strlen(Name) + 1 > sizeof(child->Name)) {
+ errno = EINVAL;
+ LEAVE_RET('n', NULL);
+ }
// Find last child, while we're at it, check for duplication
for( child = parent->Data.FirstChild; child; prev = child, child = child->Next )
{
if(strcmp(child->Name, Name) == 0) {
- LEAVE('i', 0);
- return 0;
+ LOG("Duplicate");
+ errno = EEXIST;
+ LEAVE_RET('n', NULL);
}
}
memset(child, 0, sizeof(tRamFS_File));
strcpy(child->Name, Name);
+ LOG("Name = '%s'", child->Name);
child->Parent = parent;
child->Next = NULL;
child->Node.Type = &gRootFS_FileType;
}
- prev->Next = child;
+ // Append!
+ if( prev )
+ prev->Next = child;
+ else
+ parent->Data.FirstChild = child;
parent->Node.Size ++;
- LEAVE('i', 1);
- return 1;
+ LEAVE('n', &child->Node);
+ return &child->Node;
}
/**
tRamFS_File *child = parent->Data.FirstChild;
ENTER("pNode sName", Node, Name);
- //Log("Root_FindDir: (Node=%p, Name='%s')", Node, Name);
- for(;child;child = child->Next)
+ for( child = parent->Data.FirstChild; child; child = child->Next )
{
- //Log(" Root_FindDir: strcmp('%s', '%s')", child->Node.Name, Name);
LOG("child->Name = '%s'", child->Name);
- if(strcmp(child->Name, Name) == 0) {
+ if(strcmp(child->Name, Name) == 0)
+ {
LEAVE('p', &child->Node);
return &child->Node;
}
* \fn char *Root_ReadDir(tVFS_Node *Node, int Pos)
* \brief Get an entry from the filesystem
*/
-char *Root_ReadDir(tVFS_Node *Node, int Pos)
+int Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
tRamFS_File *parent = Node->ImplPtr;
tRamFS_File *child = parent->Data.FirstChild;
for( ; child && Pos--; child = child->Next ) ;
- if(child) return strdup(child->Name);
+ if(child) {
+ strncpy(Dest, child->Name, FILENAME_MAX);
+ return 0;
+ }
- return NULL;
+ return -ENOENT;
}
/**
* Acess2 VFS
* - AllocHandle, GetHandle
*/
+#define SANITY 1
#define DEBUG 0
#include <acess.h>
#include <mm_virt.h>
tVFS_Handle *gaKernelHandles = (void*)MM_KERNEL_VFS;
// === CODE ===
+inline void _ReferenceNode(tVFS_Node *Node)
+{
+ if( !MM_GetPhysAddr(Node->Type) ) {
+ Log_Error("VFS", "Node %p's type is invalid (%p bad pointer) - %P corrupted",
+ Node, Node->Type, MM_GetPhysAddr(&Node->Type));
+ return ;
+ }
+ if( Node->Type && Node->Type->Reference )
+ Node->Type->Reference( Node );
+ else
+ Node->ReferenceCount ++;
+}
+
/**
* \fn tVFS_Handle *VFS_GetHandle(int FD)
* \brief Gets a pointer to the handle information structure
{
int max_handles = *Threads_GetMaxFD();
// Allocate Buffer
- if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+ if( MM_GetPhysAddr( gaUserHandles ) == 0 )
{
Uint addr, size;
size = max_handles * sizeof(tVFS_Handle);
else
{
// Allocate space if not already
- if( MM_GetPhysAddr( (tVAddr)gaKernelHandles ) == 0 )
+ if( MM_GetPhysAddr( gaKernelHandles ) == 0 )
{
Uint addr, size;
size = MAX_KERNEL_FILES * sizeof(tVFS_Handle);
int max_handles = *Threads_GetMaxFD();
// Check if this process has any handles
- if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+ if( MM_GetPhysAddr( gaUserHandles ) == 0 )
return ;
for( i = 0; i < max_handles; i ++ )
h = &gaUserHandles[i];
if( !h->Node )
continue ;
- if( h->Node->Type && h->Node->Type->Reference )
- h->Node->Type->Reference( h->Node );
+ _ReferenceNode(h->Node);
+ h->Mount->OpenHandleCount ++;
}
}
int max_handles = *Threads_GetMaxFD();
// Check if this process has any handles
- if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+ if( MM_GetPhysAddr( gaUserHandles ) == 0 )
return ;
for( i = 0; i < max_handles; i ++ )
h = &gaUserHandles[i];
if( !h->Node )
continue ;
- if( h->Node->Type && h->Node->Type->Close )
- h->Node->Type->Close( h->Node );
+ _CloseNode(h->Node);
}
}
int max_handles = *Threads_GetMaxFD();
// Check if this process has any handles
- if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) == 0 )
+ if( MM_GetPhysAddr( gaUserHandles ) == 0 )
return NULL;
// Allocate
// Reference node
if( !h->Node )
continue ;
- if( h->Node->Type && h->Node->Type->Reference )
- h->Node->Type->Reference( h->Node );
+ _ReferenceNode(h->Node);
+ h->Mount->OpenHandleCount ++;
}
return ret;
return ;
// Check if there is already a set of handles
- if( MM_GetPhysAddr( (tVAddr)gaUserHandles ) != 0 )
+ if( MM_GetPhysAddr( gaUserHandles ) != 0 )
return ;
if( !h->Node )
continue ;
- if( h->Node->Type && h->Node->Type->Reference )
- h->Node->Type->Reference( h->Node );
+ _ReferenceNode(h->Node);
+ h->Mount->OpenHandleCount ++;
}
}
if( !h->Node )
continue ;
- if( h->Node->Type && h->Node->Type->Close )
- h->Node->Type->Close( h->Node );
+ _CloseNode(h->Node);
+
+ ASSERT(h->Mount->OpenHandleCount > 0);
+ LOG("dec. mntpt '%s' to %i", h->Mount->MountPoint, h->Mount->OpenHandleCount-1);
+ h->Mount->OpenHandleCount --;
}
free( Handles );
}
*/
#define DEBUG 0
#include <acess.h>
-#include "vfs.h"
-#include "vfs_int.h"
+#include <vfs.h>
+#include <vfs_ext.h>
+#include <vfs_int.h>
// === CODE ===
/**
* \fn Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
* \brief Read data from a node (file)
*/
-Uint64 VFS_Read(int FD, Uint64 Length, void *Buffer)
+size_t VFS_Read(int FD, size_t Length, void *Buffer)
{
tVFS_Handle *h;
- Uint64 ret;
+ size_t ret;
ENTER("iFD XLength pBuffer", FD, Length, Buffer);
h = VFS_GetHandle(FD);
- if(!h) LEAVE_RET('i', -1);
+ if(!h) {
+ LOG("Bad Handle");
+ LEAVE_RET('i', -1);
+ }
- if( !(h->Mode & VFS_OPENFLAG_READ) || h->Node->Flags & VFS_FFLAG_DIRECTORY )
+ if( !(h->Mode & VFS_OPENFLAG_READ) ) {
+ LOG("Bad mode");
+ LEAVE_RET('i', -1);
+ }
+ if( (h->Node->Flags & VFS_FFLAG_DIRECTORY) ) {
+ LOG("Reading directory");
+ LEAVE_RET('i', -1);
+ }
+
+ if(!h->Node->Type || !h->Node->Type->Read) {
+ LOG("No read method");
LEAVE_RET('i', -1);
+ }
- if(!h->Node->Type || !h->Node->Type->Read) LEAVE_RET('i', 0);
+ if( !MM_GetPhysAddr(h->Node->Type->Read) ) {
+ Log_Error("VFS", "Node type %p(%s) read method is junk %p", h->Node->Type, h->Node, h->Node->Type->TypeName,
+ h->Node->Type->Read);
+ LEAVE_RET('i', -1);
+ }
ret = h->Node->Type->Read(h->Node, h->Position, Length, Buffer);
- if(ret == -1) LEAVE_RET('i', -1);
+ if(ret == (size_t)-1) LEAVE_RET('i', -1);
h->Position += ret;
LEAVE('X', ret);
* \fn Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
* \brief Read data from a given offset (atomic)
*/
-Uint64 VFS_ReadAt(int FD, Uint64 Offset, Uint64 Length, void *Buffer)
+size_t VFS_ReadAt(int FD, Uint64 Offset, size_t Length, void *Buffer)
{
tVFS_Handle *h;
- Uint64 ret;
+ size_t ret;
h = VFS_GetHandle(FD);
if(!h) return -1;
Warning("VFS_ReadAt - Node %p, does not have a read method", h->Node);
return 0;
}
+
+ if( !MM_GetPhysAddr(h->Node->Type->Read) ) {
+ Log_Error("VFS", "Node type %p(%s) read method is junk %p", h->Node->Type, h->Node, h->Node->Type->TypeName,
+ h->Node->Type->Read);
+ LEAVE_RET('i', -1);
+ }
+
ret = h->Node->Type->Read(h->Node, Offset, Length, Buffer);
- if(ret == -1) return -1;
+ if(ret == (size_t)-1) return -1;
return ret;
}
* \fn Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
* \brief Read data from a node (file)
*/
-Uint64 VFS_Write(int FD, Uint64 Length, const void *Buffer)
+size_t VFS_Write(int FD, size_t Length, const void *Buffer)
{
tVFS_Handle *h;
- Uint64 ret;
+ size_t ret;
h = VFS_GetHandle(FD);
if(!h) 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, h->Node->Type->TypeName,
+ h->Node->Type->Write);
+ return -1;
+ }
ret = h->Node->Type->Write(h->Node, h->Position, Length, Buffer);
- if(ret == -1) return -1;
+ 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
*/
-Uint64 VFS_WriteAt(int FD, Uint64 Offset, Uint64 Length, const void *Buffer)
+size_t VFS_WriteAt(int FD, Uint64 Offset, size_t Length, const void *Buffer)
{
tVFS_Handle *h;
- Uint64 ret;
+ size_t ret;
h = VFS_GetHandle(FD);
if(!h) return -1;
if( h->Node->Flags & VFS_FFLAG_DIRECTORY ) return -1;
if(!h->Node->Type || !h->Node->Type->Write) return 0;
- ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
- if(ret == -1) return -1;
+ if( !MM_GetPhysAddr(h->Node->Type->Write) ) {
+ Log_Error("VFS", "Node type %p(%s) write method is junk %p", h->Node->Type, h->Node, h->Node->Type->TypeName,
+ h->Node->Type->Write);
+ return -1;
+ }
+ ret = h->Node->Type->Write(h->Node, Offset, Length, Buffer);
+ if(ret == (size_t)-1) return -1;
return ret;
}
// Set relative to end of file
if(Whence < 0) {
- if( h->Node->Size == -1 ) return -1;
+ if( h->Node->Size == (Uint64)-1 ) return -1;
h->Position = h->Node->Size - Offset;
return 0;
EXPORT(VFS_AddDriver);
// === GLOBALS ===
-tVFS_Node NULLNode = {0};
+tVFS_Node NULLNode = {.Type=NULL};
tShortSpinlock slDriverListLock;
tVFS_Driver *gVFS_Drivers = NULL;
char *gsVFS_DriverFile = NULL;
return 0;
}
+void VFS_Deinit(void)
+{
+ SysFS_RemoveFile(giVFS_MountFileID);
+ free(gsVFS_MountFile);
+ SysFS_RemoveFile(giVFS_DriverFileID);
+ free(gsVFS_DriverFile);
+}
+
/**
* \fn char *VFS_GetTruePath(const char *Path)
* \brief Gets the true path (non-symlink) of a file
if(gsVFS_DriverFile) free(gsVFS_DriverFile);
gsVFS_DriverFile = buf;
}
+
+void VFS_CleanupNode(tVFS_Node *Node)
+{
+
+}
+
LOG("%i pages anonymous to %p", npages, mapping_dest);
for( ; npages --; mapping_dest += PAGE_SIZE, ofs += PAGE_SIZE )
{
- if( MM_GetPhysAddr(mapping_dest) ) {
+ if( MM_GetPhysAddr((void*)mapping_dest) ) {
// TODO: Set flags to COW if needed (well, if shared)
MM_SetFlags(mapping_dest, MM_PFLAG_COW, MM_PFLAG_COW);
LOG("clear from %p, %i bytes", (void*)(mapping_base + ofs),
// - Map (and allocate) pages
while( npages -- )
{
- if( MM_GetPhysAddr(mapping_dest) == 0 )
+ if( MM_GetPhysAddr( (void*)mapping_dest ) == 0 )
{
if( pb->PhysAddrs[pagenum - pb->BaseOffset] == 0 )
{
}
// TODO: Clip read length
read_len = nt->Read(h->Node, pagenum*PAGE_SIZE, PAGE_SIZE, (void*)mapping_dest);
-// if( read_len != PAGE_SIZE ) {
-// memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
-// }
+ // TODO: This was commented out, why?
+ if( read_len != PAGE_SIZE ) {
+ memset( (void*)(mapping_dest+read_len), 0, PAGE_SIZE-read_len );
+ }
}
- pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( mapping_dest );
+ pb->PhysAddrs[pagenum - pb->BaseOffset] = MM_GetPhysAddr( (void*)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,
/*
* Acess Micro - VFS Server version 1
*/
+#define SANITY 1
+#define DEBUG 0
#include <acess.h>
#include <vfs.h>
#include <vfs_int.h>
#if 0
int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options);
#endif
+void VFS_int_Unmount(tVFS_Mount *Mount);
void VFS_UpdateMountFile(void);
// === GLOBALS ===
-tMutex glVFS_MountList;
+tRWLock glVFS_MountList;
tVFS_Mount *gVFS_Mounts;
tVFS_Mount *gVFS_RootMount = NULL;
Uint32 giVFS_NextMountIdent = 1;
*/
int VFS_Mount(const char *Device, const char *MountPoint, const char *Filesystem, const char *Options)
{
- tVFS_Mount *mnt;
+ tVFS_Mount *mnt, *parent_mnt;
tVFS_Driver *fs;
int deviceLen = strlen(Device);
int mountLen = strlen(MountPoint);
int argLen = strlen(Options);
// Get the filesystem
- fs = VFS_GetFSByName(Filesystem);
- if(!fs) {
- Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
- return -1;
+ if( Filesystem && Filesystem[0] )
+ {
+ fs = VFS_GetFSByName(Filesystem);
+ if(!fs) {
+ Log_Warning("VFS", "VFS_Mount - Unknown FS Type '%s'", Filesystem);
+ return -ENOENT;
+ }
+ }
+ else
+ {
+ int fd = VFS_Open(Device, VFS_OPENFLAG_READ);
+ if( fd == -1 ) {
+ Log_Warning("VFS", "VFS_Mount - Unable to open '%s' for autodetect", Device);
+ return -ENOENT;
+ }
+
+ tVFS_Driver *bestfs = NULL;
+ int bestrank = 0, rank;
+ for( fs = gVFS_Drivers; fs; fs = fs->Next )
+ {
+ if(!fs->Detect) continue ;
+ rank = fs->Detect(fd);
+ if(!rank) continue ;
+ if(!bestfs || rank > bestrank) {
+ bestfs = fs;
+ bestrank = rank;
+ }
+ }
+ VFS_Close(fd);
+ if( bestfs == NULL ) {
+ Log_Warning("VFS", "VFS_Mount - Filesystem autodetection failed");
+ return -1;
+ }
+
+ fs = bestfs;
+ }
+
+ // Validate the mountpoint target
+ // - Only if / is mounted
+ if( gVFS_Mounts )
+ {
+ tVFS_Node *mpnode = VFS_ParsePath(MountPoint, NULL, &parent_mnt);
+ if( !mpnode ) {
+ Log_Warning("VFS", "VFS_Mount - Mountpoint '%s' does not exist", MountPoint);
+ return -1;
+ }
+ if( mpnode->Type->Close )
+ mpnode->Type->Close(mpnode);
+ if( parent_mnt->RootNode == mpnode ) {
+ Log_Warning("VFS", "VFS_Mount - Attempt to mount over '%s' (%s)",
+ MountPoint, parent_mnt->MountPoint);
+ return -1;
+ }
}
// Create mount information
mnt = malloc( sizeof(tVFS_Mount)+deviceLen+1+mountLen+1+argLen+1 );
if(!mnt) {
+ ASSERT(parent_mnt->OpenHandleCount > 0);
+ parent_mnt->OpenHandleCount --;
return -2;
}
-
+
// HACK: Forces VFS_ParsePath to fall back on root
if(mountLen == 1 && MountPoint[0] == '/')
mnt->MountPointLen = 0;
// Fill Structure
mnt->Filesystem = fs;
+ mnt->OpenHandleCount = 0;
mnt->Device = &mnt->StrData[0];
memcpy( mnt->Device, Device, deviceLen+1 );
mnt->Options = &mnt->StrData[deviceLen+1+mountLen+1];
memcpy( mnt->Options, Options, argLen+1 );
+ // Parse options string
+ char *str = mnt->Options;
+ int nArg = 0;
+ do {
+ nArg ++;
+ } while( (str = strchr(str, ',')) );
+
+ char *args[nArg + 1];
+ str = mnt->Options;
+ nArg = 0;
+ do {
+ args[nArg++] = str;
+ str = strchr(str, ',');
+ if(str) *str = '\0';
+ } while( str );
+ args[nArg] = 0; // NULL terminal
+
// Initialise Volume
- mnt->RootNode = fs->InitDevice(Device, NULL); //&ArgString);
+ mnt->RootNode = fs->InitDevice(Device, (const char **)args);
if(!mnt->RootNode) {
free(mnt);
+ ASSERT(parent_mnt->OpenHandleCount>0);
+ parent_mnt->OpenHandleCount --;
return -2;
}
+ // Repair the options string
+ while( nArg -- > 1 )
+ args[nArg][-1] = ',';
+
mnt->Identifier = giVFS_NextMountIdent++;
#if 0
// Ensure identifiers don't repeat
if(!gVFS_RootMount) gVFS_RootMount = mnt;
// Add to mount list
- Mutex_Acquire( &glVFS_MountList );
+ RWLock_AcquireWrite( &glVFS_MountList );
{
- tVFS_Mount *tmp;
mnt->Next = NULL;
if(gVFS_Mounts) {
+ tVFS_Mount *tmp;
for( tmp = gVFS_Mounts; tmp->Next; tmp = tmp->Next );
tmp->Next = mnt;
}
gVFS_Mounts = mnt;
}
}
- Mutex_Release( &glVFS_MountList );
+ RWLock_Release( &glVFS_MountList );
- Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, Filesystem);
+ Log_Log("VFS", "Mounted '%s' to '%s' ('%s')", Device, MountPoint, fs->Name);
VFS_UpdateMountFile();
return 0;
}
+void VFS_int_Unmount(tVFS_Mount *Mount)
+{
+ // Decrease the open handle count for the mountpoint filesystem.
+ if( Mount != gVFS_RootMount )
+ {
+ tVFS_Mount *mpmnt;
+ for( mpmnt = gVFS_Mounts; mpmnt; mpmnt = mpmnt->Next )
+ {
+ if( strncmp(mpmnt->MountPoint, Mount->MountPoint, mpmnt->MountPointLen) != 0 )
+ continue ;
+ if( Mount->MountPoint[ mpmnt->MountPointLen ] != '/' )
+ continue ;
+ break;
+ }
+ if(mpmnt) {
+ ASSERT(mpmnt->OpenHandleCount>0);
+ mpmnt->OpenHandleCount --;
+ }
+ else {
+ Log_Notice("VFS", "Mountpoint '%s' has no parent", Mount->MountPoint);
+ }
+ }
+
+ if( Mount->Filesystem->Unmount )
+ Mount->Filesystem->Unmount( Mount->RootNode );
+ LOG("%p (%s) unmounted", Mount, Mount->MountPoint);
+ free(Mount);
+}
+
+int VFS_Unmount(const char *Mountpoint)
+{
+ tVFS_Mount *mount, *prev = NULL;
+ RWLock_AcquireWrite( &glVFS_MountList );
+ for( mount = gVFS_Mounts; mount; prev = mount, mount = mount->Next )
+ {
+ if( strcmp(Mountpoint, mount->MountPoint) == 0 ) {
+ if( mount->OpenHandleCount ) {
+ LOG("Mountpoint busy");
+ RWLock_Release(&glVFS_MountList);
+ Log_Log("VFS", "Unmount of '%s' deferred, still busy (%i open handles)",
+ Mountpoint, mount->OpenHandleCount);
+ return EBUSY;
+ }
+ if(prev)
+ prev->Next = mount->Next;
+ else
+ gVFS_Mounts = mount->Next;
+ break;
+ }
+ }
+ RWLock_Release( &glVFS_MountList );
+ if( !mount ) {
+ LOG("Mountpoint not found");
+ return ENOENT;
+ }
+
+ VFS_int_Unmount(mount);
+
+ VFS_UpdateMountFile();
+
+ return EOK;
+}
+
+int VFS_UnmountAll(void)
+{
+ int nUnmounted = 0;
+ tVFS_Mount *mount, *prev = NULL, *next;
+
+ RWLock_AcquireWrite( &glVFS_MountList );
+ // If we've unmounted the final filesystem, all good
+ if( gVFS_Mounts == NULL) {
+ RWLock_Release( &glVFS_MountList );
+
+ // Final unmount means VFS completely deinited
+ VFS_Deinit();
+ return -1;
+ }
+
+ for( mount = gVFS_Mounts; mount; prev = mount, mount = next )
+ {
+ next = mount->Next;
+
+ ASSERT(mount->OpenHandleCount >= 0);
+
+ // Can't unmount stuff with open handles
+ if( mount->OpenHandleCount > 0 ) {
+ LOG("%p (%s) has open handles (%i of them)",
+ mount, mount->MountPoint, mount->OpenHandleCount);
+ continue;
+ }
+
+ if(prev)
+ prev->Next = mount->Next;
+ else
+ gVFS_Mounts = mount->Next;
+
+ VFS_int_Unmount(mount);
+ mount = prev;
+ nUnmounted ++;
+ }
+ RWLock_Release( &glVFS_MountList );
+
+ VFS_UpdateMountFile();
+
+ return nUnmounted;
+}
+
/**
* \brief Gets a mount point given the identifier
*/
tVFS_Mount *VFS_GetMountByIdent(Uint32 MountID)
{
tVFS_Mount *mnt;
+
+ RWLock_AcquireRead(&glVFS_MountList);
for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
{
if(mnt->Identifier == MountID)
- return mnt;
+ break;
}
- return NULL;
+ if(mnt)
+ mnt->OpenHandleCount ++;
+ RWLock_Release(&glVFS_MountList);
+ return mnt;
}
/**
// Format:
// <device>\t<location>\t<type>\t<options>\n
+ RWLock_AcquireRead( &glVFS_MountList );
for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
{
len += 4 + strlen(mnt->Device) + strlen(mnt->MountPoint)
+ strlen(mnt->Filesystem->Name) + strlen(mnt->Options);
}
+ RWLock_Release( &glVFS_MountList );
buf = malloc( len + 1 );
len = 0;
+ RWLock_AcquireRead( &glVFS_MountList );
for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
{
strcpy( &buf[len], mnt->Device );
len += strlen(mnt->Options);
buf[len++] = '\n';
}
+ RWLock_Release( &glVFS_MountList );
buf[len] = 0;
SysFS_UpdateFile( giVFS_MountFileID, buf, len );
/*
- * AcessMicro VFS
- * - File IO Passthru's
+ * Acess2 Kernel
+ * - By John Hodge (thePowersGang)
+ *
+ * vfs/nodecache.c
+ * - VFS Node Caching facility
*/
+#define DEBUG 0
#include <acess.h>
#include "vfs.h"
#include "vfs_int.h"
gVFS_InodeCache = ent;
SHORTREL( &glVFS_InodeCache );
- return gVFS_NextInodeHandle-1;
+ return ent->Handle;
}
/**
newEnt->Next = ent;
memcpy(&newEnt->Node, Node, sizeof(tVFS_Node));
prev->Next = newEnt;
-
+ newEnt->Node.ReferenceCount = 1;
+
+ LOG("Cached %llx as %p", Node->Inode, &newEnt->Node);
+
return &newEnt->Node;
}
* \fn void Inode_UncacheNode(int Handle, Uint64 Inode)
* \brief Dereferences/Removes a cached node
*/
-void Inode_UncacheNode(int Handle, Uint64 Inode)
+int Inode_UncacheNode(int Handle, Uint64 Inode)
{
tInodeCache *cache;
tCachedInode *ent, *prev;
cache = Inode_int_GetFSCache(Handle);
- if(!cache) return ;
-
- if(Inode > cache->MaxCached) return ;
+ if(!cache) {
+ Log_Notice("Inode", "Invalid cache handle %i used", Handle);
+ return -1;
+ }
+
+ ENTER("iHandle XInode", Handle, Inode);
+
+ if(Inode > cache->MaxCached) {
+ LEAVE('i', -1);
+ return -1;
+ }
// Search Cache
ent = cache->FirstNode;
- prev = (tCachedInode*) &cache->FirstNode; // Special case removal
+ prev = NULL;
for( ; ent; prev = ent, ent = ent->Next )
{
if(ent->Node.Inode < Inode) continue;
- if(ent->Node.Inode > Inode) return;
- ent->Node.ReferenceCount --;
- // Check if node needs to be freed
- if(ent->Node.ReferenceCount == 0)
- {
+ if(ent->Node.Inode > Inode) {
+ LEAVE('i', -1);
+ return -1;
+ }
+ break;
+ }
+
+ LOG("ent = %p", ent);
+
+ if( !ent ) {
+ LEAVE('i', -1);
+ return -1;
+ }
+
+ ent->Node.ReferenceCount --;
+ // Check if node needs to be freed
+ if(ent->Node.ReferenceCount == 0)
+ {
+ if( prev )
prev->Next = ent->Next;
- if(ent->Node.Inode == cache->MaxCached)
- {
- if(ent != cache->FirstNode)
- cache->MaxCached = prev->Node.Inode;
- else
- cache->MaxCached = 0;
- }
-
- free(ent);
+ else
+ cache->FirstNode = ent->Next;
+ if(ent->Node.Inode == cache->MaxCached)
+ {
+ if(ent != cache->FirstNode && prev)
+ cache->MaxCached = prev->Node.Inode;
+ else
+ cache->MaxCached = 0;
}
- return ;
+
+ if(ent->Node.Data)
+ free(ent->Node.Data);
+ free(ent);
+ LOG("Freed");
+ LEAVE('i', 1);
+ return 1;
+ }
+ else
+ {
+ LEAVE('i', 0);
+ return 0;
}
-
- return ;
}
/**
* Acess2 VFS
* - Open, Close and ChDir
*/
+#define SANITY 1
#define DEBUG 0
#include <acess.h>
#include "vfs.h"
extern tVFS_Node *VFS_MemFile_Create(const char *Path);
// === 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 );
// === CODE ===
+void _ReferenceMount(tVFS_Mount *Mount, const char *DebugTag)
+{
+// Log_Debug("VFS", "%s: inc. mntpt '%s' to %i", DebugTag, Mount->MountPoint, Mount->OpenHandleCount+1);
+ Mount->OpenHandleCount ++;
+}
+void _DereferenceMount(tVFS_Mount *Mount, const char *DebugTag)
+{
+// Log_Debug("VFS", "%s: dec. mntpt '%s' to %i", DebugTag, Mount->MountPoint, Mount->OpenHandleCount-1);
+ ASSERT(Mount->OpenHandleCount > 0);
+ Mount->OpenHandleCount --;
+}
/**
* \fn char *VFS_GetAbsPath(const char *Path)
* \brief Create an absolute path from a relative one
*TruePath = malloc( gVFS_RootMount->MountPointLen+1 );
strcpy(*TruePath, gVFS_RootMount->MountPoint);
}
+ _ReferenceMount(gVFS_RootMount, "ParsePath - Fast Tree Root");
if(MountPoint) *MountPoint = gVFS_RootMount;
LEAVE('p', gVFS_RootMount->RootNode);
return gVFS_RootMount->RootNode;
// Find Mountpoint
longestMount = gVFS_RootMount;
+ RWLock_AcquireRead( &glVFS_MountList );
for(mnt = gVFS_Mounts; mnt; mnt = mnt->Next)
{
// Quick Check
// Length Check - If the length is smaller than the longest match sofar
if(mnt->MountPointLen < longestMount->MountPointLen) continue;
// String Compare
- cmp = strcmp(Path, mnt->MountPoint);
+ cmp = strncmp(Path, mnt->MountPoint, mnt->MountPointLen);
+ // Not a match, continue
+ if(cmp != 0) continue;
#if OPEN_MOUNT_ROOT
// Fast Break - Request Mount Root
- if(cmp == 0) {
+ if(Path[mnt->MountPointLen] == '\0') {
if(TruePath) {
*TruePath = malloc( mnt->MountPointLen+1 );
strcpy(*TruePath, mnt->MountPoint);
}
if(MountPoint)
*MountPoint = mnt;
+ RWLock_Release( &glVFS_MountList );
+ LOG("Mount %p root", mnt);
+ _ReferenceMount(mnt, "ParsePath - Mount Root");
LEAVE('p', mnt->RootNode);
return mnt->RootNode;
}
#endif
- // Not a match, continue
- if(cmp != '/') continue;
longestMount = mnt;
}
+ if(!longestMount) {
+ Log_Panic("VFS", "VFS_ParsePath - No mount for '%s'", Path);
+ return NULL;
+ }
+
+ _ReferenceMount(longestMount, "ParsePath");
+ RWLock_Release( &glVFS_MountList );
// Save to shorter variable
mnt = longestMount;
}
// Check if the node has a FindDir method
+ if( !curNode->Type )
+ {
+ LOG("Finddir failure on '%s' - No type", Path);
+ Log_Error("VFS", "Node at '%s' has no type (mount %s:%s)",
+ Path, mnt->Filesystem->Name, mnt->MountPoint);
+ goto _error;
+ }
if( !curNode->Type->FindDir )
{
- LOG("Finddir failure on '%s'", Path);
+ LOG("Finddir failure on '%s' - No FindDir method in %s", Path, curNode->Type->TypeName);
goto _error;
}
LOG("FindDir{=%p}(%p, '%s')", curNode->Type->FindDir, curNode, pathEle);
path_buffer[ curNode->Size ] = '\0';
LOG("path_buffer = '%s'", path_buffer);
strcat(path_buffer, Path + ofs+nextSlash);
+ // TODO: Pass to VFS_GetAbsPath to handle ../. in the symlink
Path = path_buffer;
// Log_Debug("VFS", "VFS_ParsePath: Symlink translated to '%s'", Path);
// EVIL: Goto :)
LOG("Symlink -> '%s', restart", Path);
+ _DereferenceMount(mnt, "ParsePath - sym");
goto restart_parse;
}
LOG("tmpNode = %p", tmpNode);
// Check if file was found
if(!tmpNode) {
- LOG("Node '%s' not found in dir '%s'", &Path[ofs], Path);
+ LOG("Node '%s' not found in dir '%.*s'", &Path[ofs], ofs, Path);
goto _error;
}
_CloseNode( curNode );
*MountPoint = mnt;
}
+ // Leave the mointpoint's count increased
+
LEAVE('p', tmpNode);
return tmpNode;
free(*TruePath);
*TruePath = NULL;
}
+ // Open failed, so decrement the open handle count
+ _DereferenceMount(mnt, "ParsePath - error");
+
LEAVE('n');
return NULL;
}
errno = EACCES;
LEAVE_RET('i', -1);
}
+
+ if( MM_GetPhysAddr(Node->Type) == 0 ) {
+ Log_Error("VFS", "Node %p from mount '%s' (%s) has a bad type (%p)",
+ Node, Mount->MountPoint, Mount->Filesystem->Name, Node->Type);
+ errno = EINTERNAL;
+ LEAVE_RET('i', -1);
+ }
i = VFS_AllocHandle( !!(Mode & VFS_OPENFLAG_USER), Node, Mode );
if( i < 0 ) {
if( !node && (Flags & VFS_OPENFLAG_CREATE) )
{
// TODO: Translate `Mode` into ACL and node flags
- // Get parent, create node
- VFS_MkNod(absPath, 0);
- node = VFS_ParsePath(absPath, NULL, &mnt);
+ Uint new_flags = 0;
+
+ // Split path at final separator
+ char *file = strrchr(absPath, '/');
+ *file = '\0';
+ file ++;
+
+ // Get parent node
+ tVFS_Mount *pmnt;
+ tVFS_Node *pnode = VFS_ParsePath(absPath, NULL, &pmnt);
+ if(!pnode) {
+ LOG("Unable to open parent '%s'", absPath);
+ free(absPath);
+ errno = ENOENT;
+ LEAVE_RET('i', -1);
+ }
+
+ // Check ACLs on the parent
+ if( !VFS_CheckACL(pnode, VFS_PERM_EXECUTE|VFS_PERM_WRITE) ) {
+ errno = EACCES;
+ goto _pnode_err;
+ }
+
+ // Check that there's a MkNod method
+ if( !pnode->Type || !pnode->Type->MkNod ) {
+ Log_Warning("VFS", "VFS_Open - Directory has no MkNod method");
+ errno = EINVAL;
+ goto _pnode_err;
+ }
+
+ node = pnode->Type->MkNod(pnode, file, new_flags);
+ if( !node ) {
+ LOG("Cannot create node '%s' in '%s'", file, absPath);
+ errno = ENOENT;
+ goto _pnode_err;
+ }
+ // Set mountpoint (and increment open handle count)
+ mnt = pmnt;
+ _ReferenceMount(mnt, "Open - create");
+ // Fall through on error check
+
+ _CloseNode(pnode);
+ _DereferenceMount(pmnt, "Open - create");
+ goto _pnode_ok;
+
+ _pnode_err:
+ if( pnode ) {
+ _CloseNode(pnode);
+ _DereferenceMount(pmnt, "Open - create,fail");
+ free(absPath);
+ }
+ LEAVE('i', -1);
+ return -1;
}
+ _pnode_ok:
// Free generated path
free(absPath);
{
LOG("Cannot find node");
errno = ENOENT;
- LEAVE_RET('i', -1);
+ goto _error;
}
// Check for symlinks
char tmppath[node->Size+1];
if( node->Size > MAX_PATH_LEN ) {
Log_Warning("VFS", "VFS_Open - Symlink is too long (%i)", node->Size);
- LEAVE_RET('i', -1);
+ goto _error;
}
if( !node->Type || !node->Type->Read ) {
Log_Warning("VFS", "VFS_Open - No read method on symlink");
- LEAVE_RET('i', -1);
+ goto _error;
}
// Read symlink's path
node->Type->Read( node, 0, node->Size, tmppath );
tmppath[ node->Size ] = '\0';
_CloseNode( node );
+ _DereferenceMount(mnt, "Open - symlink");
// Open the target
node = VFS_ParsePath(tmppath, NULL, &mnt);
if(!node) {
LOG("Cannot find symlink target node (%s)", tmppath);
errno = ENOENT;
- LEAVE_RET('i', -1);
+ goto _error;
}
}
- LEAVE_RET('x', VFS_int_CreateHandle(node, mnt, Flags));
+ int ret = VFS_int_CreateHandle(node, mnt, Flags);
+ LEAVE_RET('x', ret);
+_error:
+ if( node )
+ {
+ _DereferenceMount(mnt, "Open - error");
+ _CloseNode(node);
+ }
+ LEAVE_RET('i', -1);
}
LEAVE_RET('i', -1);
}
+ // Increment open handle count, no problems with the mount going away as `h` is already open on it
+ _ReferenceMount(h->Mount, "OpenChild");
+
LEAVE_RET('x', VFS_int_CreateHandle(node, h->Mount, Mode));
}
Log_Warning("VFS", "Invalid file handle passed to VFS_Close, 0x%x", FD);
return;
}
-
+
+ if( h->Node == NULL ) {
+ Log_Warning("VFS", "Non-open handle passed to VFS_Close, 0x%x", FD);
+ return ;
+ }
+
#if VALIDATE_VFS_FUNCTIPONS
if(h->Node->Close && !MM_GetPhysAddr(h->Node->Close)) {
Log_Warning("VFS", "Node %p's ->Close method is invalid (%p)",
}
#endif
+ LOG("Handle %x", FD);
_CloseNode(h->Node);
-
+
+ if( h->Mount ) {
+ _DereferenceMount(h->Mount, "Close");
+ }
+
h->Node = NULL;
}
*cwdptr = buf;
}
- Log("Updated CWD to '%s'", buf);
+ Log_Debug("VFS", "Updated CWD to '%s'", buf);
return 1;
}
#include <semaphore.h>
#include <threads.h>
#include <events.h>
+#include <timers.h>
// === CONSTANTS ===
#define NUM_THREADS_PER_ALLOC 4
}
}
- // - Fast return for polling
- if( Timeout && *Timeout == 0 ) return 0;
-
// Wait for things
- if( !Timeout || *Timeout > 0 )
+ if( !Timeout )
{
LOG("Semaphore_Wait()");
// TODO: Actual timeout
Threads_WaitEvents( THREAD_EVENT_VFS );
}
+ 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
+ Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_TIMER );
+ Time_FreeTimer(t);
+ }
// Get return value
ret = 0;
VFS_int_Select_RemThread(*list, thisthread);
ret = ret || *flag == wanted;
}
+
+ Threads_ClearEvent( THREAD_EVENT_VFS );
+ Threads_ClearEvent( THREAD_EVENT_TIMER );
LEAVE('i', ret);
return ret;
LEAVE('i', ret);
return ret;
}
-
- // TODO: Implement timeout
- LOG("Timeout = %p", Timeout);
-
- // Wait (only if there is no timeout, or it is greater than zero
- if( !Timeout || *Timeout > 0 )
+
+ // Wait for things
+ if( !Timeout )
{
- // TODO: Timeout
- // TODO: Allow extra events to be waited upon
+ LOG("Semaphore_Wait()");
+ // TODO: Actual timeout
Threads_WaitEvents( THREAD_EVENT_VFS|ExtraEvents );
}
-
+ 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
+ Threads_WaitEvents( THREAD_EVENT_VFS|THREAD_EVENT_TIMER|ExtraEvents );
+ Time_FreeTimer(t);
+ }
// Fill output (modify *Handles)
// - Also, de-register
ret = VFS_int_Select_Deregister(thisthread, MaxHandle, ReadHandles, 0, IsKernel);
ret += VFS_int_Select_Deregister(thisthread, MaxHandle, WriteHandles, 1, IsKernel);
ret += VFS_int_Select_Deregister(thisthread, MaxHandle, ErrHandles, 2, IsKernel);
+
+ Threads_ClearEvent( THREAD_EVENT_VFS );
+ Threads_ClearEvent( THREAD_EVENT_TIMER );
+
LEAVE('i', ret);
return ret;
}
}
count ++;
if( MaxAllowed && count >= MaxAllowed ) {
+ Mutex_Release(&List->Lock);
LEAVE('i', 1);
return 1;
}
--- /dev/null
+/*
+ * Acess2 NVidia Graphics Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Driver Core
+ *
+ * Reference: linux/drivers/video/nvidia
+ */
+#define DEBUG 1
+#define VERSION VER2(0,1)
+#include <acess.h>
+#include <modules.h>
+#include <fs_devfs.h>
+#include <drv_pci.h>
+#include "regs.h"
+
+// === PROTOTYPES ===
+ int NV_Install(char **Arguments);
+ int NV_Cleanup(void);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, Video_NVidia, VERSION, NV_Install, NV_Cleanup, NULL);
+
+// === CODE ===
+int NV_Install(char **Arguments)
+{
+ return MODERR_NOTNEEDED;
+}
+
+int NV_Cleanup(void)
+{
+ return 0;
+}
+
--- /dev/null
+/*
+ * Acess2 NVidia Graphics Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * regs.h
+ * - Register definitions
+ */
+#ifndef _NVIDIA__REGS_H_
+#define _NVIDIA__REGS_H_
+
+// CRT Controller Registers
+enum eNVRegs_CRTC
+{
+ NUM_CRTC_REGS
+};
+
+// Attribute Controller registers
+enum eNVRegs_ATC
+{
+ NUM_ATC_REGS
+};
+
+enum eNVRegs_GRC
+{
+ NUM_GRC_REGS
+};
+
+// Sequencer registers
+enum eNVRegs_SEQ
+{
+ NUM_SEQ_REGS
+};
+
+struct sNVRegDump
+{
+ Uint8 atc_regs[NUM_ATC_REGS];
+ Uint8 crtc_regs[NUM_CRTC_REGS];
+ Uint8 gra_regs[NUM_GRC_REGS];
+ Uint8 seq_regs[NUM_SEQ_REGS];
+};
+
+#endif
+
--- /dev/null
+Display CMD Registers
+00000000000000d [Tegra2Vi] 0 - [0x000] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x001] = 0x00000100 (-)
+00000000000000d [Tegra2Vi] 0 - [0x002] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x003] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x004] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x005] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x006] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x007] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x008] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x009] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00A] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00B] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00C] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00D] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00E] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x00F] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x010] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x011] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x012] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x013] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x014] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x015] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x016] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x017] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x018] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x019] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x01A] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x028] = 0x0000011A (-)
+00000000000000d [Tegra2Vi] 0 - [0x029] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02A] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02B] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02C] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02D] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02E] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x02F] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x030] = 0xF000F800 (-)
+00000000000000d [Tegra2Vi] 0 - [0x031] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x032] = 0x00000020 (-)
+00000000000000d [Tegra2Vi] 0 - [0x033] = 0x00000114 (-)
+00000000000000d [Tegra2Vi] 0 - [0x034] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x035] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x036] = 0x00050155 (-)
+00000000000000d [Tegra2Vi] 0 - [0x037] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x038] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x039] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x03A] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x03B] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x03C] = 0x0009060C (-)
+00000000000000d [Tegra2Vi] 0 - [0x03D] = 0x000F021C (-)
+00000000000000d [Tegra2Vi] 0 - [0x03E] = 0x000D0210 (-)
+00000000000000d [Tegra2Vi] 0 - [0x03F] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x040] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x041] = 0x00000000 (DC_CMD_STATE_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x042] = 0x00000010 (DC_CMD_DISPLAY_WINDOW_HEADER_0)
+00000000000000d [Tegra2Vi] 0 - [0x043] = 0x00000000 (DC_CMD_REG_ACT_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - Display COM Registers
+00000000000000d [Tegra2Vi] 0 - [0x300] = 0x00000000 (DC_COM_CRC_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x301] = 0x00000000 (DC_COM_CRC_CHECKSUM_0)
+00000000000000d [Tegra2Vi] 0 - [0x302] = 0x00000000 (DC_COM_PIN_OUTPUT_ENABLE0_0)
+00000000000000d [Tegra2Vi] 0 - [0x303] = 0x00000000 (DC_COM_PIN_OUTPUT_ENABLE1_0)
+00000000000000d [Tegra2Vi] 0 - [0x304] = 0x00000000 (DC_COM_PIN_OUTPUT_ENABLE2_0)
+00000000000000d [Tegra2Vi] 0 - [0x305] = 0x00000000 (DC_COM_PIN_OUTPUT_ENABLE3_0)
+00000000000000d [Tegra2Vi] 0 - [0x306] = 0x00000000 (DC_COM_PIN_OUTPUT_POLARITY0_0)
+00000000000000d [Tegra2Vi] 0 - [0x307] = 0x01000000 (DC_COM_PIN_OUTPUT_POLARITY1_0)
+00000000000000d [Tegra2Vi] 0 - [0x308] = 0x00000000 (DC_COM_PIN_OUTPUT_POLARITY2_0)
+00000000000000d [Tegra2Vi] 0 - [0x309] = 0x00000000 (DC_COM_PIN_OUTPUT_POLARITY3_0)
+00000000000000d [Tegra2Vi] 0 - [0x30A] = 0x00000000 (DC_COM_PIN_OUTPUT_DATA0_0)
+00000000000000d [Tegra2Vi] 0 - [0x30B] = 0x00000000 (DC_COM_PIN_OUTPUT_DATA1_0)
+00000000000000d [Tegra2Vi] 0 - [0x30C] = 0x00000000 (DC_COM_PIN_OUTPUT_DATA2_0)
+00000000000000d [Tegra2Vi] 0 - [0x30D] = 0x00000000 (DC_COM_PIN_OUTPUT_DATA3_0)
+00000000000000d [Tegra2Vi] 0 - [0x30E] = 0x00000000 (DC_COM_PIN_INPUT_ENABLE0_0)
+00000000000000d [Tegra2Vi] 0 - [0x30F] = 0x00000000 (DC_COM_PIN_INPUT_ENABLE1_0)
+00000000000000d [Tegra2Vi] 0 - [0x310] = 0x00000000 (DC_COM_PIN_INPUT_ENABLE2_0)
+00000000000000d [Tegra2Vi] 0 - [0x311] = 0x00000000 (DC_COM_PIN_INPUT_ENABLE3_0)
+00000000000000d [Tegra2Vi] 0 - [0x312] = 0x00000000 (DC_COM_PIN_INPUT_DATA0_0)
+00000000000000d [Tegra2Vi] 0 - [0x313] = 0x00000000 (DC_COM_PIN_INPUT_DATA1_0)
+00000000000000d [Tegra2Vi] 0 - [0x314] = 0x00000000 (DC_COM_PIN_OUTPUT_SELECT0_0)
+00000000000000d [Tegra2Vi] 0 - [0x315] = 0x00000000 (DC_COM_PIN_OUTPUT_SELECT1_0)
+00000000000000d [Tegra2Vi] 0 - [0x316] = 0x00000000 (DC_COM_PIN_OUTPUT_SELECT2_0)
+00000000000000d [Tegra2Vi] 0 - [0x317] = 0x00000000 (DC_COM_PIN_OUTPUT_SELECT3_0)
+00000000000000d [Tegra2Vi] 0 - [0x318] = 0x00210222 (DC_COM_PIN_OUTPUT_SELECT4_0)
+00000000000000d [Tegra2Vi] 0 - [0x319] = 0x00002200 (DC_COM_PIN_OUTPUT_SELECT5_0)
+00000000000000d [Tegra2Vi] 0 - [0x31A] = 0x00020000 (DC_COM_PIN_OUTPUT_SELECT6_0)
+00000000000000d [Tegra2Vi] 0 - [0x31B] = 0x00000000 (DC_COM_PIN_MISC_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x31C] = 0x00840152 (-)
+00000000000000d [Tegra2Vi] 0 - [0x31D] = 0x00000144 (-)
+00000000000000d [Tegra2Vi] 0 - [0x31E] = 0x00700111 (-)
+00000000000000d [Tegra2Vi] 0 - [0x31F] = 0x00000077 (-)
+00000000000000d [Tegra2Vi] 0 - [0x320] = 0x01070023 (-)
+00000000000000d [Tegra2Vi] 0 - [0x321] = 0x0000D317 (-)
+00000000000000d [Tegra2Vi] 0 - [0x322] = 0xEAEE54C2 (-)
+00000000000000d [Tegra2Vi] 0 - [0x323] = 0x6BDC5DA4 (-)
+00000000000000d [Tegra2Vi] 0 - [0x324] = 0x05004210 (-)
+00000000000000d [Tegra2Vi] 0 - [0x325] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x326] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x327] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x328] = 0x00000400 (-)
+00000000000000d [Tegra2Vi] 0 - [0x329] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - Display DISP Registers
+00000000000000d [Tegra2Vi] 0 - [0x400] = 0x00000000 (DC_DISP_DISP_SIGNAL_OPTIONS0_0)
+00000000000000d [Tegra2Vi] 0 - [0x401] = 0x00000000 (DC_DISP_DISP_SIGNAL_OPTIONS1_0)
+00000000000000d [Tegra2Vi] 0 - [0x402] = 0x00000000 (DC_DISP_DISP_WIN_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x403] = 0x00000020 (DC_DISP_MEM_HIGH_PRIORITY_0)
+00000000000000d [Tegra2Vi] 0 - [0x404] = 0x00000001 (DC_DISP_MEM_HIGH_PRIORITY_TIMER_0)
+00000000000000d [Tegra2Vi] 0 - [0x405] = 0x00000000 (DC_DISP_DISP_TIMING_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x406] = 0x0001000B (DC_DISP_REF_TO_SYNC_0)
+00000000000000d [Tegra2Vi] 0 - [0x407] = 0x0004003A (DC_DISP_SYNC_WIDTH_0)
+00000000000000d [Tegra2Vi] 0 - [0x408] = 0x0004003A (DC_DISP_BACK_PORCH_0)
+00000000000000d [Tegra2Vi] 0 - [0x409] = 0x03000400 (DC_DISP_DISP_ACTIVE_0)
+00000000000000d [Tegra2Vi] 0 - [0x40A] = 0x0004003A (DC_DISP_FRONT_PORCH_0)
+00000000000000d [Tegra2Vi] 0 - [0x40B] = 0x00000918 (DC_DISP_H_PULSE0_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x40C] = 0x1D970F55 (DC_DISP_H_PULSE0_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x40D] = 0x02AA0AC5 (DC_DISP_H_PULSE0_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x40E] = 0x039B00AA (DC_DISP_H_PULSE0_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x40F] = 0x044D1989 (DC_DISP_H_PULSE0_POSITION_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x410] = 0x00000480 (DC_DISP_H_PULSE1_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x411] = 0x198B1E2D (DC_DISP_H_PULSE1_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x412] = 0x04910669 (DC_DISP_H_PULSE1_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x413] = 0x08381FA4 (DC_DISP_H_PULSE1_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x414] = 0x009C0625 (DC_DISP_H_PULSE1_POSITION_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x415] = 0x00000608 (DC_DISP_H_PULSE2_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x416] = 0x0C001469 (DC_DISP_H_PULSE2_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x417] = 0x07690B17 (DC_DISP_H_PULSE2_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x418] = 0x00360257 (DC_DISP_H_PULSE2_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x419] = 0x1F1809D6 (DC_DISP_H_PULSE2_POSITION_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x41A] = 0x000007D0 (DC_DISP_V_PULSE0_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x41B] = 0x15CB1886 (DC_DISP_V_PULSE0_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x41C] = 0x02401EA8 (DC_DISP_V_PULSE0_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x41D] = 0x09750264 (DC_DISP_V_PULSE0_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x41E] = 0x00000010 (DC_DISP_V_PULSE1_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x41F] = 0x16BA0A17 (DC_DISP_V_PULSE1_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x420] = 0x1AE21A90 (DC_DISP_V_PULSE1_POSITION_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x421] = 0x06860AD7 (DC_DISP_V_PULSE1_POSITION_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x422] = 0x00000000 (DC_DISP_V_PULSE2_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x423] = 0x0CC31C03 (DC_DISP_V_PULSE2_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x424] = 0x00000000 (DC_DISP_V_PULSE3_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x425] = 0x07071A0E (DC_DISP_V_PULSE3_POSITION_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x426] = 0x02960DA3 (DC_DISP_M0_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x427] = 0x1F8C1951 (DC_DISP_M1_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x428] = 0x15070003 (DC_DISP_DI_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x429] = 0x0000CEF5 (DC_DISP_PP_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x42A] = 0x10D08381 (DC_DISP_PP_SELECT_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x42B] = 0x1C2CB600 (DC_DISP_PP_SELECT_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x42C] = 0x73B3DE7D (DC_DISP_PP_SELECT_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x42D] = 0x0779CA03 (DC_DISP_PP_SELECT_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x42E] = 0x00000005 (DC_DISP_DISP_CLOCK_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x42F] = 0x00000000 (DC_DISP_DISP_INTERFACE_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x430] = 0x00000200 (DC_DISP_DISP_COLOR_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x431] = 0x00010001 (DC_DISP_SHIFT_CLOCK_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x432] = 0x00000005 (DC_DISP_DATA_ENABLE_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x433] = 0x00000000 (DC_DISP_SERIAL_INTERFACE_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x434] = 0x00000000 (DC_DISP_LCD_SPI_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x435] = 0x00DA0731 (DC_DISP_BORDER_COLOR_0)
+00000000000000d [Tegra2Vi] 0 - [0x436] = 0x00E9B832 (DC_DISP_COLOR_KEY0_LOWER_0)
+00000000000000d [Tegra2Vi] 0 - [0x437] = 0x006B4475 (DC_DISP_COLOR_KEY0_UPPER_0)
+00000000000000d [Tegra2Vi] 0 - [0x438] = 0x000FA6FB (DC_DISP_COLOR_KEY1_LOWER_0)
+00000000000000d [Tegra2Vi] 0 - [0x439] = 0x00304301 (DC_DISP_COLOR_KEY1_UPPER_0)
+00000000000000d [Tegra2Vi] 0 - [0x43A] = 0x00000000 (_DC_DISP_UNUSED_43A)
+00000000000000d [Tegra2Vi] 0 - [0x43B] = 0x00000000 (_DC_DISP_UNUSED_43B)
+00000000000000d [Tegra2Vi] 0 - [0x43C] = 0x004962ED (DC_DISP_CURSOR_FOREGROUND_0)
+00000000000000d [Tegra2Vi] 0 - [0x43D] = 0x0063462E (DC_DISP_CURSOR_BACKGROUND_0)
+00000000000000d [Tegra2Vi] 0 - [0x43E] = 0x3021352C (DC_DISP_CURSOR_START_ADDR_0)
+00000000000000d [Tegra2Vi] 0 - [0x43F] = 0x3021352C (DC_DISP_CURSOR_START_ADDR_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x440] = 0x21B10B4B (DC_DISP_CURSOR_POSITION_0)
+00000000000000d [Tegra2Vi] 0 - [0x441] = 0x21B10B4B (DC_DISP_CURSOR_POSITION_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x442] = 0x00000030 (DC_DISP_INIT_SEQ_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x443] = 0x8C0BF46E (DC_DISP_SPI_INIT_SEQ_DATA_A_0)
+00000000000000d [Tegra2Vi] 0 - [0x444] = 0xE08C7EBA (DC_DISP_SPI_INIT_SEQ_DATA_B_0)
+00000000000000d [Tegra2Vi] 0 - [0x445] = 0x89A6A8FD (DC_DISP_SPI_INIT_SEQ_DATA_C_0)
+00000000000000d [Tegra2Vi] 0 - [0x446] = 0x80D5BC36 (DC_DISP_SPI_INIT_SEQ_DATA_D_0)
+00000000000000d [Tegra2Vi] 0 - [0x480] = 0x00000000 (DC_DISP_DC_MCCIF_FIFOCTRL_0)
+00000000000000d [Tegra2Vi] 0 - [0x481] = 0xCF401F1F (DC_DISP_MCCIF_DISPLAY0A_HYST_0)
+00000000000000d [Tegra2Vi] 0 - [0x482] = 0xCF081F1F (DC_DISP_MCCIF_DISPLAY0B_HYST_0)
+00000000000000d [Tegra2Vi] 0 - [0x483] = 0xCF081F1F (DC_DISP_MCCIF_DISPLAY0C_HYST_0)
+00000000000000d [Tegra2Vi] 0 - [0x484] = 0xCF081F1F (DC_DISP_MCCIF_DISPLAY1B_HYST_0)
+00000000000000d [Tegra2Vi] 0 - [0x4C0] = 0x00000000 (DC_DISP_DAC_CRT_CTRL_0)
+00000000000000d [Tegra2Vi] 0 - [0x4C1] = 0x00000002 (DC_DISP_DISP_MISC_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - WINC_A Registers
+00000000000000d [Tegra2Vi] 0 - [0x700] = 0x40000040 (DC_WIN_A_WIN_OPTIONS_0)
+00000000000000d [Tegra2Vi] 0 - [0x701] = 0x00000000 (DC_WIN_A_BYTE_SWAP_0)
+00000000000000d [Tegra2Vi] 0 - [0x702] = 0x00000000 (DC_WIN_A_BUFFER_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x703] = 0x00000006 (DC_WIN_A_COLOR_DEPTH_0)
+00000000000000d [Tegra2Vi] 0 - [0x704] = 0x00000000 (DC_WIN_A_POSITION_0)
+00000000000000d [Tegra2Vi] 0 - [0x705] = 0x03000400 (DC_WIN_A_SIZE_0)
+00000000000000d [Tegra2Vi] 0 - [0x706] = 0x03000800 (DC_WIN_A_PRESCALED_SIZE_0)
+00000000000000d [Tegra2Vi] 0 - [0x707] = 0x00000000 (DC_WIN_A_H_INITIAL_DDA_0)
+00000000000000d [Tegra2Vi] 0 - [0x708] = 0x00000000 (DC_WIN_A_V_INITIAL_DDA_0)
+00000000000000d [Tegra2Vi] 0 - [0x709] = 0x10051004 (DC_WIN_A_DDA_INCREMENT_0)
+00000000000000d [Tegra2Vi] 0 - [0x70A] = 0x00000800 (DC_WIN_A_LINE_STRIDE_0)
+00000000000000d [Tegra2Vi] 0 - [0x70B] = 0x00000000 (DC_WIN_A_BUF_STRIDE_0)
+00000000000000d [Tegra2Vi] 0 - [0x70C] = 0x00000000 (DC_WIN_A_BUFFER_ADDR_MODE_0)
+00000000000000d [Tegra2Vi] 0 - [0x70D] = 0x00000000 (DC_WIN_A_DV_CONTROL_0)
+00000000000000d [Tegra2Vi] 0 - [0x70E] = 0x00000404 (DC_WIN_A_BLEND_NOKEY_0)
+00000000000000d [Tegra2Vi] 0 - [0x70F] = 0x0000FF00 (-)
+00000000000000d [Tegra2Vi] 0 - [0x710] = 0x0000FF00 (-)
+00000000000000d [Tegra2Vi] 0 - [0x711] = 0x00EB0B0D (-)
+00000000000000d [Tegra2Vi] 0 - [0x712] = 0x000C270E (-)
+00000000000000d [Tegra2Vi] 0 - [0x713] = 0x00263E09 (-)
+00000000000000d [Tegra2Vi] 0 - [0x714] = 0x446996C9 (-)
+00000000000000d [Tegra2Vi] 0 - WINBUF_A
+00000000000000d [Tegra2Vi] 0 - [0x800] = 0x1C022000 (DC_WINBUF_A_START_ADDR_0)
+00000000000000d [Tegra2Vi] 0 - [0x801] = 0x1C022000 (DC_WINBUF_A_START_ADDR_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x802] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x803] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x804] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x805] = 0x00000000 (-)
+00000000000000d [Tegra2Vi] 0 - [0x806] = 0x00000000 (DC_WINBUF_A_ADDR_H_OFFSET_0)
+00000000000000d [Tegra2Vi] 0 - [0x807] = 0x00000000 (DC_WINBUF_A_ADDR_H_OFFSET_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x808] = 0x00000000 (DC_WINBUF_A_ADDR_V_OFFSET_0)
+00000000000000d [Tegra2Vi] 0 - [0x809] = 0x00000000 (DC_WINBUF_A_ADDR_V_OFFSET_NS_0)
+00000000000000d [Tegra2Vi] 0 - [0x80A] = 0x00000000 (DC_WINBUF_A_UFLOW_STATUS)
* - Driver core
*/
#define DEBUG 0
+#define DUMP_REGISTERS 1
#define VERSION ((0<<8)|10)
#include <acess.h>
#include <errno.h>
tVideo_IOCtl_Pos gTegra2Vid_CursorPos;
// === CODE ===
+inline void _dumpreg(int i)
+{
+ Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x (%s)", i, gpTegra2Vid_IOMem[i],
+ (csaTegra2Vid_RegisterNames[i] ? csaTegra2Vid_RegisterNames[i] : "-"));
+}
/**
*/
int Tegra2Vid_Install(char **Arguments)
// KeyVal_Parse(&gTegra2Vid_KeyValueParser, Arguments);
gpTegra2Vid_IOMem = (void*)MM_MapHWPages(gTegra2Vid_PhysBase, 256/4);
- #if 0
+ #if DUMP_REGISTERS
{
Log_Debug("Tegra2Vid", "Display CMD Registers");
- for( int i = 0x000; i <= 0x01A; i ++ )
- Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
- for( int i = 0x028; i <= 0x043; i ++ )
- Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
+ for( int i = 0x000; i <= 0x01A; i ++ ) _dumpreg(i);
+ for( int i = 0x028; i <= 0x043; i ++ ) _dumpreg(i);
Log_Debug("Tegra2Vid", "Display COM Registers");
- for( int i = 0x300; i <= 0x329; i ++ )
- Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
+ for( int i = 0x300; i <= 0x329; i ++ ) _dumpreg(i);
Log_Debug("Tegra2Vid", "Display DISP Registers");
- for( int i = 0x400; i <= 0x446; i ++ )
- Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
- for( int i = 0x480; i <= 0x484; i ++ )
- Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
- for( int i = 0x4C0; i <= 0x4C1; i ++ )
- Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
-
+ for( int i = 0x400; i <= 0x446; i ++ ) _dumpreg(i);
+ for( int i = 0x480; i <= 0x484; i ++ ) _dumpreg(i);
+ for( int i = 0x4C0; i <= 0x4C1; i ++ ) _dumpreg(i);
Log_Debug("Tegra2Vid", "WINC_A Registers");
- for( int i = 0x700; i <= 0x714; i ++ )
- Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
+ for( int i = 0x700; i <= 0x714; i ++ ) _dumpreg(i);
Log_Debug("Tegra2Vid", "WINBUF_A");
- for( int i = 0x800; i <= 0x80A; i ++ )
- Log_Debug("Tegra2Vid", "[0x%03x] = 0x%08x", i, gpTegra2Vid_IOMem[i]);
+ for( int i = 0x800; i <= 0x80A; i ++ ) _dumpreg(i);
}
#endif
-// return 1;
// HACK!!!
#if 0
);
memset(gpTegra2Vid_Framebuffer, 0xFF, 0x1000);
-// gpTegra2Vid_IOMem[DC_WIN_A_WIN_OPTIONS_0] &= ~0x40;
+#if 0
+ gpTegra2Vid_IOMem[DC_WIN_A_WIN_OPTIONS_0] = (1 << 30);
gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
+ gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0];
+ gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] =
+ gTegra2Vid_DrvUtil_BufInfo.Pitch =
+ 1680*4;
+ gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
+ gTegra2Vid_DrvUtil_BufInfo.Width = 1680;
+ gTegra2Vid_DrvUtil_BufInfo.Height = 1050;
+#else
+ gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 13; // Could be 13 (BGR/RGB)
+ gpTegra2Vid_IOMem[DC_WIN_A_LINE_STRIDE_0] =
+ gTegra2Vid_DrvUtil_BufInfo.Pitch = 1024*4;
+ gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
gTegra2Vid_DrvUtil_BufInfo.Width = 1024;
gTegra2Vid_DrvUtil_BufInfo.Height = 768;
- gTegra2Vid_DrvUtil_BufInfo.Pitch = 1024*4;
- gTegra2Vid_DrvUtil_BufInfo.Depth = 32;
gTegra2Vid_DrvUtil_BufInfo.Framebuffer = gpTegra2Vid_Framebuffer;
+#endif
+ gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
// Tegra2Vid_int_SetMode(4);
{
const struct sTegra2_Disp_Mode *mode = &caTegra2Vid_Modes[Mode];
int w = mode->W, h = mode->H; // Horizontal/Vertical Active
- *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_FRONT_PORCH_0) = (mode->VFP << 16) | mode->HFP;
- *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_SYNC_WIDTH_0) = (mode->HS << 16) | mode->HS;
- *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_BACK_PORCH_0) = (mode->VBP << 16) | mode->HBP;
- *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_ACTIVE_0) = (mode->H << 16) | mode->W;
-
- *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_POSITION_0) = 0;
- *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_SIZE_0) = (h << 16) | w;
- *(Uint32*)(gpTegra2Vid_IOMem + DC_DISP_DISP_COLOR_CONTROL_0) = 0x8; // BASE888
- *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_COLOR_DEPTH_0) = 12; // Could be 13 (BGR/RGB)
- *(Uint32*)(gpTegra2Vid_IOMem + DC_WIN_A_PRESCALED_SIZE_0) = (h << 16) | w;
+ gpTegra2Vid_IOMem[DC_DISP_FRONT_PORCH_0] = (mode->VFP << 16) | mode->HFP;
+ gpTegra2Vid_IOMem[DC_DISP_SYNC_WIDTH_0] = (mode->HS << 16) | mode->HS;
+ gpTegra2Vid_IOMem[DC_DISP_BACK_PORCH_0] = (mode->VBP << 16) | mode->HBP;
+ gpTegra2Vid_IOMem[DC_DISP_DISP_ACTIVE_0] = (mode->H << 16) | mode->W;
+
+ gpTegra2Vid_IOMem[DC_WIN_A_POSITION_0] = 0;
+ gpTegra2Vid_IOMem[DC_WIN_A_SIZE_0] = (h << 16) | w;
+ gpTegra2Vid_IOMem[DC_DISP_DISP_COLOR_CONTROL_0] = 0x8; // BASE888
+ gpTegra2Vid_IOMem[DC_WIN_A_COLOR_DEPTH_0] = 12; // Could be 13 (BGR/RGB)
+ gpTegra2Vid_IOMem[DC_WIN_A_PRESCALED_SIZE_0] = (h << 16) | w;
Log_Debug("Tegra2Vid", "Mode %i (%ix%i) selected", Mode, w, h);
giTegra2Vid_FramebufferSize = w*h*4;
+ // TODO: Does this need RAM or unmapped space?
gpTegra2Vid_Framebuffer = (void*)MM_AllocDMA(
(giTegra2Vid_FramebufferSize + PAGE_SIZE-1) / PAGE_SIZE,
32,
);
// Tell hardware
- *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_START_ADDR_0) = gTegra2Vid_FramebufferPhys;
- *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_V_OFFSET_0) = 0; // Y offset
- *(Uint32*)(gpTegra2Vid_IOMem + DC_WINBUF_A_ADDR_H_OFFSET_0) = 0; // X offset
+ gpTegra2Vid_IOMem[DC_WINBUF_A_START_ADDR_0] = gTegra2Vid_FramebufferPhys;
+ gpTegra2Vid_IOMem[DC_WINBUF_A_ADDR_V_OFFSET_0] = 0; // Y offset
+ gpTegra2Vid_IOMem[DC_WINBUF_A_ADDR_H_OFFSET_0] = 0; // X offset
}
+ gpTegra2Vid_IOMem[DC_CMD_STATE_CONTROL_0] = WIN_A_ACT_REQ;
+
return 0;
}
Uint16 HBP, VBP;
} caTegra2Vid_Modes[] = {
// TODO: VESA timings
-// {720, 487, 16,33, 63, 33, 59, 133}, // NTSC 2
-// {720, 576, 12,33, 63, 33, 69, 193}, // PAL 2 (VFP shown as 2/33, used 33)
-// {720, 483, 16, 6, 63, 6, 59, 30}, // 480p
-// {1280, 720, 70, 5, 804, 6, 220, 20}, // 720p
-// {1920,1080, 44, 4, 884, 5, 148, 36}, // 1080p
+ {1024, 768, 58, 4, 58, 4, 58, 4}, // 1024x768 (reset), RtS=11,4
+ // TV Timings
+ {720, 487, 16,33, 63, 33, 59, 133}, // NTSC 2
+ {720, 576, 12,33, 63, 33, 69, 193}, // PAL 2 (VFP shown as 2/33, used 33)
+ {720, 483, 16, 6, 63, 6, 59, 30}, // 480p
+ {1280, 720, 70, 5, 804, 6, 220, 20}, // 720p
+ {1920,1080, 44, 4, 884, 5, 148, 36}, // 1080p
// TODO: Can all but HA/VA be constant and those select the resolution?
};
const int ciTegra2Vid_ModeCount = sizeof(caTegra2Vid_Modes)/sizeof(caTegra2Vid_Modes[0]);
DC_WIN_A_BUFFER_ADDR_MODE_0,
DC_WIN_A_DV_CONTROL_0,
DC_WIN_A_BLEND_NOKEY_0,
+ DC_WIN_A_BLEND_1WIN_0,
+ DC_WIN_A_BLEND_2WIN_B_0,
+ DC_WIN_A_BLEND_2WIN_C_0,
+ DC_WIN_A_BLEND_3WIN_BC_0,
+ DC_WIN_A_HP_FETCH_CONTROL_0,
+
DC_WINBUF_A_START_ADDR_0 = 0x800,
DC_WINBUF_A_START_ADDR_NS_0,
DC_WINBUF_A_ADDR_V_OFFSET_NS_0,
};
+#if DEBUG || DUMP_REGISTERS
+const char * const csaTegra2Vid_RegisterNames[] = {
+ [0x000] = "DC_CMD_GENERAL_INCR_SYNCPT_0",
+ "DC_CMD_GENERAL_INCR_SYNCPT_CNTRL_0",
+ "DC_CMD_GENERAL_INCR_SYNCPT_ERROR_0",
+ [0x008] = "DC_CMD_WIN_A_INCR_SYNCPT_0",
+ "DC_CMD_WIN_A_INCR_SYNCPT_CNTRL_0",
+ "DC_CMD_WIN_A_INCR_SYNCPT_ERROR_0",
+ [0x010] = "DC_CMD_WIN_B_INCR_SYNCPT_0",
+ "DC_CMD_WIN_B_INCR_SYNCPT_CNTRL_0",
+ "DC_CMD_WIN_B_INCR_SYNCPT_ERROR_0",
+ [0x018] = "DC_CMD_WIN_C_INCR_SYNCPT_0",
+ "DC_CMD_WIN_C_INCR_SYNCPT_CNTRL_0",
+ "DC_CMD_WIN_C_INCR_SYNCPT_ERROR_0",
+ [0x028] = "DC_CMD_CONT_SYNCPT_VSYNC_0",
+ [0x030] = "DC_CMD_CTXSW_0",
+ "DC_CMD_DISPLAY_COMMAND_OPTION0_0",
+ "DC_CMD_DISPLAY_COMMAND_0",
+ "DC_CMD_SIGNAL_RAISE_0",
+ [0x036] = "DC_CMD_DISPLAY_POWER_CONTROL_0",
+ "DC_CMD_INT_STATUS_0",
+ "DC_CMD_INT_MASK_0",
+ "DC_CMD_INT_ENABLE_0",
+ "DC_CMD_INT_TYPE_0",
+ "DC_CMD_INT_POLARITY_0",
+ "DC_CMD_SIGNAL_RAISE1_0",
+ "DC_CMD_SIGNAL_RAISE2_0",
+ "DC_CMD_SIGNAL_RAISE3_0",
+
+ [0x040] = "DC_CMD_STATE_ACCESS_0",
+ "DC_CMD_STATE_CONTROL_0",
+ "DC_CMD_DISPLAY_WINDOW_HEADER_0", // 042
+ "DC_CMD_REG_ACT_CONTROL_0", // 043
+
+ [0x300] = "DC_COM_CRC_CONTROL_0",
+ "DC_COM_CRC_CHECKSUM_0", // 301
+ "DC_COM_PIN_OUTPUT_ENABLE0_0", // 302
+ "DC_COM_PIN_OUTPUT_ENABLE1_0", // 303
+ "DC_COM_PIN_OUTPUT_ENABLE2_0", // 304
+ "DC_COM_PIN_OUTPUT_ENABLE3_0", // 305
+ "DC_COM_PIN_OUTPUT_POLARITY0_0", // 306
+ "DC_COM_PIN_OUTPUT_POLARITY1_0", // 307
+ "DC_COM_PIN_OUTPUT_POLARITY2_0", // 308
+ "DC_COM_PIN_OUTPUT_POLARITY3_0", // 309
+ "DC_COM_PIN_OUTPUT_DATA0_0", // 30A
+ "DC_COM_PIN_OUTPUT_DATA1_0", // 30B
+ "DC_COM_PIN_OUTPUT_DATA2_0", // 30C
+ "DC_COM_PIN_OUTPUT_DATA3_0", // 30D
+ "DC_COM_PIN_INPUT_ENABLE0_0", // 30E
+ "DC_COM_PIN_INPUT_ENABLE1_0", // 30F
+ "DC_COM_PIN_INPUT_ENABLE2_0", // 310
+ "DC_COM_PIN_INPUT_ENABLE3_0", // 311
+ "DC_COM_PIN_INPUT_DATA0_0", // 312
+ "DC_COM_PIN_INPUT_DATA1_0", // 313
+ "DC_COM_PIN_OUTPUT_SELECT0_0", // 314
+ "DC_COM_PIN_OUTPUT_SELECT1_0", // 315
+ "DC_COM_PIN_OUTPUT_SELECT2_0", // 316
+ "DC_COM_PIN_OUTPUT_SELECT3_0", // 317
+ "DC_COM_PIN_OUTPUT_SELECT4_0", // 318
+ "DC_COM_PIN_OUTPUT_SELECT5_0", // 319
+ "DC_COM_PIN_OUTPUT_SELECT6_0", // 31A
+ "DC_COM_PIN_MISC_CONTROL_0", // 31B
+ // TODO: Complete
+
+ [0x400] = "DC_DISP_DISP_SIGNAL_OPTIONS0_0",
+ "DC_DISP_DISP_SIGNAL_OPTIONS1_0", // 401
+ "DC_DISP_DISP_WIN_OPTIONS_0", // 402
+ "DC_DISP_MEM_HIGH_PRIORITY_0", // 403
+ "DC_DISP_MEM_HIGH_PRIORITY_TIMER_0", // 404
+ "DC_DISP_DISP_TIMING_OPTIONS_0", // 405
+ "DC_DISP_REF_TO_SYNC_0", // 406 (TrimSlice 0x0001 000B)
+ "DC_DISP_SYNC_WIDTH_0", // 407 (TrimSlice 0x0004 003A)
+ "DC_DISP_BACK_PORCH_0", // 408 (TrimSlice 0x0004 003A)
+ "DC_DISP_DISP_ACTIVE_0", // 409 (TrimSlice 0x0300 0400)
+ "DC_DISP_FRONT_PORCH_0", // 40A (TrimSlice 0x0004 003A)
+ "DC_DISP_H_PULSE0_CONTROL_0", // 40B
+ "DC_DISP_H_PULSE0_POSITION_A_0", // 40C
+ "DC_DISP_H_PULSE0_POSITION_B_0", // 40D
+ "DC_DISP_H_PULSE0_POSITION_C_0", // 40E
+ "DC_DISP_H_PULSE0_POSITION_D_0", // 40F
+ "DC_DISP_H_PULSE1_CONTROL_0", // 410
+ "DC_DISP_H_PULSE1_POSITION_A_0", // 411
+ "DC_DISP_H_PULSE1_POSITION_B_0", // 412
+ "DC_DISP_H_PULSE1_POSITION_C_0", // 413
+ "DC_DISP_H_PULSE1_POSITION_D_0", // 414
+ "DC_DISP_H_PULSE2_CONTROL_0", // 415
+ "DC_DISP_H_PULSE2_POSITION_A_0", // 416
+ "DC_DISP_H_PULSE2_POSITION_B_0", // 417
+ "DC_DISP_H_PULSE2_POSITION_C_0", // 418
+ "DC_DISP_H_PULSE2_POSITION_D_0", // 419
+ "DC_DISP_V_PULSE0_CONTROL_0", // 41A
+ "DC_DISP_V_PULSE0_POSITION_A_0", // 41B
+ "DC_DISP_V_PULSE0_POSITION_B_0", // 41C
+ "DC_DISP_V_PULSE0_POSITION_C_0", // 41D
+ "DC_DISP_V_PULSE1_CONTROL_0", // 41E
+ "DC_DISP_V_PULSE1_POSITION_A_0", // 41F
+ "DC_DISP_V_PULSE1_POSITION_B_0", // 420
+ "DC_DISP_V_PULSE1_POSITION_C_0", // 421
+ "DC_DISP_V_PULSE2_CONTROL_0", // 422
+ "DC_DISP_V_PULSE2_POSITION_A_0", // 423
+ "DC_DISP_V_PULSE3_CONTROL_0", // 424
+ "DC_DISP_V_PULSE3_POSITION_A_0", // 425
+ "DC_DISP_M0_CONTROL_0", // 426
+ "DC_DISP_M1_CONTROL_0", // 427
+ "DC_DISP_DI_CONTROL_0", // 428
+ "DC_DISP_PP_CONTROL_0", // 429
+ "DC_DISP_PP_SELECT_A_0", // 42A
+ "DC_DISP_PP_SELECT_B_0", // 42B
+ "DC_DISP_PP_SELECT_C_0", // 42C
+ "DC_DISP_PP_SELECT_D_0", // 42D
+ "DC_DISP_DISP_CLOCK_CONTROL_0", // 42E
+ "DC_DISP_DISP_INTERFACE_CONTROL_0",//42F
+ "DC_DISP_DISP_COLOR_CONTROL_0", // 430
+ "DC_DISP_SHIFT_CLOCK_OPTIONS_0", // 431
+ "DC_DISP_DATA_ENABLE_OPTIONS_0", // 432
+ "DC_DISP_SERIAL_INTERFACE_OPTIONS_0", // 433
+ "DC_DISP_LCD_SPI_OPTIONS_0", // 434
+ "DC_DISP_BORDER_COLOR_0", // 435
+ "DC_DISP_COLOR_KEY0_LOWER_0", // 436
+ "DC_DISP_COLOR_KEY0_UPPER_0", // 437
+ "DC_DISP_COLOR_KEY1_LOWER_0", // 438
+ "DC_DISP_COLOR_KEY1_UPPER_0", // 439
+ "_DC_DISP_UNUSED_43A",
+ "_DC_DISP_UNUSED_43B",
+ "DC_DISP_CURSOR_FOREGROUND_0", // 43C - IMPORTANT
+ "DC_DISP_CURSOR_BACKGROUND_0", // 43D - IMPORTANT
+ "DC_DISP_CURSOR_START_ADDR_0", // 43E - IMPORTANT
+ "DC_DISP_CURSOR_START_ADDR_NS_0", // 43F - IMPORTANT
+ "DC_DISP_CURSOR_POSITION_0", // 440 - IMPORTANT
+ "DC_DISP_CURSOR_POSITION_NS_0", // 441 - IMPORTANT
+ "DC_DISP_INIT_SEQ_CONTROL_0", // 442
+ "DC_DISP_SPI_INIT_SEQ_DATA_A_0", // 443
+ "DC_DISP_SPI_INIT_SEQ_DATA_B_0", // 444
+ "DC_DISP_SPI_INIT_SEQ_DATA_C_0", // 445
+ "DC_DISP_SPI_INIT_SEQ_DATA_D_0", // 446
+
+ [0x480] = "DC_DISP_DC_MCCIF_FIFOCTRL_0",
+ "DC_DISP_MCCIF_DISPLAY0A_HYST_0", // 481
+ "DC_DISP_MCCIF_DISPLAY0B_HYST_0", // 482
+ "DC_DISP_MCCIF_DISPLAY0C_HYST_0", // 483
+ "DC_DISP_MCCIF_DISPLAY1B_HYST_0", // 484
+
+ [0x4C0] = "DC_DISP_DAC_CRT_CTRL_0",
+ "DC_DISP_DISP_MISC_CONTROL_0", // 4C1
+
+ [0x500] = "DC_WINC_A_COLOR_PALETTE_0",
+ [0x600] = "DC_WINC_A_PALETTE_COLOR_EXT_0",
+ [0x700] = "DC_WIN_A_WIN_OPTIONS_0",
+ "DC_WIN_A_BYTE_SWAP_0", // 701
+ "DC_WIN_A_BUFFER_CONTROL_0", // 702
+ "DC_WIN_A_COLOR_DEPTH_0", // 703
+ "DC_WIN_A_POSITION_0", // 704
+ "DC_WIN_A_SIZE_0", // 705 (TrimSlice 0x0300 0400)
+ "DC_WIN_A_PRESCALED_SIZE_0",
+ "DC_WIN_A_H_INITIAL_DDA_0",
+ "DC_WIN_A_V_INITIAL_DDA_0",
+ "DC_WIN_A_DDA_INCREMENT_0",
+ "DC_WIN_A_LINE_STRIDE_0",
+ "DC_WIN_A_BUF_STRIDE_0",
+ "DC_WIN_A_BUFFER_ADDR_MODE_0",
+ "DC_WIN_A_DV_CONTROL_0",
+ "DC_WIN_A_BLEND_NOKEY_0",
+ "DC_WIN_A_BLEND_1WIN_0",
+ "DC_WIN_A_BLEND_2WIN_B_0",
+ "DC_WIN_A_BLEND_2WIN_C_0",
+ "DC_WIN_A_BLEND_3WIN_BC_0",
+ "DC_WIN_A_HP_FETCH_CONTROL_0",
+
+ [0x800] = "DC_WINBUF_A_START_ADDR_0",
+ [0x801] = "DC_WINBUF_A_START_ADDR_NS_0",
+ [0x806] = "DC_WINBUF_A_ADDR_H_OFFSET_0",
+ [0x807] = "DC_WINBUF_A_ADDR_H_OFFSET_NS_0",
+ [0x808] = "DC_WINBUF_A_ADDR_V_OFFSET_0",
+ [0x809] = "DC_WINBUF_A_ADDR_V_OFFSET_NS_0",
+ [0x80A] = "DC_WINBUF_A_UFLOW_STATUS"
+};
+#endif
+
+// Bit definitions
+/// \name DC_CMD_STATE_CONTROL_0
+/// \{
+#define GEN_ACT_REQ 0x0001
+#define WIN_A_ACT_REQ 0x0002
+#define WIN_B_ACT_REQ 0x0004
+#define WIN_C_ACT_REQ 0x0008
+/// \}
+
#endif
int gbVesa_CursorVisible = 0;\r
// --- 2D Video Stream Handlers ---\r
tDrvUtil_Video_BufInfo gVesa_BufInfo;\r
+// --- Settings ---\r
+// int gbVesa_DisableFBCache; // Disables the main-memory framebuffer cache\r
\r
// === CODE ===\r
int Vesa_Install(char **Arguments)\r
{\r
int rv;\r
+\r
+// for( int i = 0; Arguments[i]; i ++ )\r
+// {\r
+// if( strcmp(Aguments[i], "nocache") == 0 )\r
+// gbVesa_DisableFBCache = 1;\r
+// }\r
\r
gpVesa_BiosState = VM8086_Init();\r
\r
\r
Mutex_Release( &glVesa_Lock );\r
\r
+ gVesa_BufInfo.BackBuffer = realloc(gVesa_BufInfo.BackBuffer,\r
+ gVesa_Modes[mode].height * gVesa_Modes[mode].pitch);\r
gVesa_BufInfo.Framebuffer = gpVesa_Framebuffer;\r
gVesa_BufInfo.Pitch = gVesa_Modes[mode].pitch;\r
gVesa_BufInfo.Width = gVesa_Modes[mode].width;\r
int HFP, HSync, HDisplay, HBP;
int VFP, VSync, VDisplay, VBP;
} csaTimings[] = {
- {40, 128, 800, 88, 1, 4, 600, 23}, // SVGA @ 60Hz
- {24, 136, 1024, 160, 3, 6, 768, 29}, // XGA @ 60Hz
+ {40, 128, 800, 88, 1, 4, 600, 23}, // SVGA @ 60Hz
+ {24, 136, 1024, 160, 3, 6, 768, 29}, // XGA @ 60Hz
{38, 112, 1280, 248, 1, 3, 1024, 38} // 1280x1024 @ 60Hz
};
const Uint16 caVIAVideo_CardIDs[][2] = {
/*
- * Acess OS
- * Ext2 Driver Version 1
+ * Acess2 Ext2 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * dir.c
+ * - Directory Handling
*/
-/**
- * \file dir.c
- * \brief Second Extended Filesystem Driver
- * \todo Implement file full write support
- */
-#define DEBUG 1
+#define DEBUG 0
#define VERBOSE 0
#include "ext2_common.h"
// === MACROS ===
-#define BLOCK_DIR_OFS(_data, _block) ((Uint16*)(_data)[(_block)])
+#define BLOCK_DIR_OFS(_data, _block) (((Uint16*)(_data))[(_block)])
// === PROTOTYPES ===
-char *Ext2_ReadDir(tVFS_Node *Node, int Pos);
+ int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
- int Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
- int Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
- int Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
-// --- Helpers ---
-tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
+tVFS_Node *Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int Ext2_Unlink(tVFS_Node *Node, const char *OldName);
+ int Ext2_Link(tVFS_Node *Parent, const char *Name, tVFS_Node *Node);
// === GLOBALS ===
tVFS_NodeType gExt2_DirType = {
.ReadDir = Ext2_ReadDir,
.FindDir = Ext2_FindDir,
.MkNod = Ext2_MkNod,
- .Relink = Ext2_Relink,
+ .Unlink = Ext2_Unlink,
.Link = Ext2_Link,
.Close = Ext2_CloseFile
};
* \param Node Directory node
* \param Pos Position of desired element
*/
-char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
+int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
tExt2_Inode inode;
tExt2_DirEnt dirent;
Ext2_int_ReadInode(disk, Node->Inode, &inode);
size = inode.i_size;
- LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
+ LOG("inode={.i_block[0]= 0x%x, .i_size=0x%x}", inode.i_block[0], inode.i_size);
// Find Entry
// Get First Block
// - Do this ourselves as it is a simple operation
Base = inode.i_block[0] * disk->BlockSize;
// Scan directory
- while(Pos -- && size > 0)
+ while(Pos -- && size > 0 && size <= inode.i_size)
{
VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
ofs += dirent.rec_len;
}
ofs = 0;
Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
+ if( Base == 0 ) {
+ size = 0;
+ break;
+ }
}
}
// Check for the end of the list
- if(size <= 0) {
- LEAVE('n');
- return NULL;
+ if(size <= 0 || size > inode.i_size) {
+ LEAVE('i', -ENOENT);
+ return -ENOENT;
}
// Read Entry
VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
- //LOG("dirent.inode = %i", dirent.inode);
- //LOG("dirent.rec_len = %i", dirent.rec_len);
- //LOG("dirent.name_len = %i", dirent.name_len);
+ LOG("dirent={.rec_len=%i,.inode=0x%x,.name_len=%i}",
+ dirent.rec_len, dirent.inode, dirent.name_len);
dirent.name[ dirent.name_len ] = '\0'; // Cap off string
+ if( dirent.name_len == 0 ) {
+ LEAVE('i', 1);
+ return 1;
+ }
// Ignore . and .. (these are done in the VFS)
if( (dirent.name[0] == '.' && dirent.name[1] == '\0')
|| (dirent.name[0] == '.' && dirent.name[1] == '.' && dirent.name[2]=='\0')) {
- LEAVE('p', VFS_SKIP);
- return VFS_SKIP; // Skip
+ LEAVE('i', 1);
+ return 1; // Skip
}
- LEAVE('s', dirent.name);
- // Create new node
- return strdup(dirent.name);
+ LOG("Name '%s'", dirent.name);
+ strncpy(Dest, dirent.name, FILENAME_MAX);
+ LEAVE('i', 0);
+ return 0;
}
/**
while(size > 0)
{
VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
+ // TODO: Possible overrun if name_len == 255?
dirent.name[ dirent.name_len ] = '\0'; // Cap off string
// If it matches, create a node and return it
if(dirent.name_len == filenameLen && strcmp(dirent.name, Filename) == 0)
* \fn int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
* \brief Create a new node
*/
-int Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
+tVFS_Node *Ext2_MkNod(tVFS_Node *Parent, const char *Name, Uint Flags)
{
- #if 0
- tVFS_Node *child;
- Uint64 inodeNum;
- tExt2_Inode inode;
- inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode);
-
- memset(&inode, 0, sizeof(tExt2_Inode));
+ ENTER("pParent sName xFlags", Parent, Name, Flags);
- // File type
- inode.i_mode = 0664;
- if( Flags & VFS_FFLAG_READONLY )
- inode.i_mode &= ~0222;
- if( Flags & VFS_FFLAG_SYMLINK )
- inode.i_mode |= EXT2_S_IFLNK;
- else if( Flags & VFS_FFLAG_DIRECTORY )
- inode.i_mode |= EXT2_S_IFDIR | 0111;
-
- inode.i_uid = Threads_GetUID();
- inode.i_gid = Threads_GetGID();
- inode.i_ctime =
- inode.i_mtime =
- inode.i_atime = now() / 1000;
-
- child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum);
- return Ext2_Link(Parent, child, Name);
- #else
- return 1;
- #endif
+ Uint64 inodeNum = Ext2_int_AllocateInode(Parent->ImplPtr, Parent->Inode);
+ if( inodeNum == 0 ) {
+ LOG("Inode allocation failed");
+ LEAVE_RET('n', NULL);
+ }
+ tVFS_Node *child = Ext2_int_CreateNode(Parent->ImplPtr, inodeNum);
+ if( !child ) {
+ Ext2_int_DereferenceInode(Parent->ImplPtr, inodeNum);
+ Log_Warning("Ext2", "Ext2_MkNod - Node creation failed");
+ LEAVE_RET('n', NULL);
+ }
+
+ child->Flags = Flags & (VFS_FFLAG_DIRECTORY|VFS_FFLAG_SYMLINK|VFS_FFLAG_READONLY);
+ child->UID = Threads_GetUID();
+ child->GID = Threads_GetGID();
+ child->CTime =
+ child->MTime =
+ child->ATime =
+ now();
+ child->ImplInt = 0; // ImplInt is the link count
+ // TODO: Set up ACLs
+
+ int rv = Ext2_Link(Parent, Name, child);
+ if( rv ) {
+ Ext2_CloseFile(child);
+ return NULL;
+ }
+ LEAVE_RET('p', child);
}
/**
* \param Node This (directory) node
* \param OldName Old name of file
* \param NewName New name for file
- * \return Boolean Failure - See ::tVFS_Node.Relink for info
+ * \return Boolean Failure - See ::tVFS_Node.Unlink for info
*/
-int Ext2_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+int Ext2_Unlink(tVFS_Node *Node, const char *OldName)
{
+ Log_Warning("Ext2", "TODO: Impliment Ext2_Unlink");
return 1;
}
/**
* \brief Links an existing node to a new name
* \param Parent Parent (directory) node
- * \param Node Node to link
* \param Name New name for the node
+ * \param Node Node to link
* \return Boolean Failure - See ::tVFS_Node.Link for info
*/
-int Ext2_Link(tVFS_Node *Node, tVFS_Node *Child, const char *Name)
+int Ext2_Link(tVFS_Node *Node, const char *Name, tVFS_Node *Child)
{
- #if 0
tExt2_Disk *disk = Node->ImplPtr;
tExt2_Inode inode;
- tExt2_DirEnt dirent;
+ tExt2_DirEnt *dirent;
tExt2_DirEnt newEntry;
- Uint64 Base; // Block's Base Address
+ Uint64 base; // Block's Base Address
int block = 0, ofs = 0;
Uint size;
void *blockData;
- int bestMatch = -1, bestSize, bestBlock, bestOfs;
+ int bestMatch = -1;
+ int bestSize=0, bestBlock=0, bestOfs=0, bestNeedsSplit=0;
int nEntries;
+
+ ENTER("pNode sName pChild",
+ Node, Name, Child);
blockData = malloc(disk->BlockSize);
// Create a stub entry
newEntry.inode = Child->Inode;
newEntry.name_len = strlen(Name);
- newEntry.rec_len = (newEntry.name_len+3+8)&~3;
+ newEntry.rec_len = ((newEntry.name_len+3)&~3) + EXT2_DIRENT_SIZE;
newEntry.type = inode.i_mode >> 12;
memcpy(newEntry.name, Name, newEntry.name_len);
size = inode.i_size;
// Get a lock on the inode
- Ext2_int_LockInode(disk, Node->Inode);
-
+ //Ext2_int_LockInode(disk, Node->Inode);
+ Mutex_Acquire(&Node->Lock);
+
+// if( !Node->Data ) {
+// }
+
// Get First Block
// - Do this ourselves as it is a simple operation
base = inode.i_block[0] * disk->BlockSize;
VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
block = 0;
+ nEntries = 0;
// Find File
while(size > 0)
{
"Directory entry %i of inode 0x%x extends over a block boundary",
nEntries, (Uint)Node->Inode);
}
- else {
-
+ else
+ {
+ LOG("Entry %i: %x %i bytes", nEntries, dirent->type, dirent->rec_len);
// Free entry
- if(dirent->type == 0) {
+ if(dirent->type == 0)
+ {
if( dirent->rec_len >= newEntry.rec_len
&& (bestMatch == -1 || bestSize > dirent->rec_len) )
{
bestSize = dirent->rec_len;
bestBlock = block;
bestOfs = ofs;
+ bestNeedsSplit = 0;
}
}
// Non free - check name to avoid duplicates
- else {
+ else
+ {
+ LOG(" name='%.*s'", dirent->name_len, dirent->name);
if(strncmp(Name, dirent->name, dirent->name_len) == 0) {
- Ext2_int_UnlockInode(disk, Node->Inode);
+ //Ext2_int_UnlockInode(disk, Node->Inode);
+ Mutex_Release(&Node->Lock);
+ LEAVE('i', 1);
return 1; // ERR_???
}
+
+ int spare_space = dirent->rec_len - (dirent->name_len + EXT2_DIRENT_SIZE);
+ if( spare_space > newEntry.rec_len
+ && (bestMatch == -1 || bestSize > spare_space) )
+ {
+ bestMatch = nEntries;
+ bestSize = spare_space;
+ bestBlock = block;
+ bestOfs = ofs;
+ bestNeedsSplit = 1;
+ }
}
}
// Increment the pointer
nEntries ++;
ofs += dirent->rec_len;
- if( ofs >= disk->BlockSize ) {
+ size -= dirent->rec_len;
+ if( size > 0 && ofs >= disk->BlockSize ) {
// Read the next block if needed
- BLOCK_DIR_OFS(Node->Data, block) = nEntries;
+ // BLOCK_DIR_OFS(Node->Data, block) = nEntries;
block ++;
ofs = 0;
base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
}
}
+ LOG("bestMatch = %i", bestMatch);
+ // If EOF was reached with no space, check if we can fit one on the end
+ if( bestMatch < 0 && ofs + newEntry.rec_len < disk->BlockSize ) {
+ Node->Size += newEntry.rec_len;
+ Node->Flags |= VFS_FFLAG_DIRTY;
+ bestBlock = block;
+ bestOfs = ofs;
+ bestSize = newEntry.rec_len;
+ bestNeedsSplit = 0;
+ }
// Check if a free slot was found
- if( bestMatch >= 0 ) {
+ if( bestMatch >= 0 )
+ {
// Read-Modify-Write
- bestBlock = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock);
- if( block > 0 )
- bestMatch = BLOCK_DIR_OFS(Node->Data, bestBlock);
+ base = Ext2_int_GetBlockAddr(disk, inode.i_block, bestBlock);
VFS_ReadAt( disk->FD, base, disk->BlockSize, blockData );
dirent = blockData + bestOfs;
- memcpy(dirent, newEntry, newEntry.rec_len);
+ // Shorten a pre-existing entry
+ if(bestNeedsSplit)
+ {
+ dirent->rec_len = EXT2_DIRENT_SIZE + dirent->name_len;
+ bestOfs += dirent->rec_len;
+ //bestSize -= dirent->rec_len; // (not needed, bestSize is the spare space after)
+ dirent = blockData + bestOfs;
+ }
+ // Insert new file entry
+ memcpy(dirent, &newEntry, newEntry.rec_len);
+ // Create a new blank entry
+ if( bestSize != newEntry.rec_len )
+ {
+ bestOfs += newEntry.rec_len;
+ dirent = blockData + bestOfs;
+
+ dirent->rec_len = bestSize - newEntry.rec_len;
+ dirent->type = 0;
+ }
+ // Save changes
VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData );
}
else {
// Allocate block, Write
- block = Ext2_int_AllocateBlock(Disk, block);
- Log_Warning("EXT2", "");
+ Uint32 newblock = Ext2_int_AllocateBlock(disk, base / disk->BlockSize);
+ Ext2_int_AppendBlock(disk, &inode, newblock);
+ base = newblock * disk->BlockSize;
+ Node->Size += newEntry.rec_len;
+ Node->Flags |= VFS_FFLAG_DIRTY;
+ memcpy(blockData, &newEntry, newEntry.rec_len);
+ memset(blockData + newEntry.rec_len, 0, disk->BlockSize - newEntry.rec_len);
+ VFS_WriteAt( disk->FD, base, disk->BlockSize, blockData );
}
- Ext2_int_UnlockInode(disk, Node->Inode);
+ Child->ImplInt ++;
+ Child->Flags |= VFS_FFLAG_DIRTY;
+
+ //Ext2_int_UnlockInode(disk, Node->Inode);
+ Mutex_Release(&Node->Lock);
+ LEAVE('i', 0);
return 0;
- #else
- return 1;
- #endif
}
-// ---- INTERNAL FUNCTIONS ----
-/**
- * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
- * \brief Create a new VFS Node
- */
-tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)
-{
- tExt2_Inode inode;
- tVFS_Node retNode;
- tVFS_Node *tmpNode;
-
- if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
- return NULL;
-
- if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
- return tmpNode;
-
-
- // Set identifiers
- retNode.Inode = InodeID;
- retNode.ImplPtr = Disk;
-
- // Set file length
- retNode.Size = inode.i_size;
- retNode.Data = NULL;
-
- // Set Access Permissions
- retNode.UID = inode.i_uid;
- retNode.GID = inode.i_gid;
- retNode.NumACLs = 3;
- retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
-
- // Set Function Pointers
- retNode.Type = &gExt2_FileType;
-
- switch(inode.i_mode & EXT2_S_IFMT)
- {
- // Symbolic Link
- case EXT2_S_IFLNK:
- retNode.Flags = VFS_FFLAG_SYMLINK;
- break;
- // Regular File
- case EXT2_S_IFREG:
- retNode.Flags = 0;
- retNode.Size |= (Uint64)inode.i_dir_acl << 32;
- break;
- // Directory
- case EXT2_S_IFDIR:
- retNode.Type = &gExt2_DirType;
- retNode.Flags = VFS_FFLAG_DIRECTORY;
- retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );
- break;
- // Unknown, Write protect it to be safe
- default:
- retNode.Flags = VFS_FFLAG_READONLY;
- break;
- }
-
- // Set Timestamps
- retNode.ATime = inode.i_atime * 1000;
- retNode.MTime = inode.i_mtime * 1000;
- retNode.CTime = inode.i_ctime * 1000;
-
- // Save in node cache and return saved node
- return Inode_CacheNode(Disk->CacheID, &retNode);
-}
/*\r
- * Acess OS\r
- * Ext2 Driver Version 1\r
+ * Acess2 Ext2 Driver\r
+ * - By John Hodge (thePowersGang)\r
+ *\r
+ * ext2.c\r
+ * - Driver core\r
*/\r
-/**\r
- * \file fs/ext2.c\r
- * \brief Second Extended Filesystem Driver\r
- * \todo Implement file full write support\r
- */\r
-#define DEBUG 1\r
-#define VERBOSE 0\r
+#define DEBUG 0\r
+#define VERSION VER2(0,90)\r
#include "ext2_common.h"\r
#include <modules.h>\r
\r
-// === IMPORTS ===\r
-extern tVFS_NodeType gExt2_DirType;\r
+#define MIN_BLOCKS_PER_GROUP 2\r
+#define MAX_BLOCK_LOG_SIZE 10 // 1024 << 10 = 1MiB\r
\r
// === PROTOTYPES ===\r
int Ext2_Install(char **Arguments);\r
-// Interface Functions\r
+ int Ext2_Cleanup(void);\r
+// - Interface Functions\r
+ int Ext2_Detect(int FD);\r
tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options);\r
-void Ext2_Unmount(tVFS_Node *Node);\r
-void Ext2_CloseFile(tVFS_Node *Node);\r
-// Internal Helpers\r
- int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
-Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
-Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
-void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
+void Ext2_Unmount(tVFS_Node *Node);\r
+void Ext2_CloseFile(tVFS_Node *Node);\r
+// - Internal Helpers\r
+ int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);\r
+Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);\r
+Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);\r
+void Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode);\r
+void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);\r
\r
// === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, 0x5B /*v0.90*/, FS_Ext2, Ext2_Install, NULL);\r
+MODULE_DEFINE(0, VERSION, FS_Ext2, Ext2_Install, Ext2_Cleanup);\r
tExt2_Disk gExt2_disks[6];\r
int giExt2_count = 0;\r
tVFS_Driver gExt2_FSInfo = {\r
- "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL\r
+ .Name = "ext2",\r
+ .Detect = Ext2_Detect,\r
+ .InitDevice = Ext2_InitDevice,\r
+ .Unmount = Ext2_Unmount,\r
+ .GetNodeFromINode = NULL\r
};\r
\r
// === CODE ===\r
return MODULE_ERR_OK;\r
}\r
\r
+/**\r
+ * \brief Clean up driver state before unload\r
+ */\r
+int Ext2_Cleanup(void)\r
+{\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * Detect if a volume is Ext2 formatted\r
+ */\r
+int Ext2_Detect(int FD)\r
+{\r
+ tExt2_SuperBlock sb;\r
+ size_t len;\r
+ \r
+ len = VFS_ReadAt(FD, 1024, 1024, &sb);\r
+\r
+ if( len != 1024 ) {\r
+ Log_Debug("Ext2", "_Detect: Read failed? (0x%x != 1024)", len);\r
+ return 0;\r
+ }\r
+ \r
+ switch(sb.s_magic)\r
+ {\r
+ case 0xEF53:\r
+ return 2;\r
+ default:\r
+ Log_Debug("Ext2", "_Detect: s_magic = 0x%x", sb.s_magic);\r
+ return 0;\r
+ }\r
+}\r
+\r
/**\r
\brief Initializes a device to be read by by the driver\r
\param Device String - Device to read from\r
*/\r
tVFS_Node *Ext2_InitDevice(const char *Device, const char **Options)\r
{\r
- tExt2_Disk *disk;\r
+ tExt2_Disk *disk = NULL;\r
int fd;\r
int groupCount;\r
tExt2_SuperBlock sb;\r
if(sb.s_magic != 0xEF53) {\r
Log_Warning("EXT2", "Volume '%s' is not an EXT2 volume (0x%x != 0xEF53)",\r
Device, sb.s_magic);\r
- VFS_Close(fd);\r
- LEAVE('n');\r
- return NULL;\r
+ goto _error;\r
}\r
- \r
+\r
+ if( sb.s_blocks_per_group < MIN_BLOCKS_PER_GROUP ) {\r
+ Log_Warning("Ext2", "Blocks per group is too small (%i < %i)",\r
+ sb.s_blocks_per_group, MIN_BLOCKS_PER_GROUP);\r
+ goto _error;\r
+ } \r
+\r
// Get Group count\r
groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);\r
LOG("groupCount = %i", groupCount);\r
disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);\r
if(!disk) {\r
Log_Warning("EXT2", "Unable to allocate disk structure");\r
- VFS_Close(fd);\r
- LEAVE('n');\r
- return NULL;\r
+ goto _error;\r
}\r
disk->FD = fd;\r
memcpy(&disk->SuperBlock, &sb, 1024);\r
disk->CacheID = Inode_GetHandle();\r
\r
// Get Block Size\r
- LOG("s_log_block_size = 0x%x", sb.s_log_block_size);\r
+ if( sb.s_log_block_size > MAX_BLOCK_LOG_SIZE ) {\r
+ Log_Warning("Ext2", "Block size (log2) too large (%i > %i)",\r
+ sb.s_log_block_size, MAX_BLOCK_LOG_SIZE);\r
+ goto _error;\r
+ }\r
disk->BlockSize = 1024 << sb.s_log_block_size;\r
+ LOG("Disk->BlockSie = 0x%x (1024 << %i)", disk->BlockSize, sb.s_log_block_size);\r
\r
// Read Group Information\r
+ LOG("sb,s_first_data_block = %x", sb.s_first_data_block);\r
VFS_ReadAt(\r
disk->FD,\r
sb.s_first_data_block * disk->BlockSize + 1024,\r
disk->Groups\r
);\r
\r
- #if VERBOSE\r
LOG("Block Group 0");\r
LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);\r
LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);\r
LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);\r
LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);\r
LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);\r
- #endif\r
\r
// Get root Inode\r
Ext2_int_ReadInode(disk, 2, &inode);\r
\r
LEAVE('p', &disk->RootNode);\r
return &disk->RootNode;\r
+_error:\r
+ if( disk )\r
+ free(disk);\r
+ VFS_Close(fd);\r
+ LEAVE('n');\r
+ return NULL;\r
}\r
\r
/**\r
void Ext2_CloseFile(tVFS_Node *Node)\r
{\r
tExt2_Disk *disk = Node->ImplPtr;\r
- Inode_UncacheNode(disk->CacheID, Node->Inode);\r
+ ENTER("pNode", Node);\r
+\r
+ if( Mutex_Acquire(&Node->Lock) != 0 )\r
+ {\r
+ LEAVE('-');\r
+ return ;\r
+ }\r
+\r
+ if( Node->Flags & VFS_FFLAG_DIRTY )\r
+ {\r
+ // Commit changes\r
+ Ext2_int_WritebackNode(disk, Node);\r
+ Node->Flags &= ~VFS_FFLAG_DIRTY;\r
+ }\r
+\r
+ int was_not_referenced = (Node->ImplInt == 0);\r
+ tVFS_ACL *acls = Node->ACLs;\r
+ if( Inode_UncacheNode(disk->CacheID, Node->Inode) == 1 )\r
+ {\r
+ if( was_not_referenced )\r
+ {\r
+ LOG("Removng inode");\r
+ // Remove inode\r
+ Log_Warning("Ext2", "TODO: Remove inode when not referenced (%x)", (Uint32)Node->Inode);\r
+ }\r
+ if( acls != &gVFS_ACL_EveryoneRW ) {\r
+ free(acls);\r
+ }\r
+ LOG("Node cleaned");\r
+ }\r
+ else {\r
+ LOG("Still referenced, releasing lock");\r
+ Mutex_Release(&Node->Lock);\r
+ }\r
+ LEAVE('-');\r
return ;\r
}\r
\r
return 1;\r
}\r
\r
+/**\r
+ * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)\r
+ * \brief Create a new VFS Node\r
+ */\r
+tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID)\r
+{\r
+ tExt2_Inode inode;\r
+ tVFS_Node retNode;\r
+ tVFS_Node *tmpNode;\r
+ \r
+ if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )\r
+ return NULL;\r
+ \r
+ if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )\r
+ return tmpNode;\r
+\r
+ memset(&retNode, 0, sizeof(retNode)); \r
+ \r
+ // Set identifiers\r
+ retNode.Inode = InodeID;\r
+ retNode.ImplPtr = Disk;\r
+ retNode.ImplInt = inode.i_links_count;\r
+ if( inode.i_links_count == 0 ) {\r
+ Log_Notice("Ext2", "Inode %p:%x is not referenced, bug?", Disk, InodeID);\r
+ }\r
+ \r
+ // Set file length\r
+ retNode.Size = inode.i_size;\r
+ \r
+ // Set Access Permissions\r
+ retNode.UID = inode.i_uid;\r
+ retNode.GID = inode.i_gid;\r
+ retNode.NumACLs = 3;\r
+ retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);\r
+ \r
+ // Set Function Pointers\r
+ retNode.Type = &gExt2_FileType;\r
+ \r
+ switch(inode.i_mode & EXT2_S_IFMT)\r
+ {\r
+ // Symbolic Link\r
+ case EXT2_S_IFLNK:\r
+ retNode.Flags = VFS_FFLAG_SYMLINK;\r
+ break;\r
+ // Regular File\r
+ case EXT2_S_IFREG:\r
+ retNode.Flags = 0;\r
+ retNode.Size |= (Uint64)inode.i_dir_acl << 32;\r
+ break;\r
+ // Directory\r
+ case EXT2_S_IFDIR:\r
+ retNode.Type = &gExt2_DirType;\r
+ retNode.Flags = VFS_FFLAG_DIRECTORY;\r
+ retNode.Data = calloc( sizeof(Uint16), DivUp(retNode.Size, Disk->BlockSize) );\r
+ break;\r
+ // Unknown, Write protect it to be safe \r
+ default:\r
+ retNode.Flags = VFS_FFLAG_READONLY;\r
+ break;\r
+ }\r
+ \r
+ // Set Timestamps\r
+ retNode.ATime = inode.i_atime * 1000;\r
+ retNode.MTime = inode.i_mtime * 1000;\r
+ retNode.CTime = inode.i_ctime * 1000;\r
+ \r
+ // Save in node cache and return saved node\r
+ return Inode_CacheNode(Disk->CacheID, &retNode);\r
+}\r
+\r
+int Ext2_int_WritebackNode(tExt2_Disk *Disk, tVFS_Node *Node)\r
+{\r
+ tExt2_Inode inode;\r
+\r
+ if( Disk != Node->ImplPtr ) {\r
+ Log_Error("Ext2", "Ext2_int_WritebackNode - Disk != Node->ImplPtr");\r
+ return -1;\r
+ }\r
+ \r
+ if( Node->Flags & VFS_FFLAG_SYMLINK ) {\r
+ inode.i_mode = EXT2_S_IFLNK;\r
+ }\r
+ else if( Node->Flags & VFS_FFLAG_DIRECTORY ) {\r
+ inode.i_mode = EXT2_S_IFDIR;\r
+ }\r
+ else if( Node->Flags & VFS_FFLAG_READONLY ) {\r
+ Log_Notice("Ext2", "Not writing back readonly inode %p:%x", Disk, Node->Inode);\r
+ return 1;\r
+ }\r
+ else {\r
+ inode.i_mode = EXT2_S_IFREG;\r
+ inode.i_dir_acl = Node->Size >> 32;\r
+ }\r
+\r
+ inode.i_size = Node->Size & 0xFFFFFFFF;\r
+ inode.i_links_count = Node->ImplInt;\r
+\r
+ inode.i_uid = Node->UID;\r
+ inode.i_gid = Node->GID;\r
+\r
+ inode.i_atime = Node->ATime / 1000;\r
+ inode.i_mtime = Node->MTime / 1000;\r
+ inode.i_ctime = Node->CTime / 1000;\r
+\r
+ // TODO: Compact ACLs into unix mode\r
+ Log_Warning("Ext2", "TODO: Support converting Acess ACLs into unix modes");\r
+\r
+ Ext2_int_WriteInode(Disk, Node->Inode, &inode);\r
+\r
+ return 0;\r
+}\r
+\r
/**\r
* \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)\r
* \brief Get the address of a block from an inode's list\r
*/\r
Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)\r
{\r
-// Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
- Log_Warning("EXT2", "Ext2_int_AllocateInode is unimplemented");\r
+ Uint start_group = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;\r
+ Uint group = start_group;\r
+\r
+ if( Disk->SuperBlock.s_free_inodes_count == 0 ) \r
+ {\r
+ Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes on %p", Disk);\r
+ return 0;\r
+ }\r
+\r
+ while( group < Disk->GroupCount && Disk->Groups[group].bg_free_inodes_count == 0 )\r
+ group ++;\r
+ if( group == Disk->GroupCount )\r
+ {\r
+ group = 0;\r
+ while( group < start_group && Disk->Groups[group].bg_free_inodes_count == 0 )\r
+ group ++;\r
+ }\r
+ \r
+ if( Disk->Groups[group].bg_free_inodes_count == 0 )\r
+ {\r
+ Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes on %p, but superblock says some free", Disk);\r
+ return 0;\r
+ }\r
+\r
+ // Load bitmap for group\r
+ // (s_inodes_per_group / 8) bytes worth\r
+ // - Allocate a buffer the size of a sector/block\r
+ // - Read in part of the bitmap\r
+ // - Search for a free inode\r
+ tExt2_Group *bg = &Disk->Groups[group];\r
+ int ofs = 0;\r
+ do {\r
+ const int sector_size = 512;\r
+ Uint8 buf[sector_size];\r
+ VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf);\r
+\r
+ int byte, bit;\r
+ for( byte = 0; byte < sector_size && buf[byte] != 0xFF; byte ++ )\r
+ ;\r
+ if( byte < sector_size )\r
+ {\r
+ for( bit = 0; bit < 8 && buf[byte] & (1 << bit); bit ++)\r
+ ;\r
+ ASSERT(bit != 8);\r
+ buf[byte] |= 1 << bit;\r
+ VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_inode_bitmap+ofs, sector_size, buf);\r
+\r
+ bg->bg_free_inodes_count --;\r
+ Disk->SuperBlock.s_free_inodes_count --;\r
+\r
+ Uint32 ret = group * Disk->SuperBlock.s_inodes_per_group + byte * 8 + bit + 1;\r
+ Log_Debug("Ext2", "Ext2_int_AllocateInode - Allocated 0x%x", ret);\r
+ return ret;\r
+ }\r
+\r
+ ofs += sector_size;\r
+ } while(ofs < Disk->SuperBlock.s_inodes_per_group / 8);\r
+\r
+ Log_Notice("Ext2", "Ext2_int_AllocateInode - Out of inodes in group %p:%i but header reported free",\r
+ Disk, group);\r
+\r
return 0;\r
}\r
\r
+/**\r
+ * \brief Reduce the reference count on an inode\r
+ */\r
+void Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode)\r
+{\r
+ Log_Warning("Ext2", "TODO: Impliment Ext2_int_DereferenceInode");\r
+}\r
+\r
/**\r
* \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)\r
* \brief Updates the superblock\r
* Acess OS
* Ext2 Driver Version 1
*/
-/**
- * \file ext2_common.h
- * \brief Second Extended Filesystem Driver
- */
#ifndef _EXT2_COMMON_H
#define _EXT2_COMMON_H
#include <acess.h>
tExt2_Group Groups[];
} tExt2_Disk;
+// === GLOBALS ===
+extern tVFS_NodeType gExt2_FileType;
+extern tVFS_NodeType gExt2_DirType;
+
// === FUNCTIONS ===
// --- Common ---
extern void Ext2_CloseFile(tVFS_Node *Node);
extern Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);
extern void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);
+extern Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);
+extern void Ext2_int_DereferenceInode(tExt2_Disk *Disk, Uint32 Inode);
extern int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
extern int Ext2_int_WriteInode(tExt2_Disk *Disk, Uint32 InodeId, tExt2_Inode *Inode);
// --- Dir ---
-extern char *Ext2_ReadDir(tVFS_Node *Node, int Pos);
+extern int Ext2_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
extern tVFS_Node *Ext2_FindDir(tVFS_Node *Node, const char *FileName);
-extern int Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
-extern int Ext2_Link(tVFS_Node *Parent, tVFS_Node *Node, const char *Name);
+extern tVFS_Node *Ext2_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+extern int Ext2_Link(tVFS_Node *Parent, const char *Name, tVFS_Node *Node);
+extern tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId);
+extern int Ext2_int_WritebackNode(tExt2_Disk *Disk, tVFS_Node *Node);
// --- Read ---
extern size_t Ext2_Read(tVFS_Node *node, off_t offset, size_t length, void *buffer);
// --- Write ---
extern size_t Ext2_Write(tVFS_Node *node, off_t offset, size_t length, const void *buffer);
+extern Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 LastBlock);
+extern void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block);
+extern int Ext2_int_AppendBlock(tExt2_Disk *Disk, tExt2_Inode *Inode, Uint32 Block);
#endif
Uint8 type; //!< File Type (Duplicate of ext2_inode_s.i_mode)\r
char name[EXT2_NAME_LEN+1]; //!< File name\r
};\r
-#define EXT2_DIRENT_SIZE (sizeof(struct ext2_dir_entry_s)-EXT2_NAME_LEN+1)\r
+#define EXT2_DIRENT_SIZE (sizeof(struct ext2_dir_entry_s)-(EXT2_NAME_LEN+1))\r
\r
#endif\r
block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
if(!block) return Length - retLen;
// Add it to this inode
- if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+ if( Ext2_int_AppendBlock(disk, &inode, block) ) {
+ Log_Warning("Ext2", "Appending %x to inode %p:%X failed",
+ block, disk, Node->Inode);
Ext2_int_DeallocateBlock(disk, block);
goto ret;
}
// Last block :D
block = Ext2_int_AllocateBlock(disk, base/disk->BlockSize);
if(!block) goto ret;
- if( !Ext2_int_AppendBlock(disk, &inode, block) ) {
+ if( Ext2_int_AppendBlock(disk, &inode, block) ) {
+ Log_Warning("Ext2", "Appending %x to inode %p:%X failed",
+ block, disk, Node->Inode);
Ext2_int_DeallocateBlock(disk, block);
goto ret;
}
base = block * disk->BlockSize;
VFS_WriteAt(disk->FD, base, retLen, Buffer);
+
+ // TODO: When should the size update be committed?
inode.i_size += retLen;
+ Node->Size += retLen;
+ Node->Flags |= VFS_FFLAG_DIRTY;
+
retLen = 0;
ret: // Makes sure the changes to the inode are committed
Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
{
int bpg = Disk->SuperBlock.s_blocks_per_group;
- Uint blockgroup = PrevBlock / bpg;
- Uint bitmap[Disk->BlockSize/sizeof(Uint)];
- Uint bitsperblock = 8*Disk->BlockSize;
- int i, j = 0;
- Uint block;
-
+ Uint firstgroup = PrevBlock / bpg;
+ Uint blockgroup = firstgroup;
+ tExt2_Group *bg;
+
+ // TODO: Need to do locking on the bitmaps
+
// Are there any free blocks?
- if(Disk->SuperBlock.s_free_blocks_count == 0) return 0;
-
- if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
+ if(Disk->SuperBlock.s_free_blocks_count == 0)
+ return 0;
+
+ // First: Check the next block after \a PrevBlock
+ if( (PrevBlock + 1) % Disk->SuperBlock.s_blocks_per_group != 0
+ && Disk->Groups[blockgroup].bg_free_blocks_count > 0 )
{
- // Search block group's bitmap
- for(i = 0; i < bpg; i++)
+ bg = &Disk->Groups[blockgroup];
+ const int sector_size = 512;
+ Uint8 buf[sector_size];
+ int iblock = (PrevBlock + 1) % Disk->SuperBlock.s_blocks_per_group;
+ int byte = iblock / 8;
+ int ofs = byte / sector_size * sector_size;
+ byte %= sector_size;
+ VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+ if( (buf[byte] & (1 << (iblock%8))) == 0 )
{
- // Get the block in the bitmap block
- j = i & (bitsperblock-1);
-
- // Read in if needed
- if(j == 0) {
- VFS_ReadAt(
- Disk->FD,
- (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
- Disk->BlockSize,
- bitmap
- );
- }
-
- // Fast Check
- if( bitmap[j/32] == 0xFFFFFFFF ) {
- j = (j + 31) & ~31;
- continue;
- }
-
- // Is the bit set?
- if( bitmap[j/32] & (1 << (j%32)) )
- continue;
-
- // Ooh! We found one
- break;
- }
- if( i < bpg ) {
- Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
- goto checkAll; // Search the entire filesystem for a free block
- // Goto needed for neatness
+ // Free block - nice and contig allocation
+ buf[byte] |= (1 << (iblock%8));
+ VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+ bg->bg_free_blocks_count --;
+ Disk->SuperBlock.s_free_blocks_count --;
+ #if EXT2_UPDATE_WRITEBACK
+ Ext2_int_UpdateSuperblock(Disk);
+ #endif
+ return PrevBlock + 1;
}
-
- // Mark as used
- bitmap[j/32] |= (1 << (j%32));
- VFS_WriteAt(
- Disk->FD,
- (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
- Disk->BlockSize,
- bitmap
- );
- block = i;
- Disk->Groups[blockgroup].bg_free_blocks_count --;
- #if EXT2_UPDATE_WRITEBACK
- //Ext2_int_UpdateBlockGroup(Disk, blockgroup);
- #endif
+ // Used... darnit
+ // Fall through and search further
}
- else
+
+ // Second: Search for a group with free blocks
+ while( blockgroup < Disk->GroupCount && Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
+ blockgroup ++;
+ if( Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
{
- checkAll:
- Log_Warning("EXT2", "TODO - Implement using blocks outside the current block group");
+ blockgroup = 0;
+ while( blockgroup < firstgroup && Disk->Groups[blockgroup].bg_free_blocks_count == 0 )
+ blockgroup ++;
+ }
+ if( Disk->Groups[blockgroup].bg_free_blocks_count == 0 ) {
+ Log_Notice("Ext2", "Ext2_int_AllocateBlock - Out of blockss on %p, but superblock says some free",
+ Disk);
return 0;
}
+
+ // Search the bitmap for a free block
+ bg = &Disk->Groups[blockgroup];
+ int ofs = 0;
+ do {
+ const int sector_size = 512;
+ Uint8 buf[sector_size];
+ VFS_ReadAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+ int byte, bit;
+ for( byte = 0; byte < sector_size && buf[byte] != 0xFF; byte ++ )
+ ;
+ if( byte < sector_size )
+ {
+ for( bit = 0; bit < 8 && buf[byte] & (1 << bit); bit ++)
+ ;
+ ASSERT(bit != 8);
+ buf[byte] |= 1 << bit;
+ VFS_WriteAt(Disk->FD, Disk->BlockSize*bg->bg_block_bitmap+ofs, sector_size, buf);
+
+ bg->bg_free_blocks_count --;
+ Disk->SuperBlock.s_free_blocks_count --;
+
+ #if EXT2_UPDATE_WRITEBACK
+ Ext2_int_UpdateSuperblock(Disk);
+ #endif
+
+ Uint32 ret = blockgroup * Disk->SuperBlock.s_blocks_per_group + byte * 8 + bit;
+ Log_Debug("Ext2", "Ext2_int_AllocateBlock - Allocated 0x%x", ret);
+ return ret;
+ }
+ } while(ofs < Disk->SuperBlock.s_blocks_per_group / 8);
- // Reduce global count
- Disk->SuperBlock.s_free_blocks_count --;
- #if EXT2_UPDATE_WRITEBACK
- Ext2_int_UpdateSuperblock(Disk);
- #endif
-
- return block;
+ Log_Notice("Ext2", "Ext2_int_AllocateBlock - Out of block in group %p:%i but header reported free",
+ Disk, blockgroup);
+ return 0;
}
/**
*/
void Ext2_int_DeallocateBlock(tExt2_Disk *Disk, Uint32 Block)
{
+ Log_Warning("Ext2", "TODO: Impliment Ext2_int_DeallocateBlock");
}
/**
if( nBlocks == 0 ) {
Inode->i_block[12] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !Inode->i_block[12] ) {
+ Log_Warning("Ext2", "Allocating indirect block failed");
free(blocks);
return 1;
}
if( nBlocks == 0 ) {
Inode->i_block[13] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !Inode->i_block[13] ) {
+ Log_Warning("Ext2", "Allocating double indirect block failed");
free(blocks);
return 1;
}
id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !id1 ) {
free(blocks);
+ Log_Warning("Ext2", "Allocating double indirect block (l2) failed");
return 1;
}
blocks[nBlocks/dwPerBlock] = id1;
if( nBlocks == 0 ) {
Inode->i_block[14] = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !Inode->i_block[14] ) {
+ Log_Warning("Ext2", "Allocating triple indirect block failed");
free(blocks);
return 1;
}
{
id1 = Ext2_int_AllocateBlock(Disk, Inode->i_block[0]);
if( !id1 ) {
+ Log_Warning("Ext2", "Allocating triple indirect block (l2) failed");
free(blocks);
return 1;
}
if( nBlocks % dwPerBlock == 0 ) {
id2 = Ext2_int_AllocateBlock(Disk, id1);
if( !id2 ) {
+ Log_Warning("Ext2", "Allocating triple indirect block (l3) failed");
free(blocks);
return 1;
}
return 0;
}
- Warning("[EXT2 ] Inode %i cannot have a block appended to it, all indirects used");
+ Log_Warning("Ext2", "Inode ?? cannot have a block appended to it, all indirects used");
free(blocks);
return 1;
}
#
#
-OBJ = fat.o
+OBJ = fat.o dir.o fatio.o nodecache.o
NAME = FAT
-include ../Makefile.tpl
--- /dev/null
+/*
+ * Acess2 FAT Filesystem Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * common.h
+ * - FAT internal common header
+ */
+#ifndef _FS__FAT__COMMON_H_
+#define _FS__FAT__COMMON_H_
+
+#include "fs_fat.h"
+#include <vfs.h>
+
+#define CACHE_FAT 0 //!< Caches the FAT in memory
+#define USE_LFN 1 //!< Enables the use of Long File Names
+#define SUPPORT_WRITE 1 //!< Enables write support
+
+#define FAT_FLAG_DIRTY 0x10000
+#define FAT_FLAG_DELETE 0x20000
+
+typedef struct sFAT_VolInfo tFAT_VolInfo;
+#if USE_LFN
+typedef struct sFAT_LFNCacheEnt tFAT_LFNCacheEnt;
+typedef struct sFAT_LFNCache tFAT_LFNCache;
+#endif
+typedef struct sFAT_CachedNode tFAT_CachedNode;
+
+/**
+ * \brief Internal IDs for FAT types
+ */
+enum eFatType
+{
+ FAT12, //!< FAT12 Volume
+ FAT16, //!< FAT16 Volume
+ FAT32, //!< FAT32 Volume
+};
+
+// === TYPES ===
+struct sFAT_VolInfo
+{
+ int fileHandle; //!< File Handle
+ enum eFatType type; //!< FAT Variant
+ char name[12]; //!< Volume Name (With NULL Terminator)
+ Uint32 firstDataSect; //!< First data sector
+ Uint32 rootOffset; //!< Root Offset (clusters)
+ Uint32 ClusterCount; //!< Total Cluster Count
+ fat_bootsect bootsect; //!< Boot Sector
+ tVFS_Node rootNode; //!< Root Node
+ size_t BytesPerCluster;
+
+ tMutex lNodeCache;
+ tFAT_CachedNode *NodeCache;
+
+ tMutex lFAT; //!< Lock to prevent double-writing to the FAT
+ #if CACHE_FAT
+ Uint32 *FATCache; //!< FAT Cache
+ #endif
+};
+
+#if USE_LFN
+/**
+ * \brief Long-Filename cache entry
+ */
+struct sFAT_LFNCacheEnt
+{
+ int ID;
+ Uint16 Data[256];
+};
+/**
+ * \brief Long-Filename cache
+ */
+struct sFAT_LFNCache
+{
+ int NumEntries;
+ tFAT_LFNCacheEnt Entries[];
+};
+#endif
+
+struct sFAT_CachedNode
+{
+ struct sFAT_CachedNode *Next;
+ tVFS_Node Node;
+};
+
+// --- General Helpers ---
+extern int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster);
+extern tTime FAT_int_GetAcessTimestamp(Uint16 Date, Uint16 Time, Uint8 MS);
+extern void FAT_int_GetFATTimestamp(tTime AcessTimestamp, Uint16 *Date, Uint16 *Time, Uint8 *MS);
+
+// --- Node Caching ---
+// NOTE: FAT uses its own node cache that references by cluster (not the inode value that the Inode_* cache uses)
+// because tVFS_Node.Inode contains the parent directory inode
+extern tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry);
+extern tVFS_Node *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster);
+extern tVFS_Node *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster);
+extern int FAT_int_DerefNode(tVFS_Node *Node);
+extern void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk);
+
+// --- FAT Access ---
+#define GETFATVALUE_EOC 0xFFFFFFFF
+extern Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);
+#if SUPPORT_WRITE
+extern Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);
+extern Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster);
+#endif
+extern void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);
+extern void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, const void *Buffer);
+
+// --- Directory Access ---
+extern int FAT_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
+extern tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name);
+extern tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
+extern int FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry);
+#if SUPPORT_WRITE
+extern int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry);
+extern tVFS_Node *FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);
+extern int FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *Node);
+extern int FAT_Unlink(tVFS_Node *DirNode, const char *OldName);
+#endif
+extern void FAT_CloseFile(tVFS_Node *node);
+
+// === GLOBALS ===
+extern tVFS_NodeType gFAT_DirType;
+extern tVFS_NodeType gFAT_FileType;
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * dir.c
+ * - Directory access/manipulation code
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === PROTOTYPES ===
+void FAT_int_ProperFilename(char *dest, const char *src);
+ int FAT_int_CreateName(fat_filetable *ft, const Uint16 *LongFileName, char *Dest);
+ int FAT_int_ConvertUTF16_to_UTF8(Uint8 *Dest, const Uint16 *Source);
+ int FAT_int_ConvertUTF8_to_UTF16(Uint16 *Dest, const Uint8 *Source);
+
+ int FAT_int_GetEntryByName(tVFS_Node *DirNode, const char *Name, fat_filetable *Entry);
+ int FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry);
+ int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer);
+#if SUPPORT_WRITE
+ int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry);
+#endif
+#if USE_LFN
+Uint16 *FAT_int_GetLFN(tVFS_Node *Node, int ID);
+void FAT_int_DelLFN(tVFS_Node *Node, int ID);
+#endif
+ int FAT_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
+tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name);
+tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
+#if SUPPORT_WRITE
+tVFS_Node *FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int FAT_int_IsValid83Filename(const char *Name);
+ int FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *Node);
+ int FAT_Relink(tVFS_Node *node, const char *OldName, const char *NewName);
+#endif
+
+// === CODE ===
+
+/**
+ * \brief Converts a FAT directory entry name into a proper filename
+ * \param dest Destination array (must be at least 13 bytes in size)
+ * \param src 8.3 filename (concatenated, e.g 'FILE1 TXT')
+ */
+void FAT_int_ProperFilename(char *dest, const char *src)
+{
+ int inpos, outpos;
+
+ // Name
+ outpos = 0;
+ for( inpos = 0; inpos < 8; inpos++ ) {
+ if(src[inpos] == ' ') break;
+ dest[outpos++] = src[inpos];
+ }
+ inpos = 8;
+ // Check for empty extensions
+ if(src[8] != ' ')
+ {
+ dest[outpos++] = '.';
+ for( ; inpos < 11; inpos++) {
+ if(src[inpos] == ' ') break;
+ dest[outpos++] = src[inpos];
+ }
+ }
+ dest[outpos++] = '\0';
+
+ //LOG("dest='%s'", dest);
+}
+
+/**
+ * \fn char *FAT_int_CreateName(fat_filetable *ft, Uint8 *LongFileName)
+ * \brief Converts either a LFN or a 8.3 Name into a proper name
+ * \param ft Pointer to the file's entry in the parent directory
+ * \param LongFileName Long file name pointer
+ * \return Filename as a heap string
+ */
+int FAT_int_CreateName(fat_filetable *ft, const Uint16 *LongFileName, char *Dest)
+{
+ ENTER("pft sLongFileName", ft, LongFileName);
+ #if USE_LFN
+ if(LongFileName && LongFileName[0] != 0)
+ {
+ int len = FAT_int_ConvertUTF16_to_UTF8(NULL, LongFileName);
+ if( len > FILENAME_MAX ) {
+ return -1;
+ }
+ FAT_int_ConvertUTF16_to_UTF8((Uint8*)Dest, LongFileName);
+ }
+ else
+ {
+ #endif
+ FAT_int_ProperFilename(Dest, ft->name);
+ #if USE_LFN
+ }
+ #endif
+ return 0;
+}
+
+#if USE_LFN
+int FAT_int_CompareUTF16_UTF8(const Uint16 *Str16, const char *Str8)
+{
+ int pos16 = 0, pos8 = 0;
+ const Uint8 *str8 = (const Uint8 *)Str8;
+
+ while( Str16[pos16] && str8[pos8] )
+ {
+ Uint32 cp8, cp16;
+ if( Str16[pos16] & 0x8000 ) {
+ // Do something!
+ cp16 = 0;
+ }
+ else {
+ cp16 = Str16[pos16];
+ pos16 ++;
+ }
+ pos8 += ReadUTF8(str8 + pos8, &cp8);
+
+ if(cp16 == cp8) continue ;
+
+ if(cp16 < cp8)
+ return -1;
+ else
+ return 1;
+ }
+ if(Str16[pos16] == str8[pos8])
+ return 0;
+ if(Str16[pos16] < str8[pos8])
+ return -1;
+ else
+ return 1;
+}
+
+int FAT_int_ConvertUTF16_to_UTF8(Uint8 *Dest, const Uint16 *Source)
+{
+ int len = 0;
+ for( ; *Source; Source ++ )
+ {
+ // TODO: Decode/Reencode
+ if( Dest )
+ Dest[len] = *Source;
+ len += 1;
+ }
+ if( Dest )
+ Dest[len] = 0;
+ return len;
+}
+
+int FAT_int_ConvertUTF8_to_UTF16(Uint16 *Dest, const Uint8 *Source)
+{
+ int len = 0;
+ while( *Source )
+ {
+ Uint32 cp;
+ int cpl;
+
+ cpl = ReadUTF8(Source, &cp);
+ if(cp < 0x8000) {
+ if( Dest )
+ Dest[len] = cp;
+ len ++;
+ }
+ else {
+ // TODO!
+ }
+ Source += cpl;
+ }
+ Dest[len] = 0;
+ return len;
+}
+
+int FAT_int_ParseLFN(const fat_filetable *Entry, Uint16 *Buffer)
+{
+ const fat_longfilename *lfnInfo;
+ int ofs;
+
+ lfnInfo = (const void*)Entry;
+
+ if(lfnInfo->id & 0x40) {
+ memset(Buffer, 0, 256*2);
+ }
+ ofs = (lfnInfo->id & 0x3F) * 13 - 1;
+ if( ofs >= 255 )
+ return -1;
+
+ Buffer[ofs--] = lfnInfo->name3[1]; Buffer[ofs--] = lfnInfo->name3[0];
+ Buffer[ofs--] = lfnInfo->name2[5]; Buffer[ofs--] = lfnInfo->name2[4];
+ Buffer[ofs--] = lfnInfo->name2[3]; Buffer[ofs--] = lfnInfo->name2[2];
+ Buffer[ofs--] = lfnInfo->name2[1]; Buffer[ofs--] = lfnInfo->name2[0];
+ Buffer[ofs--] = lfnInfo->name1[4]; Buffer[ofs--] = lfnInfo->name1[3];
+ Buffer[ofs--] = lfnInfo->name1[2]; Buffer[ofs--] = lfnInfo->name1[1];
+ Buffer[ofs--] = lfnInfo->name1[0];
+
+ if((lfnInfo->id&0x3F) == 1)
+ return 1;
+ return 0;
+}
+#endif
+
+int FAT_int_GetEntryByName(tVFS_Node *DirNode, const char *Name, fat_filetable *Entry)
+{
+ fat_filetable fileinfo[16];
+ char tmpName[13];
+ #if USE_LFN
+ Uint16 lfn[256];
+ int lfnId = -1;
+ #endif
+
+ ENTER("pDirNode sName pEntry", DirNode, Name, Entry);
+
+ for( int i = 0; ; i++ )
+ {
+ if((i & 0xF) == 0) {
+ if(FAT_int_ReadDirSector(DirNode, i/16, fileinfo))
+ {
+ LEAVE('i', -1);
+ return -1;
+ }
+ }
+
+ //Check if the files are free
+ if(fileinfo[i&0xF].name[0] == '\0') break; // End of List marker
+ if(fileinfo[i&0xF].name[0] == '\xE5') continue; // Free entry
+
+
+ #if USE_LFN
+ // Long File Name Entry
+ if(fileinfo[i & 0xF].attrib == ATTR_LFN)
+ {
+ if( FAT_int_ParseLFN(&fileinfo[i&0xF], lfn) )
+ lfnId = i+1;
+ continue ;
+ }
+ // Remove LFN if it does not apply
+ if(lfnId != i) lfn[0] = 0;
+ #else
+ if(fileinfo[i&0xF].attrib == ATTR_LFN) continue;
+ #endif
+
+ // Get Real Filename
+ FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);
+// LOG("tmpName = '%s'", tmpName);
+// #if DEBUG
+// Debug_HexDump("FAT tmpName", tmpName, strlen(tmpName));
+// #endif
+/*
+ #if DEBUG && USE_LFN
+ if(lfnId == i)
+ {
+ Uint8 lfntmp[256*3+1];
+ FAT_int_ConvertUTF16_to_UTF8(lfntmp, lfn);
+ LOG("lfntmp = '%s'", lfntmp);
+ }
+ #endif
+*/
+
+ // Only the long name is case sensitive, 8.3 is not
+ #if USE_LFN
+ if(strucmp(tmpName, Name) == 0 || FAT_int_CompareUTF16_UTF8(lfn, Name) == 0)
+ #else
+ if(strucmp(tmpName, Name) == 0)
+ #endif
+ {
+ memcpy(Entry, fileinfo + (i&0xF), sizeof(*Entry));
+ LOG("Found %s at %i", Name, i);
+ LEAVE('i', i);
+ return i;
+ }
+ }
+
+ LEAVE('i', -1);
+ return -1;
+}
+
+int FAT_int_GetEntryByCluster(tVFS_Node *DirNode, Uint32 Cluster, fat_filetable *Entry)
+{
+ int ents_per_sector = 512 / sizeof(fat_filetable);
+ fat_filetable fileinfo[ents_per_sector];
+ int i, sector;
+
+ if( Mutex_Acquire(&DirNode->Lock) ) {
+ return -EINTR;
+ }
+
+ sector = 0;
+ for( i = 0; ; i ++ )
+ {
+ if( i == 0 || i == ents_per_sector )
+ {
+ if(FAT_int_ReadDirSector(DirNode, sector, fileinfo))
+ {
+ LOG("ReadDirSector failed");
+ break ;
+ }
+ i = 0;
+ sector ++;
+ }
+
+ // Check for free/end of list
+ if(fileinfo[i].name[0] == '\0') break; // End of List marker
+ if(fileinfo[i].name[0] == '\xE5') continue; // Free entry
+
+ if(fileinfo[i].attrib == ATTR_LFN) continue;
+
+ LOG("fileinfo[i].cluster = %x:%04x", fileinfo[i].clusterHi, fileinfo[i].cluster);
+ #if DEBUG
+ {
+ char tmpName[13];
+ FAT_int_ProperFilename(tmpName, fileinfo[i].name);
+ LOG("tmpName = '%s'", tmpName);
+ }
+ #endif
+
+
+ if(fileinfo[i].cluster != (Cluster & 0xFFFF)) continue;
+ if(fileinfo[i].clusterHi != ((Cluster >> 16) & 0xFFFF)) continue;
+
+ memcpy(Entry, &fileinfo[i], sizeof(*Entry));
+ Mutex_Release(&DirNode->Lock);
+ return i;
+ }
+
+ Mutex_Release(&DirNode->Lock);
+ return -ENOENT;
+}
+
+/*
+ * ====================
+ * Directory IO
+ * ====================
+ */
+
+/**
+ * \brief Reads a sector from the disk
+ * \param Node Directory node to read
+ * \param Sector Sector number in the directory to read
+ * \param Buffer Destination buffer for the read data
+ */
+int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)
+{
+ Uint64 addr;
+ tFAT_VolInfo *disk = Node->ImplPtr;
+
+ ENTER("pNode iSector pEntry", Node, Sector, Buffer);
+
+ // Parse address
+ if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))
+ {
+ LEAVE('i', 1);
+ return 1;
+ }
+
+ LOG("addr = 0x%llx", addr);
+ // Read Sector
+ if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)
+ {
+ LEAVE('i', 1);
+ return 1;
+ }
+
+ LEAVE('i', 0);
+ return 0;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Write a sector to the disk
+ * \param Node Directory node to write
+ * \param Sector Sector number in the directory to write
+ * \param Buffer Source data
+ */
+int FAT_int_WriteDirSector(tVFS_Node *Node, int Sector, const fat_filetable *Buffer)
+{
+ Uint64 addr;
+ tFAT_VolInfo *disk = Node->ImplPtr;
+
+ ENTER("pNode iSector pEntry", Node, Sector, Buffer);
+
+ // Parse address
+ if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))
+ {
+ LEAVE('i', 1);
+ return 1;
+ }
+
+ // Read Sector
+ if(VFS_WriteAt(disk->fileHandle, addr, 512, Buffer) != 512)
+ {
+ LEAVE('i', 1);
+ return 1;
+ }
+
+ LEAVE('i', 0);
+ return 0;
+}
+
+/**
+ * \brief Writes an entry to the disk
+ * \todo Support expanding a directory
+ * \param Node Directory node
+ * \param ID ID of entry to update
+ * \param Entry Entry data
+ * \return Zero on success, non-zero on error
+ */
+int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)
+{
+ Uint64 addr = 0;
+ int tmp;
+ Uint32 cluster = 0;
+ tFAT_VolInfo *disk = Node->ImplPtr;
+
+ ENTER("pNode iID pEntry", Node, ID, Entry);
+
+ tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);
+ if( tmp )
+ {
+ //TODO: Allocate a cluster
+ cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);
+ if(cluster == -1) {
+ Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);
+ LEAVE('i', 1);
+ return 1;
+ }
+ FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);
+ }
+
+
+ LOG("addr = 0x%llx", addr);
+
+ // Wriet data to disk
+ VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry);
+
+ LEAVE('i', 0);
+ return 0;
+}
+#endif
+
+#if USE_LFN
+/**
+ * \fn Uint16 *FAT_int_GetLFN(tVFS_Node *node)
+ * \brief Return pointer to LFN cache entry
+ * \param Node Directory node
+ * \param ID ID of the short name
+ * \return Pointer to the LFN cache entry
+ */
+Uint16 *FAT_int_GetLFN(tVFS_Node *Node, int ID)
+{
+ tFAT_LFNCache *cache;
+ int i, firstFree;
+
+ if( Mutex_Acquire( &Node->Lock ) ) {
+ return NULL;
+ }
+
+ // TODO: Thread Safety (Lock things)
+ cache = Node->Data;
+
+ // Create a cache if it isn't there
+ if(!cache) {
+ cache = Node->Data = malloc( sizeof(tFAT_LFNCache) + sizeof(tFAT_LFNCacheEnt) );
+ cache->NumEntries = 1;
+ cache->Entries[0].ID = ID;
+ cache->Entries[0].Data[0] = 0;
+ Mutex_Release( &Node->Lock );
+ //Log_Debug("FAT", "Return = %p (new)", cache->Entries[0].Data);
+ return cache->Entries[0].Data;
+ }
+
+ // Scan for this entry
+ firstFree = -1;
+ for( i = 0; i < cache->NumEntries; i++ )
+ {
+ if( cache->Entries[i].ID == ID ) {
+ Mutex_Release( &Node->Lock );
+ //Log_Debug("FAT", "Return = %p (match)", cache->Entries[i].Data);
+ return cache->Entries[i].Data;
+ }
+ if( cache->Entries[i].ID == -1 && firstFree == -1 )
+ firstFree = i;
+ }
+
+ if(firstFree == -1) {
+ // Use `i` for temp length
+ i = sizeof(tFAT_LFNCache) + (cache->NumEntries+1)*sizeof(tFAT_LFNCacheEnt);
+ Node->Data = realloc( Node->Data, i );
+ if( !Node->Data ) {
+ Log_Error("FAT", "realloc() fail, unable to allocate %i for LFN cache", i);
+ Mutex_Release( &Node->Lock );
+ return NULL;
+ }
+ //Log_Debug("FAT", "Realloc (%i)\n", i);
+ cache = Node->Data;
+ i = cache->NumEntries;
+ cache->NumEntries ++;
+ }
+ else {
+ i = firstFree;
+ }
+
+ // Create new entry
+ cache->Entries[ i ].ID = ID;
+ cache->Entries[ i ].Data[0] = '\0';
+
+ Mutex_Release( &Node->Lock );
+ //Log_Debug("FAT", "Return = %p (firstFree, i = %i)", cache->Entries[i].Data, i);
+ return cache->Entries[ i ].Data;
+}
+
+/**
+ * \fn void FAT_int_DelLFN(tVFS_Node *node)
+ * \brief Delete a LFN cache entry
+ * \param Node Directory node
+ * \param ID File Entry ID
+ */
+void FAT_int_DelLFN(tVFS_Node *Node, int ID)
+{
+ tFAT_LFNCache *cache = Node->Data;
+ int i;
+
+ // Fast return
+ if(!cache) return;
+
+ // Scan for a current entry
+ for( i = 0; i < cache->NumEntries; i++ )
+ {
+ if( cache->Entries[i].ID == ID )
+ cache->Entries[i].ID = -1;
+ }
+ return ;
+}
+#endif
+
+/**
+ * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)
+ * \param Node Node structure of directory
+ * \param ID Directory position
+ * \return Filename as a heap string, NULL or VFS_SKIP
+ */
+int FAT_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
+{
+ fat_filetable fileinfo[16]; // sizeof(fat_filetable)=32, so 16 per sector
+ int a;
+ #if USE_LFN
+ Uint16 *lfn = NULL;
+ #endif
+
+ ENTER("pNode iID", Node, ID);
+
+ if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))
+ {
+ LOG("End of chain, end of dir");
+ LEAVE('i', -EIO);
+ return -EIO;
+ }
+
+ // Offset in sector
+ a = ID % 16;
+
+ LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]);
+
+ // Check if this is the last entry
+ if( fileinfo[a].name[0] == '\0' ) {
+ Node->Size = ID;
+ LOG("End of list");
+ LEAVE('i', -ENOENT);
+ return -ENOENT; // break
+ }
+
+ // Check for empty entry
+ if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {
+ LOG("Empty Entry");
+ LEAVE_RET('i', 1); // Skip
+ }
+
+ #if USE_LFN
+ // Get Long File Name Cache
+ if(fileinfo[a].attrib == ATTR_LFN)
+ {
+ fat_longfilename *lfnInfo;
+
+ lfnInfo = (fat_longfilename *) &fileinfo[a];
+
+ // Get cache for corresponding file
+ // > ID + Index gets the corresponding short node
+ lfn = FAT_int_GetLFN( Node, ID + (lfnInfo->id & 0x3F) );
+
+ a = FAT_int_ParseLFN(&fileinfo[a], lfn);
+ if( a < 0 ) {
+ LOG("Invalid LFN, error");
+ LEAVE_RET('i', -EIO);
+ }
+
+ LEAVE_RET('i', 1); // Skip
+ }
+ #endif
+
+ // Check if it is a volume entry
+ if(fileinfo[a].attrib & 0x08) {
+ LEAVE_RET('i', 1); // Skip
+ }
+ // Ignore .
+ if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == ' ') {
+ LEAVE_RET('i', 1); // Skip
+ }
+ // and ..
+ if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == '.' && fileinfo[a].name[2] == ' ') {
+ LEAVE_RET('i', 1); // Skip
+ }
+
+ LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",
+ fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],
+ fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],
+ fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );
+
+ #if USE_LFN
+ lfn = FAT_int_GetLFN(Node, ID);
+ //Log_Debug("FAT", "lfn = %p'%s'", lfn, lfn);
+ FAT_int_CreateName(&fileinfo[a], lfn, Dest);
+ #else
+ FAT_int_CreateName(&fileinfo[a], NULL, Dest);
+ #endif
+
+ LEAVE('i', 0);
+ return 0;
+}
+
+/**
+ * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)
+ * \brief Finds an entry in the current directory
+ */
+tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name)
+{
+ fat_filetable fileent;
+
+ ENTER("pNode sname", Node, Name);
+
+ // Fast Returns
+ if(!Name || Name[0] == '\0') {
+ LEAVE('n');
+ return NULL;
+ }
+
+ if( FAT_int_GetEntryByName(Node, Name, &fileent) == -1 ) {
+ LEAVE('n');
+ return NULL;
+ }
+
+
+ tVFS_Node *ret = FAT_int_CreateNode(Node, &fileent);
+ LOG("Found %s as %p", Name, ret);
+ LEAVE('p', ret);
+ return ret;
+}
+
+tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)
+{
+ tFAT_VolInfo *disk = Root->ImplPtr;
+ tVFS_Node *dirnode, *ret;
+ fat_filetable ft;
+
+ ENTER("pRoot XInode", Root, Inode);
+
+ ret = FAT_int_GetNode(disk, Inode & 0xFFFFFFFF);
+ if( ret ) {
+ if( (ret->Inode >> 32) != 0 ) {
+ LOG("Node in cache, quick return");
+ LEAVE('p', ret);
+ return ret;
+ }
+ else {
+ LOG("Node cached, but incomplete");
+ // Fall on through
+ }
+ ret = NULL;
+ }
+
+ dirnode = FAT_int_CreateIncompleteDirNode(disk, Inode >> 32);
+
+ int id = FAT_int_GetEntryByCluster(dirnode, Inode & 0xFFFFFFFF, &ft);
+ if( id != -1 ) {
+ ret = FAT_int_CreateNode(dirnode, &ft);
+ }
+
+ dirnode->Type->Close(dirnode);
+
+ LEAVE('p', ret);
+ return ret;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Create a new node
+ */
+tVFS_Node *FAT_Mknod(tVFS_Node *DirNode, const char *Name, Uint Flags)
+{
+ tFAT_VolInfo *disk = DirNode->ImplPtr;
+ int rv;
+ fat_filetable ft;
+ memset(&ft, 0, sizeof(ft));
+
+ ENTER("pDirNode sName xFlags", DirNode, Name, Flags);
+
+ // Allocate a cluster
+ Uint32 cluster = FAT_int_AllocateCluster(disk, -1);
+ LOG("Cluster 0x%07x allocated", cluster);
+
+ // Create a temporary file table entry for an empty node
+ ft.cluster = cluster & 0xFFFF;
+ ft.clusterHi = cluster >> 16;
+ ft.size = 0;
+ if( Flags & VFS_FFLAG_DIRECTORY )
+ ft.attrib = ATTR_DIRECTORY;
+ else
+ ft.attrib = 0;
+
+ tVFS_Node *newnode = FAT_int_CreateNode(DirNode, &ft);
+ if( !newnode ) {
+ errno = -EINTERNAL;
+ return NULL;
+ }
+ LOG("newnode = %p", newnode);
+
+ // Call link
+ if( (rv = FAT_Link(DirNode, Name, newnode)) ) {
+ newnode->ImplInt |= FAT_FLAG_DELETE;
+ }
+ LEAVE('p', newnode);
+ return newnode;
+}
+
+/**
+ * \brief Internal - Checks if a character is valid in an 8.3 filename
+ */
+static inline int is_valid_83_char(char ch)
+{
+ if( '0' <= ch && ch <= '9' )
+ return 1;
+ if( 'A' <= ch && ch <= 'Z' )
+ return 1;
+ if( 'a' <= ch && ch <= 'z' )
+ return 1;
+ if( strchr("$%'-_@~`#!(){}^#&", ch) )
+ return 1;
+ if( ch > 128 )
+ return 1;
+ return 0;
+}
+
+Uint8 FAT_int_UnicodeTo83(Uint32 Input)
+{
+ Input = toupper(Input);
+ // Input = unicode_to_oem(Input);
+ if( Input > 256 )
+ Input = '_';
+ if(!is_valid_83_char(Input))
+ Input = '_';
+ return Input;
+}
+
+/**
+ * \brief Internal - Determines if a filename is a valid 8.3 filename
+ */
+int FAT_int_IsValid83Filename(const char *Name)
+{
+ int i, j;
+
+ if( !Name[0] || Name[0] == '.' )
+ return 0;
+
+ // Check filename portion
+ for( i = 0; Name[i] && i < 8; i ++ )
+ {
+ if( Name[i] == '.' )
+ break;
+ if( !is_valid_83_char(Name[i]) )
+ return 0;
+ }
+ // If the next char is not \0 or '.', it's not valid
+ if( Name[i] && Name[i++] != '.' )
+ return 0;
+
+ // Check the extension portion
+ for( j = 0; Name[i+j] && j < 3; j ++ )
+ {
+ if( !is_valid_83_char(Name[i+j]) )
+ return 0;
+ }
+
+ // After the extension must be the end
+ if( Name[i+j] )
+ return 0;
+
+ return 1;
+}
+
+Uint8 FAT_int_MakeLFNChecksum(const char *ShortName)
+{
+ Uint8 ret = 0;
+ for( int i = 0; i < 11; i++ )
+ {
+ // ret = (ret >>> 1) + ShortName[i]
+ // where >>> is rotate right
+ ret = ((ret & 1) ? 0x80 : 0x00) + (ret >> 1) + ShortName[i];
+ }
+ return ret;
+}
+
+/**
+ * \brief Create a new name for a file
+ * \note Since FAT doesn't support reference counting, this will cause double-references if
+ * a file is hardlinked and not unlinked
+ */
+int FAT_Link(tVFS_Node *DirNode, const char *NewName, tVFS_Node *NewNode)
+{
+ Uint16 lfn[256];
+ fat_filetable ft;
+ int nLFNEnt = 0;
+ const int eps = 512 / sizeof(fat_filetable);
+ fat_filetable fileinfo[eps];
+
+ if( Mutex_Acquire( &DirNode->Lock ) ) {
+ return EINTR;
+ }
+
+ // -- Ensure duplicates aren't created --
+ if( FAT_int_GetEntryByName(DirNode, NewName, &ft) >= 0 ) {
+ Mutex_Release( &DirNode->Lock );
+ return EEXIST;
+ }
+
+ // -- Create filetable entry --
+ #if 0
+ {
+ int bDirty = 0;
+ int inofs = 0;
+ while( NewName[inofs] && NewName[inofs] == '.' )
+ inofs ++, bDirty = 1;
+ for( int i = 0; i < 8 && NewName[inofs] && NewName[inofs] != '.'; i ++ )
+ {
+ Uint32 cp;
+ inofs += ReadUTF8(NewName + inofs, &cp);
+ // Spaces are silently skipped
+ if(isspace(cp)) {
+ i --, bDirty = 1;
+ continue ;
+ }
+ ft.name[i] = FAT_int_UnicodeTo83(cp);
+ if(ft.name[i] != cp)
+ bDirty = 1;
+ }
+ while( NewName[inofs] && NewName[inofs] != '.' )
+ inofs ++, bDirty = 1;
+ for( ; i < 8+3 && NewName[inofs]; i ++ )
+ {
+ Uint32 cp;
+ inofs += ReadUTF8(NewName + inofs, &cp);
+ // Spaces are silently skipped
+ if(isspace(cp)) {
+ i --, bDirty = 1;
+ continue ;
+ }
+ ft.name[i] = FAT_int_UnicodeTo83(cp);
+ if(ft.name[i] != cp)
+ bDirty = 1;
+ }
+ if( !NewName[inofs] ) bDirty = 1;
+
+ if( bDirty )
+ {
+ int lfnlen = FAT_int_ConvertUTF8_to_UTF16(lfn, (const Uint8*)NewName);
+ lfn[lfnlen] = 0;
+ nLFNEnt = DivUp(lfnlen, 13);
+ }
+ }
+ #endif
+ int bNeedsLFN = !FAT_int_IsValid83Filename(NewName);
+ if( bNeedsLFN )
+ {
+ int lfnlen = FAT_int_ConvertUTF8_to_UTF16(lfn, (const Uint8*)NewName);
+ lfn[lfnlen] = 0;
+ nLFNEnt = DivUp(lfnlen, 13);
+
+ // Create a base mangled filetable entry
+ int i, j = 0;
+ while(NewName[j] == '.') j ++; // Eat leading dots
+ for( i = 0; i < 6 && NewName[j] && NewName[j] != '.'; i ++, j ++ )
+ {
+ if( !isalpha(NewName[j]) && !is_valid_83_char(NewName[j]) )
+ ft.name[i] = '_';
+ else
+ ft.name[i] = toupper(NewName[j]);
+ }
+ ft.name[i++] = '~';
+ ft.name[i++] = '1';
+ while(i < 8) ft.name[i++] = ' ';
+ while(NewName[j] && NewName[j] != '.') j ++;
+ for( ; i < 8+3 && NewName[j]; i ++, j ++ )
+ {
+ if( NewName[j] == '.' )
+ i --;
+ else if( !is_valid_83_char(NewName[j]) )
+ ft.name[i] = '_';
+ else
+ ft.name[i] = toupper(NewName[j]);
+ }
+ while(i < 8+3) ft.name[i++] = ' ';
+
+ // - Ensure there isn't a duplicate short-name
+ int bIsDuplicate = 1;
+ while( bIsDuplicate )
+ {
+ bIsDuplicate = 0; // Assume none
+
+ // Scan directory
+ for( int id = 0; ; id ++ )
+ {
+ if( id % eps == 0 )
+ {
+ if(FAT_int_ReadDirSector(DirNode, id/eps, fileinfo))
+ break; // end of cluster chain
+ }
+
+ // End of file list
+ if( fileinfo[id%eps].name[0] == '\0' ) break;
+ // Empty entry
+ if( fileinfo[id%eps].name[0] == '\xE5' ) continue;
+ // LFN entry
+ if( fileinfo[id%eps].attrib == ATTR_LFN ) continue;
+
+ // Is this a duplicate?
+ if( memcmp(ft.name, fileinfo[id%eps].name, 8+3) == 0 ) {
+ bIsDuplicate = 1;
+ break;
+ }
+
+ // No - move a long
+ }
+
+ // If a duplicate was found, increment the suffix
+ if( bIsDuplicate )
+ {
+ if( ft.name[7] == '9' ) {
+ // TODO: Expand into ~00
+ Log_Error("FAT", "TODO: Use two digit LFN suffixes");
+ Mutex_Release(&DirNode->Lock);
+ return ENOTIMPL;
+ }
+
+ ft.name[7] += 1;
+ }
+ }
+ }
+ else
+ {
+ // Create pure filetable entry
+ int i;
+ // - Copy filename
+ for( i = 0; i < 8 && *NewName && *NewName != '.'; i ++, NewName++ )
+ ft.name[i] = *NewName;
+ // - Pad with spaces
+ for( ; i < 8; i ++ )
+ ft.name[i] = ' ';
+ // - Eat '.'
+ if(*NewName)
+ NewName ++;
+ // - Copy extension
+ for( ; i < 8+3 && *NewName; i ++, NewName++ )
+ ft.name[i] = *NewName;
+ // - Pad with spaces
+ for( ; i < 8+3; i ++ )
+ ft.name[i] = ' ';
+ }
+
+ ft.attrib = 0;
+ if(NewNode->Flags & VFS_FFLAG_DIRECTORY )
+ ft.attrib |= ATTR_DIRECTORY;
+ ft.ntres = 0;
+ FAT_int_GetFATTimestamp(NewNode->CTime, &ft.cdate, &ft.ctime, &ft.ctimems);
+// ft.ctimems = ft.ctimems;
+ ft.ctime = LittleEndian16(ft.ctime);
+ ft.cdate = LittleEndian16(ft.cdate);
+ FAT_int_GetFATTimestamp(NewNode->MTime, &ft.mdate, &ft.mtime, NULL);
+ ft.mtime = LittleEndian16(ft.mtime);
+ ft.mdate = LittleEndian16(ft.mdate);
+ FAT_int_GetFATTimestamp(NewNode->ATime, &ft.adate, NULL, NULL);
+ ft.adate = LittleEndian16(ft.adate);
+ ft.clusterHi = LittleEndian16((NewNode->Inode >> 16) & 0xFFFF);
+ ft.cluster = LittleEndian16(NewNode->Inode & 0xFFFF);
+ ft.size = LittleEndian32(NewNode->Size);
+
+ LOG("ft.name = '%.11s'", ft.name);
+
+ // -- Add entry to the directory --
+ // Locate a range of nLFNEnt + 1 free entries
+ int end_id = -1;
+ int range_first = 0, range_last = -1;
+ for( int id = 0; ; id ++ )
+ {
+ if( id % eps == 0 )
+ {
+ if(FAT_int_ReadDirSector(DirNode, id/eps, fileinfo))
+ break; // end of cluster chain
+ }
+
+ // End of file list, break out
+ if( fileinfo[id%eps].name[0] == '\0' ) {
+ if( id - range_first == nLFNEnt )
+ range_last = id;
+ end_id = id;
+ break;
+ }
+
+ // If an entry is occupied, clear the range
+ if( fileinfo[id%eps].name[0] != '\xE5' ) {
+ range_first = id + 1;
+ continue ;
+ }
+
+ // Free entry, check if we have enough
+ if( id - range_first == nLFNEnt ) {
+ range_last = id;
+ break;
+ }
+ // Check the next one
+ }
+ if( range_last == -1 )
+ {
+ // - If there are none, defragment the directory?
+
+ // - Else, expand the directory
+ if( end_id == -1 ) {
+ // End of cluster chain
+ }
+ else {
+ // Just end of block
+ }
+ // - and if that fails, return an error
+ Log_Warning("FAT", "TODO: Impliment directory expansion / defragmenting");
+ Mutex_Release(&DirNode->Lock);
+ return ENOTIMPL;
+ }
+
+ // Calculate the checksum used for LFN
+ Uint8 lfn_checksum = 0;
+ if( nLFNEnt )
+ {
+ lfn_checksum = FAT_int_MakeLFNChecksum(ft.name);
+ }
+
+ // Insert entries
+ if( range_first % eps != 0 )
+ FAT_int_ReadDirSector(DirNode, range_first/eps, fileinfo);
+ for( int id = range_first; id <= range_last; id ++ )
+ {
+ if( id % eps == 0 ) {
+ if( id != range_first )
+ FAT_int_WriteDirSector(DirNode, (id-1)/eps, fileinfo);
+ FAT_int_ReadDirSector(DirNode, id/eps, fileinfo);
+ }
+
+ if( id == range_last ) {
+ // Actual entry
+ memcpy(fileinfo + id % eps, &ft, sizeof(fat_filetable));
+ }
+ else {
+ // Long filename
+ int lfnid = (nLFNEnt - (id - range_first));
+ int ofs = (lfnid-1) * 13;
+ int i=0, j=0;
+ fat_longfilename *lfnent = (void*)( fileinfo + id%eps );
+
+ lfnent->id = 0x40 | lfnid;
+ lfnent->attrib = ATTR_LFN;
+ lfnent->type = 0;
+ lfnent->firstCluster = 0;
+ lfnent->checksum = lfn_checksum; // ???
+
+ for( i = 0; i < 13; i ++ )
+ {
+ Uint16 wd;
+ if( (wd = lfn[ofs+j]) ) j ++;
+ wd = LittleEndian16(wd);
+ if(i < 5)
+ lfnent->name1[i ] = wd;
+ else if( i < 5+6 )
+ lfnent->name2[i-5 ] = wd;
+ else
+ lfnent->name3[i-5-6] = wd;
+ }
+ }
+ }
+ FAT_int_WriteDirSector(DirNode, range_last/eps, fileinfo);
+
+ Mutex_Release( &DirNode->Lock );
+ return 0;
+}
+
+/**
+ * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)
+ * \brief Rename / Delete a file
+ */
+int FAT_Unlink(tVFS_Node *Node, const char *OldName)
+{
+ tVFS_Node *child;
+ fat_filetable ft;
+
+ if( Mutex_Acquire(&Node->Lock) ) {
+ return EINTR;
+ }
+
+ int id = FAT_int_GetEntryByName(Node, OldName, &ft);
+ if(id == -1) {
+ Mutex_Release(&Node->Lock);
+ return ENOTFOUND;
+ }
+
+ child = FAT_int_CreateNode(Node->ImplPtr, &ft);
+ if( !child ) {
+ Mutex_Release(&Node->Lock);
+ return EINVAL;
+ }
+ child->ImplInt |= FAT_FLAG_DELETE; // Mark for deletion on close
+
+ // TODO: If it has a LFN, remove that too
+
+ // Delete from the directory
+ ft.name[0] = '\xE5';
+ FAT_int_WriteDirEntry(Node, id, &ft);
+
+ // Close child
+ child->Type->Close( child );
+ Mutex_Release( &Node->Lock );
+ return EOK;
+}
+#endif
#define DEBUG 0\r
#define VERBOSE 1\r
\r
-#define CACHE_FAT 0 //!< Caches the FAT in memory\r
-#define USE_LFN 1 //!< Enables the use of Long File Names\r
-#define SUPPORT_WRITE 0 //!< Enables write support\r
-\r
#include <acess.h>\r
#include <modules.h>\r
-#include <vfs.h>\r
-#include "fs_fat.h"\r
-\r
-#define FAT_FLAG_DIRTY 0x10000\r
-#define FAT_FLAG_DELETE 0x20000\r
-\r
-// === TYPES ===\r
-#if USE_LFN\r
-/**\r
- * \brief Long-Filename cache entry\r
- */\r
-typedef struct sFAT_LFNCacheEnt\r
-{\r
- int ID;\r
- // TODO: Handle UTF16 names correctly\r
- char Data[256];\r
-} tFAT_LFNCacheEnt;\r
-/**\r
- * \brief Long-Filename cache\r
- */\r
-typedef struct sFAT_LFNCache\r
-{\r
- int NumEntries;\r
- tFAT_LFNCacheEnt Entries[];\r
-} tFAT_LFNCache;\r
-#endif\r
+#include "common.h"\r
\r
// === PROTOTYPES ===\r
// --- Driver Core\r
int FAT_Install(char **Arguments);\r
+ int FAT_Detect(int FD);\r
tVFS_Node *FAT_InitDevice(const char *device, const char **options);\r
void FAT_Unmount(tVFS_Node *Node);\r
// --- Helpers\r
int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster);\r
-Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 Cluster);\r
-#if SUPPORT_WRITE\r
-Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous);\r
-Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster);\r
-#endif\r
-void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer);\r
// --- File IO\r
size_t FAT_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);\r
#if SUPPORT_WRITE\r
-void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer);\r
-size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);\r
-#endif\r
-// --- Directory IO\r
-char *FAT_ReadDir(tVFS_Node *Node, int ID);\r
-tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name);\r
-tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);\r
-#if SUPPORT_WRITE\r
- int FAT_Mknod(tVFS_Node *Node, const char *Name, Uint Flags);\r
- int FAT_Relink(tVFS_Node *node, const char *OldName, const char *NewName);\r
+size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);\r
#endif\r
void FAT_CloseFile(tVFS_Node *node);\r
\r
+\r
// === Options ===\r
int giFAT_MaxCachedClusters = 1024*512/4;\r
\r
// === SEMI-GLOBALS ===\r
-MODULE_DEFINE(0, (0<<8)|50 /*v0.50*/, VFAT, FAT_Install, NULL, NULL);\r
+MODULE_DEFINE(0, VER2(0,80) /*v0.80*/, VFAT, FAT_Install, NULL, NULL);\r
tFAT_VolInfo gFAT_Disks[8];\r
int giFAT_PartCount = 0;\r
-tVFS_Driver gFAT_FSInfo = {"fat", 0, FAT_InitDevice, FAT_Unmount, FAT_GetNodeFromINode, NULL};\r
+tVFS_Driver gFAT_FSInfo = {\r
+ .Name = "fat",\r
+ .Detect = FAT_Detect,\r
+ .InitDevice = FAT_InitDevice,\r
+ .Unmount = FAT_Unmount,\r
+ .GetNodeFromINode = FAT_GetNodeFromINode\r
+};\r
tVFS_NodeType gFAT_DirType = {\r
.TypeName = "FAT-Dir",\r
.ReadDir = FAT_ReadDir,\r
.FindDir = FAT_FindDir,\r
#if SUPPORT_WRITE\r
.MkNod = FAT_Mknod,\r
- .Relink = FAT_Relink,\r
+ .Link = FAT_Link,\r
+ .Unlink = FAT_Unlink,\r
#endif\r
.Close = FAT_CloseFile\r
};\r
return MODULE_ERR_OK;\r
}\r
\r
+/**\r
+ * \brief Detect if a file is a FAT device\r
+ */\r
+int FAT_Detect(int FD)\r
+{\r
+ fat_bootsect bs;\r
+ \r
+ if( VFS_ReadAt(FD, 0, 512, &bs) != 512) {\r
+ return 0;\r
+ }\r
+\r
+ if(bs.bps == 0 || bs.spc == 0)\r
+ return 0;\r
+ \r
+ return 1;\r
+}\r
/**\r
* \brief Reads the boot sector of a disk and prepares the structures for it\r
*/\r
Uint32 FATSz, RootDirSectors, TotSec;\r
tVFS_Node *node = NULL;\r
tFAT_VolInfo *diskInfo = &gFAT_Disks[giFAT_PartCount];\r
+\r
+ memset(diskInfo, 0, sizeof(*diskInfo));\r
\r
// Temporary Pointer\r
bs = &diskInfo->bootsect;\r
VFS_ReadAt(diskInfo->fileHandle, 0, 512, bs);\r
\r
if(bs->bps == 0 || bs->spc == 0) {\r
- Log_Notice("FAT", "Error in FAT Boot Sector");\r
+ Log_Notice("FAT", "Error in FAT Boot Sector (zero BPS/SPC)");\r
+ VFS_Close(diskInfo->fileHandle);\r
return NULL;\r
}\r
\r
\r
diskInfo->ClusterCount = (TotSec - (bs->resvSectCount + (bs->fatCount * FATSz) + RootDirSectors)) / bs->spc;\r
\r
- if(diskInfo->ClusterCount < 4085)\r
+ if(diskInfo->ClusterCount < FAT16_MIN_SECTORS)\r
diskInfo->type = FAT12;\r
- else if(diskInfo->ClusterCount < 65525)\r
+ else if(diskInfo->ClusterCount < FAT32_MIN_CLUSTERS)\r
diskInfo->type = FAT16;\r
else\r
diskInfo->type = FAT32;\r
diskInfo->FATCache = (Uint32*)malloc(sizeof(Uint32)*diskInfo->ClusterCount);\r
if(diskInfo->FATCache == NULL) {\r
Log_Warning("FAT", "Heap Exhausted");\r
+ VFS_Cose(diskInfo->fileHandle);\r
return NULL;\r
}\r
Ofs = bs->resvSectCount*512;\r
\r
diskInfo->BytesPerCluster = bs->spc * bs->bps;\r
\r
- // Initalise inode cache for filesystem\r
- diskInfo->inodeHandle = Inode_GetHandle();\r
- LOG("Inode Cache handle is %i", diskInfo->inodeHandle);\r
- \r
// == VFS Interface\r
node = &diskInfo->rootNode;\r
//node->Size = bs->files_in_root;\r
// Close Disk Handle\r
VFS_Close( disk->fileHandle );\r
// Clear Node Cache\r
- Inode_ClearCache(disk->inodeHandle);\r
+ FAT_int_ClearNodeCache(disk);\r
// Mark as unused\r
disk->fileHandle = -2;\r
return;\r
*/\r
int FAT_int_GetAddress(tVFS_Node *Node, Uint64 Offset, Uint64 *Addr, Uint32 *Cluster)\r
{\r
- Uint32 cluster;\r
+ Uint32 cluster, base_cluster;\r
Uint64 addr;\r
int skip;\r
tFAT_VolInfo *disk = Node->ImplPtr;\r
\r
ENTER("pNode XOffset", Node, Offset);\r
\r
- cluster = Node->Inode & 0xFFFFFFF; // Cluster ID\r
- LOG("cluster = 0x%07x", cluster);\r
+ cluster = base_cluster = Node->Inode & 0xFFFFFFF; // Cluster ID\r
+// LOG("base cluster = 0x%07x", cluster);\r
\r
// Do Cluster Skip\r
// - Pre FAT32 had a reserved area for the root.\r
if(Cluster) *Cluster = cluster;\r
cluster = FAT_int_GetFatValue(disk, cluster);\r
// Check for end of cluster chain\r
- if(cluster == 0xFFFFFFFF) { LEAVE('i', 1); return 1;}\r
+ if(cluster == GETFATVALUE_EOC) { LEAVE('i', 1); return 1; }\r
}\r
if(Cluster) *Cluster = cluster;\r
}\r
else {\r
+ // TODO: Bounds checking on root\r
+// LOG("Root cluster count %i", disk->bootsect.files_in_root*32/disk->BytesPerCluster);\r
// Increment by clusters in offset\r
cluster += Offset / disk->BytesPerCluster;\r
}\r
\r
- LOG("cluster = %08x", cluster);\r
+// LOG("cluster = 0x%07x", cluster);\r
\r
// Bounds Checking (Used to spot corruption)\r
if(cluster > disk->ClusterCount + 2)\r
\r
// Compute Offsets\r
// - Pre FAT32 cluster base (in sectors)\r
- if( cluster == disk->rootOffset && disk->type != FAT32 ) {\r
+ if( base_cluster == disk->rootOffset && disk->type != FAT32 ) {\r
addr = disk->bootsect.resvSectCount * disk->bootsect.bps;\r
addr += cluster * disk->BytesPerCluster;\r
}\r
return 0;\r
}\r
\r
-/*\r
- * ====================\r
- * FAT Manipulation\r
- * ====================\r
- */\r
-/**\r
- * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
- * \brief Fetches a value from the FAT\r
- */\r
-Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)\r
-{\r
- Uint32 val = 0;\r
- Uint32 ofs;\r
- ENTER("pDisk xCluster", Disk, cluster);\r
- Mutex_Acquire( &Disk->lFAT );\r
- #if CACHE_FAT\r
- if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
- {\r
- val = Disk->FATCache[cluster];\r
- if(Disk->type == FAT12 && val == EOC_FAT12) val = -1;\r
- if(Disk->type == FAT16 && val == EOC_FAT16) val = -1;\r
- if(Disk->type == FAT32 && val == EOC_FAT32) val = -1;\r
- }\r
- else\r
- {\r
- #endif\r
- ofs = Disk->bootsect.resvSectCount*512;\r
- if(Disk->type == FAT12) {\r
- VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);\r
- val = (cluster & 1 ? val>>12 : val & 0xFFF);\r
- if(val == EOC_FAT12) val = -1;\r
- } else if(Disk->type == FAT16) {\r
- VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);\r
- if(val == EOC_FAT16) val = -1;\r
- } else {\r
- VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);\r
- if(val == EOC_FAT32) val = -1;\r
- }\r
- #if CACHE_FAT\r
- }\r
- #endif /*CACHE_FAT*/\r
- Mutex_Release( &Disk->lFAT );\r
- LEAVE('x', val);\r
- return val;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Allocate a new cluster\r
- */\r
-Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)\r
-{\r
- Uint32 ret = Previous;\r
- #if CACHE_FAT\r
- if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
- {\r
- Uint32 eoc;\r
- \r
- LOCK(Disk->lFAT);\r
- for(ret = Previous; ret < Disk->ClusterCount; ret++)\r
- {\r
- if(Disk->FATCache[ret] == 0)\r
- goto append;\r
- }\r
- for(ret = 0; ret < Previous; ret++)\r
- {\r
- if(Disk->FATCache[ret] == 0)\r
- goto append;\r
- }\r
- \r
- RELEASE(Disk->lFAT);\r
- return 0;\r
- \r
- append:\r
- switch(Disk->type)\r
- {\r
- case FAT12: eoc = EOC_FAT12; break;\r
- case FAT16: eoc = EOC_FAT16; break;\r
- case FAT32: eoc = EOC_FAT32; break;\r
- default: return 0;\r
- }\r
- \r
- Disk->FATCache[ret] = eoc;\r
- Disk->FATCache[Previous] = ret;\r
- \r
- RELEASE(Disk->lFAT);\r
- return ret;\r
- }\r
- else\r
- {\r
- #endif\r
- Uint32 val;\r
- Uint32 ofs = Disk->bootsect.resvSectCount*512;\r
- Log_Warning("FAT", "TODO: Implement cluster allocation with non cached FAT");\r
- return 0;\r
- \r
- switch(Disk->type)\r
- {\r
- case FAT12:\r
- VFS_ReadAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
- if( Previous & 1 ) {\r
- val &= 0xFFF000;\r
- val |= ret;\r
- }\r
- else {\r
- val &= 0xFFF;\r
- val |= ret<<12;\r
- }\r
- VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
- \r
- VFS_ReadAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
- if( Cluster & 1 ) {\r
- val &= 0xFFF000;\r
- val |= eoc;\r
- }\r
- else {\r
- val &= 0x000FFF;\r
- val |= eoc<<12;\r
- }\r
- VFS_WriteAt(Disk->fileHandle, ofs+(ret>>1)*3, 3, &val);\r
- break;\r
- case FAT16:\r
- VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
- VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);\r
- break;\r
- case FAT32:\r
- VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
- VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);\r
- break;\r
- }\r
- return ret;\r
- #if CACHE_FAT\r
- }\r
- #endif\r
-}\r
-\r
-/**\r
- * \brief Free's a cluster\r
- * \return The original contents of the cluster\r
- */\r
-Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)\r
-{\r
- Uint32 ret;\r
- #if CACHE_FAT\r
- if( Disk->ClusterCount <= giFAT_MaxCachedClusters )\r
- {\r
- LOCK(Disk->lFAT);\r
- \r
- ret = Disk->FATCache[Cluster];\r
- Disk->FATCache[Cluster] = 0;\r
- \r
- RELEASE(Disk->lFAT);\r
- }\r
- else\r
- {\r
- #endif\r
- Uint32 val;\r
- Uint32 ofs = Disk->bootsect.resvSectCount*512;\r
- LOCK(Disk->lFAT);\r
- switch(Disk->type)\r
- {\r
- case FAT12:\r
- VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);\r
- if( Cluster & 1 ) {\r
- ret = val & 0xFFF0000;\r
- val &= 0xFFF;\r
- }\r
- else {\r
- ret = val & 0xFFF;\r
- val &= 0xFFF000;\r
- }\r
- VFS_WriteAt(Disk->fileHandle, ofs+(Previous>>1)*3, 3, &val);\r
- break;\r
- case FAT16:\r
- VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);\r
- val = 0;\r
- VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
- break;\r
- case FAT32:\r
- VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);\r
- val = 0;\r
- VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);\r
- break;\r
- }\r
- RELEASE(Disk->lFAT);\r
- #if CACHE_FAT\r
- }\r
- #endif\r
- if(Disk->type == FAT12 && ret == EOC_FAT12) ret = -1;\r
- if(Disk->type == FAT16 && ret == EOC_FAT16) ret = -1;\r
- if(Disk->type == FAT32 && ret == EOC_FAT32) ret = -1;\r
- return ret;\r
-}\r
-#endif\r
-\r
-/*\r
- * ====================\r
- * Cluster IO\r
- * ====================\r
- */\r
-/**\r
- * \brief Read a cluster\r
- * \param Disk Disk (Volume) to read from\r
- * \param Length Length to read\r
- * \param Buffer Destination for read data\r
- */\r
-void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)\r
-{\r
- ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);\r
- VFS_ReadAt(\r
- Disk->fileHandle,\r
- (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
- * Disk->bootsect.bps,\r
- Length,\r
- Buffer\r
- );\r
- LEAVE('-');\r
-}\r
-\r
/* ====================\r
* File IO\r
* ====================\r
for(i = preSkip; i--; )\r
{\r
cluster = FAT_int_GetFatValue(disk, cluster);\r
- if(cluster == -1) {\r
+ if(cluster == GETFATVALUE_EOC) {\r
Log_Warning("FAT", "Offset is past end of cluster chain mark");\r
LEAVE('i', 0);\r
return 0;\r
LOG("pos = %i, Reading the rest of the clusters");\r
// Get next cluster in the chain\r
cluster = FAT_int_GetFatValue(disk, cluster);\r
- if(cluster == -1) {\r
+ if(cluster == GETFATVALUE_EOC) {\r
Log_Warning("FAT", "Read past End of Cluster Chain (Align)");\r
LEAVE('X', pos);\r
return pos;\r
// Read the rest of the cluster data\r
for( ; count; count -- )\r
{\r
- if(cluster == -1) {\r
+ if(cluster == GETFATVALUE_EOC) {\r
Log_Warning("FAT", "Read past End of Cluster Chain (Bulk)");\r
LEAVE('X', pos);\r
return pos;\r
}\r
\r
#if SUPPORT_WRITE\r
-/**\r
- * \brief Write a cluster to disk\r
- */\r
-void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, void *Buffer)\r
-{\r
- ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);\r
- VFS_ReadAt(\r
- Disk->fileHandle,\r
- (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )\r
- * Disk->bootsect.bps,\r
- Disk->BytesPerCluster,\r
- Buffer\r
- );\r
- LEAVE('-');\r
-}\r
-\r
/**\r
* \brief Write to a file\r
* \param Node File Node\r
* \param Length Size of data to write\r
* \param Buffer Data source\r
*/\r
-size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)\r
+size_t FAT_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)\r
{\r
tFAT_VolInfo *disk = Node->ImplPtr;\r
char tmpBuf[disk->BytesPerCluster];\r
int remLength = Length;\r
Uint32 cluster, tmpCluster;\r
int bNewCluster = 0;\r
+ off_t original_offset = Offset;\r
\r
if(Offset > Node->Size) return 0;\r
\r
+ ENTER("pNode Xoffset xlength pbuffer", Node, Offset, Length, Buffer);\r
+ \r
// Seek Clusters\r
cluster = Node->Inode & 0xFFFFFFFF;\r
while( Offset > disk->BytesPerCluster )\r
{\r
cluster = FAT_int_GetFatValue( disk, cluster );\r
- if(cluster == -1) {\r
+ if(cluster == GETFATVALUE_EOC) {\r
Log_Warning("FAT", "EOC Unexpectedly Reached");\r
+ LEAVE('i', 0);\r
return 0;\r
}\r
Offset -= disk->BytesPerCluster;\r
if( Offset == disk->BytesPerCluster )\r
{\r
Uint32 tmp = FAT_int_AllocateCluster(disk, cluster);\r
- if(!tmp) return 0;\r
+ if(!tmp) {\r
+ LEAVE('i', 0);\r
+ return 0;\r
+ }\r
cluster = tmp;\r
Offset -= disk->BytesPerCluster;\r
}\r
{\r
char tmpBuf[disk->BytesPerCluster];\r
\r
+ LOG("Read-Modify-Write single");\r
+ \r
// Read-Modify-Write\r
FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
memcpy( tmpBuf + Offset, Buffer, Length );\r
FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
- \r
- return Length;\r
+ goto return_full;\r
}\r
\r
// Clean up changes within a cluster\r
if( Offset )\r
{ \r
+ LOG("Read-Modify-Write first");\r
+\r
// Read-Modify-Write\r
FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
memcpy( tmpBuf + Offset, Buffer, disk->BytesPerCluster - Offset );\r
\r
// Get next cluster (allocating if needed)\r
tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
- if(tmpCluster == -1) {\r
+ if(tmpCluster == GETFATVALUE_EOC) {\r
tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
- if( tmpCluster == 0 ) {\r
- return Length - remLength;\r
- }\r
+ if( tmpCluster == 0 )\r
+ goto ret_incomplete;\r
}\r
cluster = tmpCluster;\r
}\r
{\r
FAT_int_WriteCluster( disk, cluster, Buffer );\r
Buffer += disk->BytesPerCluster;\r
+ remLength -= disk->BytesPerCluster;\r
\r
// Get next cluster (allocating if needed)\r
tmpCluster = FAT_int_GetFatValue(disk, cluster);\r
- if(tmpCluster == -1) {\r
+ if(tmpCluster == GETFATVALUE_EOC) {\r
bNewCluster = 1;\r
tmpCluster = FAT_int_AllocateCluster(disk, cluster);\r
- if( tmpCluster == 0 ) {\r
- return Length - remLength;\r
- }\r
+ if( tmpCluster == 0 )\r
+ goto ret_incomplete;\r
}\r
cluster = tmpCluster;\r
}\r
\r
// Finish off\r
- tmpBuf = malloc( disk->BytesPerCluster );\r
- if( bNewCluster )\r
- memset(tmpBuf, 0, disk->BytesPerCluster);\r
- else\r
- FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
- memcpy( tmpBuf, Buffer, remLength );\r
- FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
- free( tmpBuf );\r
- \r
- return Length;\r
-}\r
-#endif\r
-\r
-/* ====================\r
- * File Names & Nodes\r
- * ====================\r
- */\r
-/**\r
- * \brief Converts a FAT directory entry name into a proper filename\r
- * \param dest Destination array (must be at least 13 bytes in size)\r
- * \param src 8.3 filename (concatenated, e.g 'FILE1 TXT')\r
- */\r
-void FAT_int_ProperFilename(char *dest, const char *src)\r
-{\r
- int inpos, outpos;\r
- \r
- // Name\r
- outpos = 0;\r
- for( inpos = 0; inpos < 8; inpos++ ) {\r
- if(src[inpos] == ' ') break;\r
- dest[outpos++] = src[inpos];\r
- }\r
- inpos = 8;\r
- // Check for empty extensions\r
- if(src[8] != ' ')\r
- {\r
- dest[outpos++] = '.';\r
- for( ; inpos < 11; inpos++) {\r
- if(src[inpos] == ' ') break;\r
- dest[outpos++] = src[inpos];\r
- }\r
- }\r
- dest[outpos++] = '\0';\r
- \r
- //LOG("dest='%s'", dest);\r
-}\r
-\r
-/**\r
- * \fn char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
- * \brief Converts either a LFN or a 8.3 Name into a proper name\r
- * \param ft Pointer to the file's entry in the parent directory\r
- * \param LongFileName Long file name pointer\r
- * \return Filename as a heap string\r
- */\r
-char *FAT_int_CreateName(fat_filetable *ft, char *LongFileName)\r
-{\r
- char *ret;\r
- ENTER("pft sLongFileName", ft, LongFileName);\r
- //Log_Debug("FAT", "FAT_int_CreateName(ft=%p, LongFileName=%p'%s')", ft, LongFileName);\r
- #if USE_LFN\r
- if(LongFileName && LongFileName[0] != '\0')\r
- { \r
- ret = strdup(LongFileName);\r
- }\r
- else\r
- {\r
- #endif\r
- ret = (char*) malloc(13);\r
- if( !ret ) {\r
- Log_Warning("FAT", "FAT_int_CreateName: malloc(13) failed");\r
- return NULL;\r
- }\r
- FAT_int_ProperFilename(ret, ft->name);\r
- #if USE_LFN\r
- }\r
- #endif\r
- LEAVE('s', ret);\r
- return ret;\r
-}\r
-\r
-/**\r
- * \brief Creates a tVFS_Node structure for a given file entry\r
- * \param Parent Parent directory VFS node\r
- * \param Entry File table entry for the new node\r
- * \param Pos Position in the parent of the new node\r
- */\r
-tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry, int Pos)\r
-{\r
- tVFS_Node node;\r
- tVFS_Node *ret;\r
- tFAT_VolInfo *disk = Parent->ImplPtr;\r
- \r
- ENTER("pParent pFT", Parent, Entry);\r
- LOG("disk = %p", disk);\r
- \r
- memset(&node, 0, sizeof(tVFS_Node));\r
- \r
- // Set Other Data\r
- // 0-27: Cluster, 32-59: Parent Cluster\r
- node.Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);\r
- LOG("node.Inode = %llx", node.Inode);\r
- // Position in parent directory\r
- node.ImplInt = Pos & 0xFFFF;\r
- // Disk Pointer\r
- node.ImplPtr = disk;\r
- node.Size = Entry->size;\r
- LOG("Entry->size = %i", Entry->size);\r
- // root:root\r
- node.UID = 0; node.GID = 0;\r
- node.NumACLs = 1;\r
- \r
- node.Flags = 0;\r
- if(Entry->attrib & ATTR_DIRECTORY) node.Flags |= VFS_FFLAG_DIRECTORY;\r
- if(Entry->attrib & ATTR_READONLY) {\r
- node.Flags |= VFS_FFLAG_READONLY;\r
- node.ACLs = &gVFS_ACL_EveryoneRX; // R-XR-XR-X\r
- }\r
- else {\r
- node.ACLs = &gVFS_ACL_EveryoneRWX; // RWXRWXRWX\r
- }\r
- \r
- // Create timestamps\r
- node.ATime = timestamp(0,0,0,\r
- ((Entry->adate&0x1F) - 1), // Days\r
- ((Entry->adate&0x1E0) - 1), // Months\r
- 1980+((Entry->adate&0xFF00)>>8) // Years\r
- );\r
- \r
- node.CTime = Entry->ctimems * 10; // Miliseconds\r
- node.CTime += timestamp(\r
- ((Entry->ctime&0x1F)<<1), // Seconds\r
- ((Entry->ctime&0x3F0)>>5), // Minutes\r
- ((Entry->ctime&0xF800)>>11), // Hours\r
- ((Entry->cdate&0x1F)-1), // Days\r
- ((Entry->cdate&0x1E0)-1), // Months\r
- 1980+((Entry->cdate&0xFF00)>>8) // Years\r
- );\r
- \r
- node.MTime = timestamp(\r
- ((Entry->mtime&0x1F)<<1), // Seconds\r
- ((Entry->mtime&0x3F0)>>5), // Minutes\r
- ((Entry->mtime&0xF800)>>11), // Hours\r
- ((Entry->mdate&0x1F)-1), // Days\r
- ((Entry->mdate&0x1E0)-1), // Months\r
- 1980+((Entry->mdate&0xFF00)>>8) // Years\r
- );\r
- \r
- // Set pointers\r
- if(node.Flags & VFS_FFLAG_DIRECTORY) {\r
- //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);\r
- node.Type = &gFAT_DirType; \r
- node.Size = -1;\r
- }\r
- else {\r
- node.Type = &gFAT_FileType;\r
- }\r
- \r
- ret = Inode_CacheNode(disk->inodeHandle, &node);\r
- LEAVE('p', ret);\r
- return ret;\r
-}\r
-\r
-/* \r
- * ====================\r
- * Directory IO\r
- * ====================\r
- */\r
-\r
-/**\r
- * \brief Reads a sector from the disk\r
- * \param Node Directory node to read\r
- * \param Sector Sector number in the directory to read\r
- * \param Buffer Destination buffer for the read data\r
- */\r
-int FAT_int_ReadDirSector(tVFS_Node *Node, int Sector, fat_filetable *Buffer)\r
-{\r
- Uint64 addr;\r
- tFAT_VolInfo *disk = Node->ImplPtr;\r
- \r
- ENTER("pNode iSector pEntry", Node, Sector, Buffer);\r
- \r
- // Parse address\r
- if(FAT_int_GetAddress(Node, Sector * 512, &addr, NULL))\r
- {\r
- LEAVE('i', 1);\r
- return 1;\r
- }\r
- \r
- LOG("addr = 0x%llx", addr);\r
- // Read Sector\r
- if(VFS_ReadAt(disk->fileHandle, addr, 512, Buffer) != 512)\r
- {\r
- LEAVE('i', 1);\r
- return 1;\r
- }\r
- \r
- LEAVE('i', 0);\r
- return 0;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \brief Writes an entry to the disk\r
- * \todo Support expanding a directory\r
- * \param Node Directory node\r
- * \param ID ID of entry to update\r
- * \param Entry Entry data\r
- * \return Zero on success, non-zero on error\r
- */\r
-int FAT_int_WriteDirEntry(tVFS_Node *Node, int ID, fat_filetable *Entry)\r
-{\r
- Uint64 addr = 0;\r
- int tmp;\r
- Uint32 cluster = 0;\r
- tFAT_VolInfo *disk = Node->ImplPtr;\r
- \r
- ENTER("pNode iID pEntry", Node, ID, Entry);\r
- \r
- tmp = FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
- if( tmp )\r
- {\r
- //TODO: Allocate a cluster\r
- cluster = FAT_int_AllocateCluster(Node->ImplPtr, cluster);\r
- if(cluster == -1) {\r
- Log_Warning("FAT", "Unable to allocate an other cluster for %p", Node);\r
- LEAVE('i', 1);\r
- return 1;\r
- }\r
- FAT_int_GetAddress(Node, ID * sizeof(fat_filetable), &addr, &cluster);\r
- }\r
- \r
-\r
- LOG("addr = 0x%llx", addr);\r
- \r
- // Read Sector\r
- VFS_WriteAt(disk->fileHandle, addr, sizeof(fat_filetable), Entry); // Read Dir Data\r
- \r
- LEAVE('i', 0);\r
- return 0;\r
-}\r
-#endif\r
-\r
-#if USE_LFN \r
-/**\r
- * \fn char *FAT_int_GetLFN(tVFS_Node *node)\r
- * \brief Return pointer to LFN cache entry\r
- * \param Node Directory node\r
- * \param ID ID of the short name\r
- * \return Pointer to the LFN cache entry\r
- */\r
-char *FAT_int_GetLFN(tVFS_Node *Node, int ID)\r
-{\r
- tFAT_LFNCache *cache;\r
- int i, firstFree;\r
- \r
- Mutex_Acquire( &Node->Lock );\r
- \r
- // TODO: Thread Safety (Lock things)\r
- cache = Node->Data;\r
- \r
- // Create a cache if it isn't there\r
- if(!cache) {\r
- cache = Node->Data = malloc( sizeof(tFAT_LFNCache) + sizeof(tFAT_LFNCacheEnt) );\r
- cache->NumEntries = 1;\r
- cache->Entries[0].ID = ID;\r
- cache->Entries[0].Data[0] = '\0';\r
- Mutex_Release( &Node->Lock );\r
- //Log_Debug("FAT", "Return = %p (new)", cache->Entries[0].Data);\r
- return cache->Entries[0].Data;\r
- }\r
- \r
- // Scan for this entry\r
- firstFree = -1;\r
- for( i = 0; i < cache->NumEntries; i++ )\r
- {\r
- if( cache->Entries[i].ID == ID ) {\r
- Mutex_Release( &Node->Lock );\r
- //Log_Debug("FAT", "Return = %p (match)", cache->Entries[i].Data);\r
- return cache->Entries[i].Data;\r
- }\r
- if( cache->Entries[i].ID == -1 && firstFree == -1 )\r
- firstFree = i;\r
- }\r
- \r
- if(firstFree == -1) {\r
- // Use `i` for temp length\r
- i = sizeof(tFAT_LFNCache) + (cache->NumEntries+1)*sizeof(tFAT_LFNCacheEnt);\r
- Node->Data = realloc( Node->Data, i );\r
- if( !Node->Data ) {\r
- Log_Error("FAT", "realloc() fail, unable to allocate %i for LFN cache", i);\r
- Mutex_Release( &Node->Lock );\r
- return NULL;\r
- }\r
- //Log_Debug("FAT", "Realloc (%i)\n", i);\r
- cache = Node->Data;\r
- i = cache->NumEntries;\r
- cache->NumEntries ++;\r
- }\r
- else {\r
- i = firstFree;\r
- }\r
- \r
- // Create new entry\r
- cache->Entries[ i ].ID = ID;\r
- cache->Entries[ i ].Data[0] = '\0';\r
- \r
- Mutex_Release( &Node->Lock );\r
- //Log_Debug("FAT", "Return = %p (firstFree, i = %i)", cache->Entries[i].Data, i);\r
- return cache->Entries[ i ].Data;\r
-}\r
-\r
-/**\r
- * \fn void FAT_int_DelLFN(tVFS_Node *node)\r
- * \brief Delete a LFN cache entry\r
- * \param Node Directory node\r
- * \param ID File Entry ID\r
- */\r
-void FAT_int_DelLFN(tVFS_Node *Node, int ID)\r
-{\r
- tFAT_LFNCache *cache = Node->Data;\r
- int i;\r
- \r
- // Fast return\r
- if(!cache) return;\r
- \r
- // Scan for a current entry\r
- for( i = 0; i < cache->NumEntries; i++ )\r
- {\r
- if( cache->Entries[i].ID == ID )\r
- cache->Entries[i].ID = -1;\r
- }\r
- return ;\r
-}\r
-#endif\r
-\r
-/**\r
- * \fn char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
- * \param Node Node structure of directory\r
- * \param ID Directory position\r
- * \return Filename as a heap string, NULL or VFS_SKIP\r
- */\r
-char *FAT_ReadDir(tVFS_Node *Node, int ID)\r
-{\r
- fat_filetable fileinfo[16]; // sizeof(fat_filetable)=32, so 16 per sector\r
- int a = 0;\r
- char *ret;\r
- #if USE_LFN\r
- char *lfn = NULL;\r
- #endif\r
- \r
- ENTER("pNode iID", Node, ID);\r
- \r
- if(FAT_int_ReadDirSector(Node, ID/16, fileinfo))\r
- {\r
- LOG("End of chain, end of dir");\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- // Offset in sector\r
- a = ID % 16;\r
-\r
- LOG("fileinfo[%i].name[0] = 0x%x", a, (Uint8)fileinfo[a].name[0]);\r
- \r
- // Check if this is the last entry\r
- if( fileinfo[a].name[0] == '\0' ) {\r
- Node->Size = ID;\r
- LOG("End of list");\r
- LEAVE('n');\r
- return NULL; // break\r
- }\r
- \r
- // Check for empty entry\r
- if( (Uint8)fileinfo[a].name[0] == 0xE5 ) {\r
- LOG("Empty Entry");\r
- #if 0 // Stop on empty entry?\r
- LEAVE('n');\r
- return NULL; // Stop\r
- #else\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP; // Skip\r
- #endif\r
- }\r
- \r
- #if USE_LFN\r
- // Get Long File Name Cache\r
- if(fileinfo[a].attrib == ATTR_LFN)\r
+ if( remLength )\r
{\r
- fat_longfilename *lfnInfo;\r
- \r
- lfnInfo = (fat_longfilename *) &fileinfo[a];\r
- \r
- // Get cache for corresponding file\r
- // > ID + Index gets the corresponding short node\r
- lfn = FAT_int_GetLFN( Node, ID + (lfnInfo->id & 0x3F) );\r
- \r
- // Bit 6 indicates the start of an entry\r
- if(lfnInfo->id & 0x40) memset(lfn, 0, 256);\r
- \r
- a = ((lfnInfo->id & 0x3F) - 1) * 13;\r
- //Log_Debug("FAT", "ID = 0x%02x, a = %i", lfnInfo->id, a);\r
- \r
- // Sanity Check (FAT implementations should not allow >255 character names)\r
- if(a > 255) return VFS_SKIP;\r
- \r
- // Append new bytes\r
- lfn[a+ 0] = lfnInfo->name1[0]; lfn[a+ 1] = lfnInfo->name1[1];\r
- lfn[a+ 2] = lfnInfo->name1[2]; lfn[a+ 3] = lfnInfo->name1[3];\r
- lfn[a+ 4] = lfnInfo->name1[4]; \r
- lfn[a+ 5] = lfnInfo->name2[0]; lfn[a+ 6] = lfnInfo->name2[1];\r
- lfn[a+ 7] = lfnInfo->name2[2]; lfn[a+ 8] = lfnInfo->name2[3];\r
- lfn[a+ 9] = lfnInfo->name2[4]; lfn[a+10] = lfnInfo->name2[5];\r
- lfn[a+11] = lfnInfo->name3[0]; lfn[a+12] = lfnInfo->name3[1];\r
- LOG("lfn = '%s'", lfn);\r
- //Log_Debug("FAT", "lfn = '%s'", lfn);\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP;\r
- }\r
- #endif\r
- \r
- // Check if it is a volume entry\r
- if(fileinfo[a].attrib & 0x08) {\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP;\r
- }\r
- // Ignore .\r
- if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == ' ') {\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP;\r
- }\r
- // and ..\r
- if(fileinfo[a].name[0] == '.' && fileinfo[a].name[1] == '.' && fileinfo[a].name[2] == ' ') {\r
- LEAVE('p', VFS_SKIP);\r
- return VFS_SKIP;\r
- }\r
- \r
- LOG("name='%c%c%c%c%c%c%c%c.%c%c%c'",\r
- fileinfo[a].name[0], fileinfo[a].name[1], fileinfo[a].name[2], fileinfo[a].name[3],\r
- fileinfo[a].name[4], fileinfo[a].name[5], fileinfo[a].name[6], fileinfo[a].name[7],\r
- fileinfo[a].name[8], fileinfo[a].name[9], fileinfo[a].name[10] );\r
- \r
- #if USE_LFN\r
- lfn = FAT_int_GetLFN(Node, ID);\r
- //Log_Debug("FAT", "lfn = %p'%s'", lfn, lfn);\r
- ret = FAT_int_CreateName(&fileinfo[a], lfn);\r
- #else\r
- ret = FAT_int_CreateName(&fileinfo[a], NULL);\r
- #endif\r
- \r
- LEAVE('s', ret);\r
- return ret;\r
-}\r
-\r
-/**\r
- * \fn tVFS_Node *FAT_FindDir(tVFS_Node *node, char *name)\r
- * \brief Finds an entry in the current directory\r
- */\r
-tVFS_Node *FAT_FindDir(tVFS_Node *Node, const char *Name)\r
-{\r
- fat_filetable fileinfo[16];\r
- char tmpName[13];\r
- #if USE_LFN\r
- fat_longfilename *lfnInfo;\r
- char lfn[256];\r
- int lfnPos=255, lfnId = -1;\r
- #endif\r
- int i;\r
- tVFS_Node *tmpNode;\r
- tFAT_VolInfo *disk = Node->ImplPtr;\r
- Uint32 cluster;\r
- \r
- ENTER("pNode sname", Node, Name); \r
-\r
- // Fast Returns\r
- if(!Name || Name[0] == '\0') {\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- \r
- for( i = 0; ; i++ )\r
- {\r
- if((i & 0xF) == 0) {\r
- if(FAT_int_ReadDirSector(Node, i/16, fileinfo))\r
- {\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- }\r
- \r
- //Check if the files are free\r
- if(fileinfo[i&0xF].name[0] == '\0') break; // End of List marker\r
- if(fileinfo[i&0xF].name[0] == '\xE5') continue; // Free entry\r
- \r
- \r
- #if USE_LFN\r
- // Long File Name Entry\r
- if(fileinfo[i & 0xF].attrib == ATTR_LFN)\r
- {\r
- lfnInfo = (fat_longfilename *) &fileinfo[i&0xF];\r
- if(lfnInfo->id & 0x40) {\r
- memset(lfn, 0, 256);\r
- lfnPos = (lfnInfo->id & 0x3F) * 13 - 1;\r
- }\r
- // Sanity check the position so we don't overflow\r
- if( lfnPos < 12 )\r
- continue ;\r
- lfn[lfnPos--] = lfnInfo->name3[1]; lfn[lfnPos--] = lfnInfo->name3[0];\r
- lfn[lfnPos--] = lfnInfo->name2[5]; lfn[lfnPos--] = lfnInfo->name2[4];\r
- lfn[lfnPos--] = lfnInfo->name2[3]; lfn[lfnPos--] = lfnInfo->name2[2];\r
- lfn[lfnPos--] = lfnInfo->name2[1]; lfn[lfnPos--] = lfnInfo->name2[0];\r
- lfn[lfnPos--] = lfnInfo->name1[4]; lfn[lfnPos--] = lfnInfo->name1[3];\r
- lfn[lfnPos--] = lfnInfo->name1[2]; lfn[lfnPos--] = lfnInfo->name1[1];\r
- lfn[lfnPos--] = lfnInfo->name1[0];\r
- if((lfnInfo->id&0x3F) == 1)\r
- {\r
- lfnId = i+1;\r
- }\r
- }\r
+ if( bNewCluster )\r
+ memset(tmpBuf, 0, disk->BytesPerCluster);\r
else\r
- {\r
- // Remove LFN if it does not apply\r
- if(lfnId != i) lfn[0] = '\0';\r
- #else\r
- if(fileinfo[i&0xF].attrib == ATTR_LFN) continue;\r
- #endif\r
- // Get Real Filename\r
- FAT_int_ProperFilename(tmpName, fileinfo[i&0xF].name);\r
- LOG("tmpName = '%s'", tmpName);\r
- \r
- // Only the long name is case sensitive, 8.3 is not\r
- #if USE_LFN\r
- if(strucmp(tmpName, Name) == 0 || strcmp(lfn, Name) == 0)\r
- #else\r
- if(strucmp(tmpName, Name) == 0)\r
- #endif\r
- {\r
- cluster = fileinfo[i&0xF].cluster | (fileinfo[i&0xF].clusterHi << 16);\r
- tmpNode = Inode_GetCache(disk->inodeHandle, cluster);\r
- if(tmpNode == NULL) // Node is not cached\r
- {\r
- tmpNode = FAT_int_CreateNode(Node, &fileinfo[i&0xF], i);\r
- }\r
- LEAVE('p', tmpNode);\r
- return tmpNode;\r
- }\r
- #if USE_LFN\r
- }\r
- #endif\r
+ FAT_int_ReadCluster( disk, cluster, disk->BytesPerCluster, tmpBuf );\r
+ memcpy( tmpBuf, Buffer, remLength );\r
+ FAT_int_WriteCluster( disk, cluster, tmpBuf );\r
}\r
- \r
- LEAVE('n');\r
- return NULL;\r
-}\r
\r
-tVFS_Node *FAT_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode)\r
-{\r
- tFAT_VolInfo *disk = Root->ImplPtr;\r
- int ents_per_sector = 512 / sizeof(fat_filetable); \r
- fat_filetable fileinfo[ents_per_sector];\r
- int sector = 0, i;\r
- tVFS_Node stub_node;\r
-\r
- ENTER("pRoot XInode", Root, Inode);\r
-\r
- stub_node.ImplPtr = disk;\r
- stub_node.Size = -1;\r
- stub_node.Inode = Inode >> 32;\r
-\r
- for( i = 0; ; i ++ )\r
- {\r
- if( i == 0 || i == ents_per_sector )\r
- {\r
- if(FAT_int_ReadDirSector(&stub_node, sector, fileinfo))\r
- {\r
- LOG("ReadDirSector failed");\r
- LEAVE('n');\r
- return NULL;\r
- }\r
- i = 0;\r
- sector ++;\r
- }\r
- \r
- // Check for free/end of list\r
- if(fileinfo[i].name[0] == '\0') break; // End of List marker\r
- if(fileinfo[i].name[0] == '\xE5') continue; // Free entry\r
- \r
- if(fileinfo[i].attrib == ATTR_LFN) continue;\r
-\r
- LOG("fileinfo[i].cluster = %x %04x", fileinfo[i].clusterHi, fileinfo[i].cluster);\r
- #if DEBUG\r
- {\r
- char tmpName[13];\r
- FAT_int_ProperFilename(tmpName, fileinfo[i].name);\r
- LOG("tmpName = '%s'", tmpName);\r
- }\r
- #endif\r
- \r
- \r
- if(fileinfo[i].cluster != (Inode & 0xFFFF)) continue;\r
- if(fileinfo[i].clusterHi != ((Inode >> 16) & 0xFFFF)) continue;\r
-\r
- LEAVE_RET('p', FAT_int_CreateNode(&stub_node, &fileinfo[i], sector*ents_per_sector+i));\r
+return_full:\r
+ if( original_offset + Length > Node->Size ) {\r
+ Node->Size = original_offset + Length;\r
+ LOG("Updated size to %x", Node->Size);\r
+ Node->ImplInt |= FAT_FLAG_DIRTY;\r
}\r
- LOG("sector = %i, i = %i", sector, i);\r
- LEAVE('n');\r
- return NULL;\r
-}\r
-\r
-#if SUPPORT_WRITE\r
-/**\r
- * \fn int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
- * \brief Create a new node\r
- */\r
-int FAT_Mknod(tVFS_Node *Node, char *Name, Uint Flags)\r
-{\r
- return 0;\r
-}\r
\r
-/**\r
- * \fn int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
- * \brief Rename / Delete a file\r
- */\r
-int FAT_Relink(tVFS_Node *Node, char *OldName, char *NewName)\r
-{\r
- tVFS_Node *child;\r
- fat_filetable ft = {0};\r
- int ret;\r
- \r
- child = FAT_FindDir(Node, OldName);\r
- if(!child) return ENOTFOUND;\r
- \r
- // Delete?\r
- if( NewName == NULL )\r
- {\r
- child->ImplInt |= FAT_FLAG_DELETE; // Mark for deletion on close\r
- \r
- // Delete from the directory\r
- ft.name[0] = '\xE9';\r
- FAT_int_WriteDirEntry(Node, child->ImplInt & 0xFFFF, &ft);\r
- \r
- // Return success\r
- ret = EOK;\r
- }\r
- // Rename\r
- else\r
- {\r
- Log_Warning("FAT", "Renaming no yet supported %p ('%s' => '%s')",\r
- Node, OldName, NewName);\r
- ret = ENOTIMPL;\r
- }\r
- \r
- // Close child\r
- child->Close( child );\r
- return ret;\r
+ LEAVE('i', Length);\r
+ return Length;\r
+ret_incomplete:\r
+ LOG("Write incomplete");\r
+ Length -= remLength;\r
+ if( original_offset + Length > Node->Size ) {\r
+ Node->Size = original_offset + Length; \r
+ Node->ImplInt |= FAT_FLAG_DIRTY;\r
+ }\r
+ LEAVE('i', Length);\r
+ return Length;\r
}\r
#endif\r
\r
{\r
tFAT_VolInfo *disk = Node->ImplPtr;\r
if(Node == NULL) return ;\r
- \r
+\r
+ ENTER("pNode", Node); \r
+\r
#if SUPPORT_WRITE\r
// Update the node if it's dirty (don't bother if it's marked for\r
// deletion)\r
if( (Node->ImplInt & FAT_FLAG_DIRTY) && !(Node->ImplInt & FAT_FLAG_DELETE) )\r
{\r
- tFAT_VolInfo buf[16];\r
- tFAT_VolInfo *ft = &buf[ (Node->ImplInt & 0xFFFF) % 16 ];\r
- \r
- FAT_int_ReadDirSector(Node, (Node->ImplInt & 0xFFFF)/16, buf);\r
- ft->size = Node->Size;\r
+ fat_filetable ft;\r
+ tVFS_Node *dirnode;\r
+\r
+ dirnode = FAT_int_CreateIncompleteDirNode(disk, Node->Inode >> 32);\r
+ if( !dirnode ) {\r
+ Log_Error("FAT", "Can't get node for directory cluster #0x%x", Node->Inode>>32);\r
+ LEAVE('-');\r
+ return ;\r
+ }\r
+\r
+ int id = FAT_int_GetEntryByCluster(dirnode, Node->Inode & 0xFFFFFFFF, &ft);\r
+ ft.size = Node->Size;\r
// TODO: update adate, mtime, mdate\r
- FAT_int_WriteDirEntry(Node, Node->ImplInt & 0xFFFF, ft);\r
+ FAT_int_WriteDirEntry(dirnode, id, &ft);\r
+ \r
+ dirnode->Type->Close(dirnode);\r
\r
Node->ImplInt &= ~FAT_FLAG_DIRTY;\r
}\r
#endif\r
+\r
+ Uint32 cluster = Node->Inode;\r
+ Uint32 implint = Node->ImplInt;\r
\r
- // TODO: Make this more thread safe somehow, probably by moving the\r
- // Inode_UncacheNode higher up and saving the cluster value somewhere\r
- if( Node->ReferenceCount == 1 )\r
- { \r
- #if SUPPORT_WRITE\r
+ #if SUPPORT_WRITE\r
+ if( FAT_int_DerefNode(Node) == 1 )\r
+ {\r
+ LOG("implint = %x", implint);\r
// Delete File\r
- if( Node->ImplInt & FAT_FLAG_DELETE ) {\r
+ if( implint & FAT_FLAG_DELETE ) {\r
+ Log_Debug("FAT", "Deallocating chain stating at 0x%07x", cluster);\r
// Since the node is marked, we only need to remove it's data\r
- Uint32 cluster = Node->Inode & 0xFFFFFFFF;\r
while( cluster != -1 )\r
- cluster = FAT_int_FreeCluster(Node->ImplPtr, cluster);\r
+ cluster = FAT_int_FreeCluster(disk, cluster);\r
}\r
- #endif\r
}\r
- \r
- Inode_UncacheNode(disk->inodeHandle, Node->Inode);\r
- return ;\r
+ #endif\r
+ LEAVE('-');\r
}\r
--- /dev/null
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * fatio.c
+ * - FAT Manipulation and Cluster IO
+ */
+#define DEBUG 0
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === CODE ===
+/**
+ * \fn Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
+ * \brief Fetches a value from the FAT
+ */
+Uint32 FAT_int_GetFatValue(tFAT_VolInfo *Disk, Uint32 cluster)
+{
+ Uint32 val = 0;
+ Uint32 ofs;
+ ENTER("pDisk xCluster", Disk, cluster);
+
+ Mutex_Acquire( &Disk->lFAT );
+ #if CACHE_FAT
+ if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+ {
+ val = Disk->FATCache[cluster];
+ if(Disk->type == FAT12 && val == EOC_FAT12) val = GETFATVALUE_EOC;
+ if(Disk->type == FAT16 && val == EOC_FAT16) val = GETFATVALUE_EOC;
+ if(Disk->type == FAT32 && val == EOC_FAT32) val = GETFATVALUE_EOC;
+ }
+ else
+ {
+ #endif
+ ofs = Disk->bootsect.resvSectCount*512;
+ if(Disk->type == FAT12) {
+ VFS_ReadAt(Disk->fileHandle, ofs+(cluster/2)*3, 3, &val);
+ LOG("3 bytes at 0x%x are (Uint32)0x%x", ofs+(cluster/2)*3, val);
+ val = (cluster & 1) ? (val>>12) : (val & 0xFFF);
+ if(val == EOC_FAT12) val = GETFATVALUE_EOC;
+ } else if(Disk->type == FAT16) {
+ VFS_ReadAt(Disk->fileHandle, ofs+cluster*2, 2, &val);
+ if(val == EOC_FAT16) val = GETFATVALUE_EOC;
+ } else {
+ VFS_ReadAt(Disk->fileHandle, ofs+cluster*4, 4, &val);
+ if(val == EOC_FAT32) val = GETFATVALUE_EOC;
+ }
+ #if CACHE_FAT
+ }
+ #endif /*CACHE_FAT*/
+ Mutex_Release( &Disk->lFAT );
+ LEAVE('x', val);
+ return val;
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Allocate a new cluster
+ */
+Uint32 FAT_int_AllocateCluster(tFAT_VolInfo *Disk, Uint32 Previous)
+{
+ Uint32 ret = -1;
+
+ #if CACHE_FAT
+ if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+ {
+ int bFoundCluster = 0;
+ Uint32 eoc;
+
+ switch(Disk->type)
+ {
+ case FAT12: eoc = EOC_FAT12; break;
+ case FAT16: eoc = EOC_FAT16; break;
+ case FAT32: eoc = EOC_FAT32; break;
+ default: return 0;
+ }
+
+ Mutex_Acquire(&Disk->lFAT);
+ if( Previous != -1 )
+ {
+ for(ret = Previous; ret < Disk->ClusterCount; ret++)
+ {
+ if(Disk->FATCache[ret] != 0) {
+ bFoundCluster = 1;
+ break;
+ }
+ }
+ }
+ if( !bFoundCluster )
+ {
+ for(ret = 0; ret < Previous; ret++)
+ {
+ if(Disk->FATCache[ret] == 0) {
+ bFoundCluster = 1;
+ break;
+ }
+ }
+ }
+
+ if(bFoundCluster)
+ {
+ Disk->FATCache[ret] = eoc;
+ if( Previous != -1 )
+ Disk->FATCache[Previous] = ret;
+ }
+ else
+ {
+ ret = 0;
+ }
+
+ Mutex_Release(&Disk->lFAT);
+ LOG("Allocated cluster %x", ret);
+ return ret;
+ }
+ else
+ {
+ #endif
+ Uint32 val = 0;
+ Uint32 base = Disk->bootsect.resvSectCount*512;
+ int block = 0, block_ofs = 0;
+ int first_block;
+ const int block_size = 512*3;
+ const int ents_per_block_12 = block_size * 2 / 3; // 1.5 bytes per entry
+// const int ents_per_block_16 = block_size / 2; // 2 bytes per entry
+// const int ents_per_block_32 = block_size / 4; // 4 bytes per entry
+ int block_count_12 = DivUp(Disk->ClusterCount, ents_per_block_12);
+ Uint8 sector_data[block_size+1];
+ sector_data[block_size] = 0;
+
+ Mutex_Acquire(&Disk->lFAT);
+ switch(Disk->type)
+ {
+ case FAT12:
+ if( Previous != -1 )
+ block = Previous / ents_per_block_12;
+ else
+ block = 0;
+ first_block = block;
+
+ // Search within the same block as the previous cluster first
+ do {
+ VFS_ReadAt(Disk->fileHandle, base + block*block_size, block_size, sector_data);
+ for( block_ofs = 0; block_ofs < ents_per_block_12; block_ofs ++ )
+ {
+ Uint32 *valptr = (void*)( sector_data + block_ofs / 2 * 3 );
+ int bitofs = 12 * (block_ofs % 2);
+// LOG("%i:%i - FAT Ent 0x%03x", block, block_ofs, (*valptr>>bitofs) & 0xFFF);
+ if( ((*valptr >> bitofs) & 0xFFF) == 0 ) {
+ // Found a free cluster
+ *valptr |= EOC_FAT12 << bitofs;
+ ret = block * ents_per_block_12 + block_ofs;
+ break;
+ }
+ }
+ // Check for early break from the above loop
+ if( block_ofs != ents_per_block_12 )
+ break;
+
+ // Next block please
+ block ++;
+ if( block == block_count_12 )
+ block = 0;
+ } while( block != first_block );
+
+ if( ret != 0 ) // TODO: Could cluster 0 be valid?
+ {
+ // Write back changes to this part of the FAT
+ VFS_WriteAt(Disk->fileHandle, base + block, block_size, sector_data);
+
+ // Note the new cluster in the chain
+ if( Previous != -1 )
+ {
+ LOG("Updating cluster %x to point to %x (offset %x)", Previous, ret,
+ base + (Previous>>1)*3);
+ VFS_ReadAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val);
+ if( Previous & 1 ) {
+ val &= 0x000FFF;
+ val |= ret << 12;
+ }
+ else {
+ val &= 0xFFF000;
+ val |= ret << 0;
+ }
+ VFS_WriteAt(Disk->fileHandle, base + (Previous>>1)*3, 3, &val);
+ }
+ }
+ break;
+ case FAT16:
+ Log_Warning("FAT", "TODO: Implement cluster allocation with FAT16");
+// VFS_ReadAt(Disk->fileHandle, ofs+Previous*2, 2, &ret);
+// VFS_WriteAt(Disk->fileHandle, ofs+ret*2, 2, &eoc);
+ break;
+ case FAT32:
+ Log_Warning("FAT", "TODO: Implement cluster allocation with FAT32");
+// VFS_ReadAt(Disk->fileHandle, ofs+Previous*4, 4, &ret);
+// VFS_WriteAt(Disk->fileHandle, ofs+ret*4, 4, &eoc);
+ break;
+ }
+ Mutex_Release(&Disk->lFAT);
+ LOG("Allocated cluster %x", ret);
+ return ret;
+ #if CACHE_FAT
+ }
+ #endif
+}
+
+/**
+ * \brief Free's a cluster
+ * \return The original contents of the cluster
+ */
+Uint32 FAT_int_FreeCluster(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+ Uint32 ret;
+
+ if( Cluster < 2 || Cluster > Disk->ClusterCount ) // oops?
+ {
+ Log_Notice("FAT", "Cluster 0x%x is out of range (2 ... 0x%x)",
+ Cluster, Disk->ClusterCount-1);
+ return -1;
+ }
+
+ Mutex_Acquire(&Disk->lFAT);
+ #if CACHE_FAT
+ if( Disk->ClusterCount <= giFAT_MaxCachedClusters )
+ {
+
+ ret = Disk->FATCache[Cluster];
+ Disk->FATCache[Cluster] = 0;
+ }
+ else
+ {
+ #endif
+ Uint32 val = 0;
+ Uint32 ofs = Disk->bootsect.resvSectCount*512;
+ switch(Disk->type)
+ {
+ case FAT12:
+ VFS_ReadAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
+ val = LittleEndian32(val);
+ if( Cluster & 1 ) {
+ ret = (val >> 12) & 0xFFF;
+ val &= 0xFFF;
+ }
+ else {
+ ret = val & 0xFFF;
+ val &= 0xFFF000;
+ }
+ val = LittleEndian32(val);
+ VFS_WriteAt(Disk->fileHandle, ofs+(Cluster>>1)*3, 3, &val);
+ break;
+ case FAT16:
+ VFS_ReadAt(Disk->fileHandle, ofs+Cluster*2, 2, &ret);
+ ret = LittleEndian16(ret);
+ val = 0;
+ VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 2, &val);
+ break;
+ case FAT32:
+ VFS_ReadAt(Disk->fileHandle, ofs+Cluster*4, 4, &ret);
+ ret = LittleEndian32(ret);
+ val = 0;
+ VFS_WriteAt(Disk->fileHandle, ofs+Cluster*2, 4, &val);
+ break;
+ }
+ #if CACHE_FAT
+ }
+ #endif
+ Mutex_Release(&Disk->lFAT);
+ LOG("ret = %07x, eoc = %07x", ret, EOC_FAT12);
+ if(ret == 0) {
+ Log_Notice("FAT", "Cluster 0x%x was already free", Cluster);
+ return -1;
+ }
+ if(Disk->type == FAT12 && ret == EOC_FAT12) ret = -1;
+ if(Disk->type == FAT16 && ret == EOC_FAT16) ret = -1;
+ if(Disk->type == FAT32 && ret == EOC_FAT32) ret = -1;
+ LOG("ret = %07x", ret);
+ return ret;
+}
+#endif
+
+/*
+ * ====================
+ * Cluster IO
+ * ====================
+ */
+/**
+ * \brief Read a cluster
+ * \param Disk Disk (Volume) to read from
+ * \param Length Length to read
+ * \param Buffer Destination for read data
+ */
+void FAT_int_ReadCluster(tFAT_VolInfo *Disk, Uint32 Cluster, int Length, void *Buffer)
+{
+ ENTER("pDisk xCluster iLength pBuffer", Disk, Cluster, Length, Buffer);
+ VFS_ReadAt(
+ Disk->fileHandle,
+ (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
+ * Disk->bootsect.bps,
+ Length,
+ Buffer
+ );
+ LEAVE('-');
+}
+
+#if SUPPORT_WRITE
+/**
+ * \brief Write a cluster to disk
+ */
+void FAT_int_WriteCluster(tFAT_VolInfo *Disk, Uint32 Cluster, const void *Buffer)
+{
+ ENTER("pDisk xCluster pBuffer", Disk, Cluster, Buffer);
+ VFS_WriteAt(
+ Disk->fileHandle,
+ (Disk->firstDataSect + (Cluster-2)*Disk->bootsect.spc )
+ * Disk->bootsect.bps,
+ Disk->BytesPerCluster,
+ Buffer
+ );
+ LEAVE('-');
+}
+#endif
#ifndef _FS_FAT_H_\r
#define _FS_FAT_H_\r
\r
+#define FAT16_MIN_SECTORS 4085\r
+#define FAT32_MIN_CLUSTERS 65525\r
+\r
// === On Disk Structures ===\r
/**\r
* \struct fat_bootsect_s\r
* \}\r
*/\r
\r
-/**\r
- * \brief Internal IDs for FAT types\r
- */\r
-enum eFatType\r
-{\r
- FAT12, //!< FAT12 Volume\r
- FAT16, //!< FAT16 Volume\r
- FAT32, //!< FAT32 Volume\r
-};\r
-\r
/**\r
* \name End of Cluster marks\r
* \brief FAT values that indicate the end of a cluster chain in\r
typedef struct fat_filetable_s fat_filetable;\r
typedef struct fat_longfilename_s fat_longfilename;\r
\r
-// === Memory Structures ===\r
-/**\r
- * \struct drv_fat_volinfo_s\r
- * \brief Representation of a volume in memory\r
- */\r
-struct drv_fat_volinfo_s\r
-{\r
- int fileHandle; //!< File Handle\r
- int type; //!< FAT Type. See eFatType\r
- char name[12]; //!< Volume Name (With NULL Terminator)\r
- tMutex lFAT; //!< Lock to prevent double-writing to the FAT\r
- Uint32 firstDataSect; //!< First data sector\r
- Uint32 rootOffset; //!< Root Offset (clusters)\r
- Uint32 ClusterCount; //!< Total Cluster Count\r
- fat_bootsect bootsect; //!< Boot Sector\r
- tVFS_Node rootNode; //!< Root Node\r
- int BytesPerCluster;\r
- int inodeHandle; //!< Inode Cache Handle\r
- #if CACHE_FAT\r
- Uint32 *FATCache; //!< FAT Cache\r
- #endif\r
-};\r
-\r
-typedef struct drv_fat_volinfo_s tFAT_VolInfo;\r
-\r
#endif\r
--- /dev/null
+/*
+ * Acess2 FAT12/16/32 Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * nodecache.c
+ * - FAT-Specific node caching
+ */
+#include <acess.h>
+#include <vfs.h>
+#include "common.h"
+
+// === PROTOTYPES ===
+extern tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node);
+
+// === CODE ===
+tTime FAT_int_GetAcessTimestamp(Uint16 Date, Uint16 Time, Uint8 MS)
+{
+ return MS * 10 + timestamp(
+ // Seconds Minutes Hours
+ (Time & 0x1F) * 2, (Time >> 5) & 0x3F, (Time >> 11) & 0x1F,
+ // Day Month Year
+ (Date & 0x1F) - 1, ((Date >> 5) & 0xF) - 1, 1980 + ((Date >> 9) & 0xFF)
+ );
+}
+
+void FAT_int_GetFATTimestamp(tTime AcessTimestamp, Uint16 *Date, Uint16 *Time, Uint8 *MS)
+{
+ int y, m, d;
+ int h, min, s, ms;
+ format_date(AcessTimestamp, &y, &m, &d, &h, &min, &s, &ms);
+ if(Date)
+ *Date = (d + 1) | ((m + 1) << 5) | ((y - 1980) << 9);
+ if(Time)
+ *Time = (s / 2) | (min << 5) | (h << 11);
+ if(MS)
+ *MS = (ms / 10) + (s & 1) * 100;
+}
+
+/**
+ * \brief Creates a tVFS_Node structure for a given file entry
+ * \param Parent Parent directory VFS node
+ * \param Entry File table entry for the new node
+ */
+tVFS_Node *FAT_int_CreateNode(tVFS_Node *Parent, fat_filetable *Entry)
+{
+ tVFS_Node node;
+ tVFS_Node *ret;
+ tFAT_VolInfo *disk = Parent->ImplPtr;
+
+ ENTER("pParent pEntry", Parent, Entry);
+ LOG("disk = %p", disk);
+
+ if( (ret = FAT_int_GetNode(disk, Entry->cluster | (Entry->clusterHi<<16))) )
+ {
+ if( (ret->Inode >> 32) != 0 )
+ {
+ LEAVE('p', ret);
+ return ret;
+ }
+ }
+ else
+ {
+ ret = &node;
+ memset(ret, 0, sizeof(tVFS_Node));
+ }
+
+ // Set Other Data
+ // 0-27: Cluster, 32-59: Parent Cluster
+ ret->Inode = Entry->cluster | (Entry->clusterHi<<16) | (Parent->Inode << 32);
+ LOG("node.Inode = %llx", ret->Inode);
+ ret->ImplInt = 0;
+ // Disk Pointer
+ ret->ImplPtr = disk;
+ ret->Size = Entry->size;
+ LOG("Entry->size = %i", Entry->size);
+ // root:root
+ ret->UID = 0; ret->GID = 0;
+ ret->NumACLs = 1;
+
+ ret->Flags = 0;
+ if(Entry->attrib & ATTR_DIRECTORY)
+ ret->Flags |= VFS_FFLAG_DIRECTORY;
+ if(Entry->attrib & ATTR_READONLY) {
+ ret->Flags |= VFS_FFLAG_READONLY;
+ ret->ACLs = &gVFS_ACL_EveryoneRX; // R-XR-XR-X
+ }
+ else {
+ ret->ACLs = &gVFS_ACL_EveryoneRWX; // RWXRWXRWX
+ }
+
+ // Create timestamps
+ ret->CTime = FAT_int_GetAcessTimestamp(Entry->cdate, Entry->ctime, Entry->ctimems);
+ ret->MTime = FAT_int_GetAcessTimestamp(Entry->mdate, Entry->mtime, 0);
+ ret->ATime = FAT_int_GetAcessTimestamp(Entry->adate, 0, 0);
+
+ // Set pointers
+ if(ret->Flags & VFS_FFLAG_DIRECTORY) {
+ //Log_Debug("FAT", "Directory %08x has size 0x%x", node.Inode, node.Size);
+ ret->Type = &gFAT_DirType;
+ ret->Size = -1;
+ }
+ else {
+ ret->Type = &gFAT_FileType;
+ }
+
+ // Cache node only if we're not updating a cache
+ if( ret == &node ) {
+ ret = FAT_int_CacheNode(disk, &node);
+ }
+
+ LEAVE('p', ret);
+ return ret;
+}
+
+tVFS_Node *FAT_int_CreateIncompleteDirNode(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+ if( Cluster == Disk->rootOffset )
+ return &Disk->rootNode;
+
+ // If the directory isn't in the cache, what do?
+ // - we want to lock it such that we don't collide, but don't want to put crap data in the cache
+ // - Put a temp node in with a flag that indicates it's incomplete?
+
+ Mutex_Acquire(&Disk->lNodeCache);
+ tFAT_CachedNode *cnode, *prev = NULL;
+
+ for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next)
+ {
+ if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
+ cnode->Node.ReferenceCount ++;
+ Mutex_Release(&Disk->lNodeCache);
+ return &cnode->Node;
+ }
+ }
+
+ // Create a temporary node?
+ cnode = calloc( sizeof(tFAT_CachedNode), 1 );
+ cnode->Node.Inode = Cluster;
+ cnode->Node.ReferenceCount = 1;
+ cnode->Node.ImplPtr = Disk;
+ cnode->Node.Type = &gFAT_DirType;
+ cnode->Node.Size = -1;
+
+ if( prev )
+ prev->Next = cnode;
+ else
+ Disk->NodeCache = cnode;
+
+ Mutex_Release(&Disk->lNodeCache);
+ return &cnode->Node;
+}
+
+tVFS_Node *FAT_int_GetNode(tFAT_VolInfo *Disk, Uint32 Cluster)
+{
+ if( Cluster == Disk->rootOffset )
+ return &Disk->rootNode;
+ Mutex_Acquire(&Disk->lNodeCache);
+ tFAT_CachedNode *cnode;
+
+ for(cnode = Disk->NodeCache; cnode; cnode = cnode->Next)
+ {
+ if( (cnode->Node.Inode & 0xFFFFFFFF) == Cluster ) {
+ cnode->Node.ReferenceCount ++;
+ Mutex_Release(&Disk->lNodeCache);
+ return &cnode->Node;
+ }
+ }
+
+ Mutex_Release(&Disk->lNodeCache);
+ return NULL;
+}
+
+tVFS_Node *FAT_int_CacheNode(tFAT_VolInfo *Disk, const tVFS_Node *Node)
+{
+ tFAT_CachedNode *cnode, *prev = NULL;
+ Mutex_Acquire(&Disk->lNodeCache);
+
+ for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
+ {
+ if( cnode->Node.Inode == Node->Inode ) {
+ cnode->Node.ReferenceCount ++;
+ Mutex_Release(&Disk->lNodeCache);
+ return &cnode->Node;
+ }
+ }
+
+ cnode = malloc(sizeof(tFAT_CachedNode));
+ cnode->Next = NULL;
+ memcpy(&cnode->Node, Node, sizeof(tVFS_Node));
+ cnode->Node.ReferenceCount = 1;
+
+ if( prev )
+ prev->Next = cnode;
+ else
+ Disk->NodeCache = cnode;
+
+ Mutex_Release(&Disk->lNodeCache);
+ return &cnode->Node;
+}
+
+int FAT_int_DerefNode(tVFS_Node *Node)
+{
+ tFAT_VolInfo *Disk = Node->ImplPtr;
+ tFAT_CachedNode *cnode, *prev = NULL;
+ int bFreed = 0;
+
+ if( Node == &Disk->rootNode )
+ return 0;
+
+ Mutex_Acquire(&Disk->lNodeCache);
+ Node->ReferenceCount --;
+ for(cnode = Disk->NodeCache; cnode; prev = cnode, cnode = cnode->Next )
+ {
+ if(Node == &cnode->Node) {
+ if(prev)
+ prev->Next = cnode->Next;
+ else
+ Disk->NodeCache = cnode->Next;
+ break;
+ }
+ }
+ if(Node->ReferenceCount == 0 && cnode) {
+ // Already out of the list :)
+ if(cnode->Node.Data)
+ free(cnode->Node.Data);
+ VFS_CleanupNode(&cnode->Node);
+ free(cnode);
+ bFreed = 1;
+ }
+ Mutex_Release(&Disk->lNodeCache);
+ if( !cnode ) {
+ // Not here?
+ return -1;
+ }
+
+ return bFreed;
+}
+
+void FAT_int_ClearNodeCache(tFAT_VolInfo *Disk)
+{
+ // TODO: In theory when this is called, all handles will be closed
+}
foreach($lines as $line)
{
$line = trim($line);
+ if($line[0] == "#") continue;
// Directory
if(preg_match('/^Dir\s+"([^"]+)"\s+{$/', $line, $matches))
{
}
$size = filesize($path);
-/*
- $_sym = $prefix."_".$i."_data";
- $fp = fopen($path, "rb");
-
- $gOutput .= "Uint8 $_sym[] = {\n";
- for( $j = 0; $j + 16 < $size; $j += 16 ) {
- $gOutput .= "\t";
- $gOutput .= hd8($fp).",".hd8($fp).",";
- $gOutput .= hd8($fp).",".hd8($fp).",";
- $gOutput .= hd8($fp).",".hd8($fp).",";
- $gOutput .= hd8($fp).",".hd8($fp).",";
- $gOutput .= hd8($fp).",".hd8($fp).",";
- $gOutput .= hd8($fp).",".hd8($fp).",";
- $gOutput .= hd8($fp).",".hd8($fp).",";
- $gOutput .= hd8($fp).",".hd8($fp).",\n";
- }
- $gOutput .= "\t";
- for( ; $j < $size; $j ++ ) {
- if( $j & 15 ) $gOutput .= ",";
- $gOutput .= hd8($fp);
- }
- fclose($fp);
- $gOutput .= "\n};\n";
-*/
-
-//*
$_sym = "_binary_".str_replace(array("/","-","."), "_", $path)."_start";
$gOutput .= "extern Uint8 {$_sym}[];";
$gSymFiles[] = $path;
-//*/
$gOutput .= <<<EOF
tVFS_Node {$prefix}_{$i} = {
.NumACLs = 1,
Dir "SBin" {
File "init" "__BIN__/SBin/init"
File "login" "__BIN__/SBin/login"
- File "dhcpc" "__BIN__/SBin/dhcpc"
+ File "telnetd" "__BIN__/SBin/telnetd"
}
Dir "Bin" {
File "CLIShell" "__BIN__/Bin/CLIShell"
File "ls" "__BIN__/Bin/ls"
File "cat" "__BIN__/Bin/cat"
File "mount" "__BIN__/Bin/mount"
- File "ifconfig" "__BIN__/Bin/ifconfig"
+ File "lspci" "__BIN__/Bin/lspci"
+ File "ip" "__BIN__/Bin/ip"
File "ping" "__BIN__/Bin/ping"
File "telnet" "__BIN__/Bin/telnet"
File "irc" "__BIN__/Bin/irc"
+ File "dhcpc" "__BIN__/SBin/dhcpc"
}
Dir "Libs" {
File "ld-acess.so" "__BIN__/Libs/ld-acess.so"
}
}
}
+#Dir "Keen5" {
+# File "keen5e" "/home/tpg/Projects/AcessPorts/omnispeak/bin/keen5e"
+# File "EGADICT.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGADICT.CK5"
+# File "EGAGRAPH.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGAGRAPH.CK5"
+# File "EGAHEAD.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/EGAHEAD.CK5"
+# File "GAMEMAPS.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/GAMEMAPS.CK5"
+# File "GFXINFOE.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/GFXINFOE.CK5"
+# File "MAPHEAD.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/MAPHEAD.CK5"
+# File "TILEINFO.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/original/TILEINFO.CK5"
+# File "ACTION.CK5" "/home/tpg/Projects/AcessPorts/omnispeak/bin/ACTION.CK5"
+#}
// === Functions ===
-extern size_t InitRD_ReadFile(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
-extern char *InitRD_ReadDir(tVFS_Node *Node, int ID);
-extern tVFS_Node *InitRD_FindDir(tVFS_Node *Node, const char *Name);
+//extern size_t InitRD_ReadFile(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
+//extern int InitRD_ReadDir(tVFS_Node *Node, int ID);
+//extern tVFS_Node *InitRD_FindDir(tVFS_Node *Node, const char *Name);
// === Globals ===
tVFS_NodeType gInitRD_DirType;
void InitRD_Unmount(tVFS_Node *Node);
tVFS_Node *InitRD_GetNodeFromINode(tVFS_Node *Root, Uint64 Inode);
size_t InitRD_ReadFile(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
-char *InitRD_ReadDir(tVFS_Node *Node, int ID);
+ int InitRD_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
tVFS_Node *InitRD_FindDir(tVFS_Node *Node, const char *Name);
void InitRD_DumpDir(tVFS_Node *Node, int Indent);
// === GLOBALS ===
MODULE_DEFINE(0, 0x0A, FS_InitRD, InitRD_Install, NULL);
tVFS_Driver gInitRD_FSInfo = {
- "initrd", 0, InitRD_InitDevice, InitRD_Unmount, InitRD_GetNodeFromINode
+ .Name = "initrd",
+ .InitDevice = InitRD_InitDevice,
+ .Unmount = InitRD_Unmount,
+ .GetNodeFromINode = InitRD_GetNodeFromINode
};
tVFS_NodeType gInitRD_DirType = {
.ReadDir = InitRD_ReadDir,
*/
int InitRD_Install(char **Arguments)
{
- Log_Notice("InitRD", "Installed");
VFS_AddDriver( &gInitRD_FSInfo );
return MODULE_ERR_OK;
#if DUMP_ON_MOUNT
InitRD_DumpDir( &gInitRD_RootNode, 0 );
#endif
- Log_Notice("InitRD", "Mounted (%i files)", giInitRD_NumFiles);
return &gInitRD_RootNode;
}
/**
* \brief Read from a directory
*/
-char *InitRD_ReadDir(tVFS_Node *Node, int ID)
+int InitRD_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
{
tInitRD_File *dir = Node->ImplPtr;
if(ID >= Node->Size)
- return NULL;
+ return -EINVAL;
- return strdup(dir[ID].Name);
+ strncpy(Dest, dir[ID].Name, FILENAME_MAX);
+ return 0;
}
/**
};
} PACKED tNTFS_FILE_Attrib;
+extern int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
+extern tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name);
+
#endif
#include "index.h"
// === PROTOTYPES ===
-char *NTFS_ReadDir(tVFS_Node *Node, int Pos);
+ int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name);
Uint64 NTFS_int_IndexLookup(Uint64 Inode, const char *IndexName, const char *Str);
/**
* \brief Get the name of an indexed directory entry
*/
-char *NTFS_ReadDir(tVFS_Node *Node, int Pos)
+int NTFS_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
- return NULL;
+ return -ENOTIMPL;
}
/**
#include "common.h"
#include <modules.h>
-// === IMPORTS ===
-extern char *NTFS_ReadDir(tVFS_Node *Node, int Pos);
-extern tVFS_Node *NTFS_FindDir(tVFS_Node *Node, const char *Name);
-
// === PROTOTYPES ===
int NTFS_Install(char **Arguments);
tVFS_Node *NTFS_InitDevice(const char *Devices, const char **Options);
// === GLOBALS ===
MODULE_DEFINE(0, 0x0A /*v0.1*/, FS_NTFS, NTFS_Install, NULL);
-tVFS_Driver gNTFS_FSInfo = {"ntfs", 0, NTFS_InitDevice, NTFS_Unmount, NULL};
+tVFS_Driver gNTFS_FSInfo = {
+ .Name = "ntfs",
+ .InitDevice = NTFS_InitDevice,
+ .Unmount = NTFS_Unmount,
+ .GetNodeFromINode = NULL
+};
tVFS_NodeType gNTFS_DirType = {
.TypeName = "NTFS-File",
.ReadDir = NTFS_ReadDir,
--- /dev/null
+#
+# RAMDisk Makfile
+#
+
+OBJ = ramdisk.o
+NAME = RAMDisk
+
+-include ../Makefile.tpl
+
--- /dev/null
+/*
+ * Acess2 Kernel - RAM Disk Support
+ * - By John Hodge (thePowersGang)
+ *
+ * ramdisk.c
+ * - Core File
+ */
+#define DEBUG 1
+#include <acess.h>
+#include <modules.h>
+#include "ramdisk.h"
+#define VERSION VER2(0,1)
+
+#define MIN_RAMDISK_SIZE (1*1024*1024)
+#define MAX_RAMDISK_SIZE (64*1024*1024)
+
+// === PROTOTYPES ===
+ int RAMFS_Install(char **Arguments);
+ int RAMFS_Cleanup(void);
+// --- Mount/Unmount ---
+tVFS_Node *RAMFS_InitDevice(const char *Device, const char **Options);
+void RAMFS_Unmount(tVFS_Node *Node);
+// --- Directories ---
+ int RAMFS_ReadDir(tVFS_Node *Node, int Index, char Dest[256]);
+tVFS_Node *RAMFS_FindDir(tVFS_Node *Node, const char *Name);
+tVFS_Node *RAMFS_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int RAMFS_Link(tVFS_Node *DirNode, const char *Name, tVFS_Node *Node);
+ int RAMFS_Unlink(tVFS_Node *Node, const char *Name);
+// --- Files ---
+size_t RAMFS_Read(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer);
+size_t RAMFS_Write(tVFS_Node *Node, off_t Offset, size_t Size, const void *Buffer);
+// --- Internals --
+void RAMFS_int_RefFile(tRAMFS_Inode *Inode);
+void RAMFS_int_DerefFile(tRAMFS_Inode *Inode);
+void *RAMFS_int_GetPage(tRAMFS_File *File, int Page, int bCanAlloc);
+void RAMFS_int_DropPage(void *Page);
+Uint32 RAMFS_int_AllocatePage(tRAMDisk *Disk);
+void RAMFS_int_RefFile(tRAMFS_Inode *Inode);
+void RAMFS_int_DerefFile(tRAMFS_Inode *Inode);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, FS_RAMDisk, RAMFS_Install, RAMFS_Cleanup, NULL);
+tVFS_Driver gRAMFS_Driver = {
+ .Name = "ramfs",
+ .InitDevice = RAMFS_InitDevice,
+ .Unmount = RAMFS_Unmount
+ // TODO: GetNodeFromInode
+ };
+tVFS_NodeType gRAMFS_DirNodeType = {
+ .ReadDir = RAMFS_ReadDir,
+ .FindDir = RAMFS_FindDir,
+ .MkNod = RAMFS_MkNod,
+ .Link = RAMFS_Link,
+ .Unlink = RAMFS_Unlink
+ };
+tVFS_NodeType gRAMFS_FileNodeType = {
+ .Read = RAMFS_Read,
+ .Write = RAMFS_Write
+ };
+
+// === CODE ===
+int RAMFS_Install(char **Arguments)
+{
+ VFS_AddDriver( &gRAMFS_Driver );
+ return 0;
+}
+
+int RAMFS_Cleanup(void)
+{
+ return 0;
+}
+
+
+// --- Mount/Unmount
+const char *_GetOption(const char *Data, const char *Option)
+{
+ int len = strlen(Option);
+ if( strncmp(Data, Option, len) != 0 )
+ return NULL;
+ if( Data[len] != '=' )
+ return NULL;
+ return Data + len + 1;
+}
+
+tVFS_Node *RAMFS_InitDevice(const char *Device, const char **Options)
+{
+ size_t size = 0;
+ tRAMDisk *rd;
+
+ if( Options )
+ {
+ const char *v;
+ for( int i = 0; Options[i]; i ++ )
+ {
+ LOG("Options[%i] = '%s'", i, Options[i]);
+ if( (v = _GetOption(Options[i], "megs")) )
+ {
+ size = atoi(v) * 1024 * 1024;
+ LOG("Size set to %iMiB", size>>20);
+ }
+ }
+ }
+
+ LOG("Disk Size %iKiB", size>>10);
+
+ if( size > MAX_RAMDISK_SIZE || size < MIN_RAMDISK_SIZE )
+ return NULL;
+
+ int n_pages = size / PAGE_SIZE;
+
+ rd = calloc(1, sizeof(tRAMDisk) + n_pages * sizeof(tPAddr) + n_pages / 8);
+ rd->MaxPages = n_pages;
+ rd->RootDir.Inode.Disk = rd;
+ rd->RootDir.Inode.Node.ImplPtr = &rd->RootDir;
+ rd->RootDir.Inode.Node.Flags = VFS_FFLAG_DIRECTORY;
+ rd->RootDir.Inode.Node.Size = -1;
+ rd->RootDir.Inode.Node.Type = &gRAMFS_DirNodeType;
+ rd->Bitmap = (void*)&rd->PhysPages[ n_pages ];
+
+ for( int i = 0; i < n_pages; i ++ )
+ {
+ rd->PhysPages[i] = MM_AllocPhys();
+ if( !rd->PhysPages[i] ) {
+ // Um... oops?
+ break;
+ }
+ }
+
+ LOG("Mounted");
+ return &rd->RootDir.Inode.Node;
+}
+
+void RAMFS_Unmount(tVFS_Node *Node)
+{
+ Log_Warning("RAMDisk", "TODO: Impliment unmounting");
+}
+
+// --- Directories ---
+int RAMFS_ReadDir(tVFS_Node *Node, int Index, char Dest[FILENAME_MAX])
+{
+ tRAMFS_Dir *dir = Node->ImplPtr;
+ for( tRAMFS_DirEnt *d = dir->FirstEnt; d; d = d->Next )
+ {
+ if( Index -- == 0 ) {
+ LOG("Return %s", d->Name);
+ strncpy(Dest, d->Name, FILENAME_MAX);
+ return 0;
+ }
+ }
+ LOG("Return -ENOENT");
+ return -ENOENT;
+}
+
+tVFS_Node *RAMFS_FindDir(tVFS_Node *Node, const char *Name)
+{
+ tRAMFS_Dir *dir = Node->ImplPtr;
+
+ for( tRAMFS_DirEnt *d = dir->FirstEnt; d; d = d->Next )
+ {
+ if( strcmp(d->Name, Name) == 0 ) {
+ LOG("Return %p", &d->Inode->Node);
+ return &d->Inode->Node;
+ }
+ }
+
+ LOG("Return NULL");
+ return NULL;
+}
+
+tVFS_Node *RAMFS_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+{
+ tRAMFS_Dir *dir = Node->ImplPtr;
+ if( RAMFS_FindDir(Node, Name) != NULL )
+ return NULL;
+
+ tRAMFS_DirEnt *de = malloc( sizeof(tRAMFS_DirEnt) + strlen(Name) + 1 );
+ de->Next = NULL;
+ de->NameLen = strlen(Name);
+ strcpy(de->Name, Name);
+
+ if( Flags & VFS_FFLAG_DIRECTORY ) {
+ tRAMFS_Dir *newdir = calloc(1, sizeof(tRAMFS_Dir));
+ newdir->Inode.Node.Type = &gRAMFS_DirNodeType;
+ de->Inode = &newdir->Inode;
+ }
+ else {
+ tRAMFS_File *newfile = calloc(1, sizeof(tRAMFS_File));
+ newfile->Inode.Node.Type = &gRAMFS_FileNodeType;
+ de->Inode = &newfile->Inode;
+ }
+ de->Inode->Disk = dir->Inode.Disk;
+ de->Inode->Node.Flags = Flags;
+ de->Inode->Node.ImplPtr = de->Inode;
+
+ RAMFS_int_RefFile(de->Inode);
+
+ // TODO: Lock?
+ if(dir->FirstEnt)
+ dir->LastEnt->Next = de;
+ else
+ dir->FirstEnt = de;
+ dir->LastEnt = de;
+
+ return &de->Inode->Node;
+}
+
+int RAMFS_Link(tVFS_Node *DirNode, const char *Name, tVFS_Node *FileNode)
+{
+ tRAMFS_Dir *dir = DirNode->ImplPtr;
+ tRAMFS_DirEnt *dp;
+
+ for( dp = dir->FirstEnt; dp; dp = dp->Next )
+ {
+ if( strcmp(dp->Name, Name) == 0 )
+ return -1;
+ }
+
+ dp = malloc( sizeof(tRAMFS_DirEnt) + strlen(Name) + 1 );
+ dp->Next = NULL;
+ dp->Inode = FileNode->ImplPtr;
+ RAMFS_int_RefFile(dp->Inode);
+ strcpy(dp->Name, Name);
+
+ // TODO: Lock?
+ if(dir->FirstEnt)
+ dir->LastEnt->Next = dp;
+ else
+ dir->FirstEnt = dp;
+ dir->LastEnt = dp;
+
+ return 0;
+}
+
+int RAMFS_Unlink(tVFS_Node *Node, const char *Name)
+{
+ tRAMFS_Dir *dir = Node->ImplPtr;
+ tRAMFS_DirEnt *dp, *p = NULL;
+
+ // TODO: Is locking needed?
+
+ // Find the directory entry
+ for( dp = dir->FirstEnt; dp; p = dp, dp = dp->Next )
+ {
+ if( strcmp(dp->Name, Name) == 0 )
+ break ;
+ }
+ if( !dp ) return -1;
+
+ // Dereference the file
+ RAMFS_int_DerefFile( dp->Inode );
+
+ // Remove and free directory entry
+ if(!p)
+ dir->FirstEnt = dp->Next;
+ else
+ p->Next = dp->Next;
+ if( dir->LastEnt == dp )
+ dir->LastEnt = p;
+ free(dp);
+
+ return 0;
+}
+
+// --- Files ---
+size_t RAMFS_int_DoIO(tRAMFS_File *File, off_t Offset, size_t Size, void *Buffer, int bRead)
+{
+ size_t rem;
+ Uint8 *page_virt;
+ int page;
+
+ if( Offset >= File->Size ) return 0;
+
+ if( Offset + Size > File->Size ) Size = File->Size - Size;
+
+ if( Size == 0 ) return 0;
+
+ page = Offset / PAGE_SIZE;
+ Offset %= PAGE_SIZE;
+ rem = Size;
+
+ page_virt = RAMFS_int_GetPage(File, page++, !bRead);
+ if(!page_virt) return 0;
+
+ if( Offset + Size <= PAGE_SIZE )
+ {
+ if( bRead )
+ memcpy(Buffer, page_virt + Offset, Size);
+ else
+ memcpy(page_virt + Offset, Buffer, Size);
+ return 0;
+ }
+
+ if( bRead )
+ memcpy(Buffer, page_virt + Offset, PAGE_SIZE - Offset);
+ else
+ memcpy(page_virt + Offset, Buffer, PAGE_SIZE - Offset);
+ Buffer += PAGE_SIZE - Offset;
+ rem -= PAGE_SIZE - Offset;
+
+ while( rem >= PAGE_SIZE )
+ {
+ RAMFS_int_DropPage(page_virt);
+ page_virt = RAMFS_int_GetPage(File, page++, !bRead);
+ if(!page_virt) return Size - rem;
+
+ if( bRead )
+ memcpy(Buffer, page_virt, PAGE_SIZE);
+ else
+ memcpy(page_virt, Buffer, PAGE_SIZE);
+
+ Buffer += PAGE_SIZE;
+ rem -= PAGE_SIZE;
+ }
+
+ if( rem > 0 )
+ {
+ page_virt = RAMFS_int_GetPage(File, page, !bRead);
+ if(!page_virt) return Size - rem;
+ if( bRead )
+ memcpy(Buffer, page_virt, rem);
+ else
+ memcpy(page_virt, Buffer, rem);
+ }
+
+ RAMFS_int_DropPage(page_virt);
+
+ return Size;
+}
+
+size_t RAMFS_Read(tVFS_Node *Node, off_t Offset, size_t Size, void *Buffer)
+{
+ tRAMFS_File *file = Node->ImplPtr;
+
+ return RAMFS_int_DoIO(file, Offset, Size, Buffer, 1);
+}
+
+size_t RAMFS_Write(tVFS_Node *Node, off_t Offset, size_t Size, const void *Buffer)
+{
+ tRAMFS_File *file = Node->ImplPtr;
+
+ // TODO: Limit checks?
+ if( Offset == file->Size )
+ file->Size += Size;
+
+ return RAMFS_int_DoIO(file, Offset, Size, (void*)Buffer, 0);
+}
+
+// --- Internals ---
+void *RAMFS_int_GetPage(tRAMFS_File *File, int Page, int bCanAlloc)
+{
+ Uint32 page_id = 0;
+ Uint32 *page_in_1 = NULL;
+ Uint32 *page_in_2 = NULL;
+
+ int ofs = 0, block;
+
+ if( Page < 0 ) return NULL;
+
+ if( Page < RAMFS_NDIRECT )
+ {
+ if( File->PagesDirect[Page] )
+ page_id = File->PagesDirect[Page];
+ }
+ else if( Page - RAMFS_NDIRECT < PAGE_SIZE/4 )
+ {
+ ofs = Page - RAMFS_NDIRECT;
+ if( File->Indirect1Page == 0 ) {
+ if( !bCanAlloc )
+ return NULL;
+ else
+ File->Indirect1Page = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
+ }
+ page_in_1 = MM_MapTemp( File->Inode.Disk->PhysPages[File->Indirect1Page-1] );
+ page_id = page_in_1[ofs];
+ }
+ else if( Page - RAMFS_NDIRECT - PAGE_SIZE/4 < (PAGE_SIZE/4)*(PAGE_SIZE/4) )
+ {
+ block = (Page - RAMFS_NDIRECT - PAGE_SIZE/4) / (PAGE_SIZE/4);
+ ofs = (Page - RAMFS_NDIRECT - PAGE_SIZE/4) % (PAGE_SIZE/4);
+ if( File->Indirect2Page == 0 ){
+ if( !bCanAlloc )
+ return NULL;
+ else
+ File->Indirect2Page = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
+ }
+
+ page_in_2 = MM_MapTemp( File->Inode.Disk->PhysPages[File->Indirect2Page-1] );
+ if( page_in_2[block] == 0 ) {
+ if( !bCanAlloc )
+ return NULL;
+ else
+ page_in_2[block] = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
+ }
+
+ page_in_1 = MM_MapTemp( File->Inode.Disk->PhysPages[page_in_2[block] - 1] );
+ page_id = page_in_1[ofs];
+ }
+
+ if( page_id == 0 )
+ {
+ if( !bCanAlloc )
+ return NULL;
+
+ page_id = RAMFS_int_AllocatePage(File->Inode.Disk) + 1;
+ if(page_in_1)
+ page_in_1[ofs] = page_id;
+ else
+ File->PagesDirect[Page] = page_id;
+ }
+
+ MM_FreeTemp( page_in_1 );
+ MM_FreeTemp( page_in_2 );
+
+ return MM_MapTemp( File->Inode.Disk->PhysPages[page_id - 1] );
+}
+
+void RAMFS_int_DropPage(void *Page)
+{
+ MM_FreeTemp( Page );
+}
+
+Uint32 RAMFS_int_AllocatePage(tRAMDisk *Disk)
+{
+ int i, j;
+
+ // Quick check
+ if( Disk->nUsedPages == Disk->MaxPages )
+ return 0;
+
+ // Find a chunk with at least one free page
+ for( i = 0; i < Disk->MaxPages / 32; i ++ )
+ {
+ if( Disk->Bitmap[i] != -1 )
+ break;
+ }
+ if( i == Disk->MaxPages / 32 ) {
+ Log_Error("RAMFS", "Bookkeeping error, count and bitmap disagree");
+ return 0;
+ }
+
+ // Find the exact page
+ for( j = 0; j < 32; j ++ )
+ {
+ if( !(Disk->Bitmap[i] & (1U << j)) )
+ break ;
+ }
+ ASSERT(j < 32);
+
+ return i * 32 + j;
+}
+
+void RAMFS_int_RefFile(tRAMFS_Inode *Inode)
+{
+ Inode->nLink ++;
+}
+
+void RAMFS_int_DerefFile(tRAMFS_Inode *Inode)
+{
+ Inode->nLink --;
+ if( Inode->nLink >= 0 )
+ return ;
+
+ Log_Error("RAMFS", "TODO: Clean up files when deleted");
+
+ // Need to delete file
+ switch( Inode->Type )
+ {
+ case 0: // File
+ break ;
+ case 1: // Directory
+ break ;
+ case 2: // Symlink
+ break ;
+ }
+ free(Inode);
+}
--- /dev/null
+/*
+ * Acess2 Kernel - RAM Disk Support
+ * - By John Hodge (thePowersGang)
+ *
+ * ramdisk.h
+ * - Core header
+ */
+#ifndef _RAMDISK_H_
+#define _RAMDISK_H_
+
+#include <vfs.h>
+
+#define RAMFS_NDIRECT 12
+
+typedef struct sRAMFS_Inode tRAMFS_Inode;
+typedef struct sRAMFS_File tRAMFS_File;
+typedef struct sRAMFS_DirEnt tRAMFS_DirEnt;
+typedef struct sRAMFS_Dir tRAMFS_Dir;
+typedef struct sRAMDisk tRAMDisk;
+
+struct sRAMFS_Inode
+{
+ tRAMDisk *Disk;
+ tVFS_Node Node;
+ int Type; // 0: Normal, 1: Dir, 2: Symlink
+ int nLink;
+};
+
+struct sRAMFS_File
+{
+ tRAMFS_Inode Inode;
+ size_t Size;
+ int nAllocPageSlots;
+ Uint32 PagesDirect[RAMFS_NDIRECT];
+ Uint32 Indirect1Page; // PAGE_SIZE/sizeof(Uint32) = 1024 on x86
+ Uint32 Indirect2Page; // ~1 Million on x86
+};
+
+struct sRAMFS_DirEnt
+{
+ tRAMFS_DirEnt *Next;
+ tRAMFS_Inode *Inode;
+ Uint8 NameLen;
+ char Name[];
+};
+
+struct sRAMFS_Dir
+{
+ tRAMFS_Inode Inode;
+
+ tRAMFS_DirEnt *FirstEnt;
+ tRAMFS_DirEnt *LastEnt;
+};
+
+struct sRAMDisk
+{
+ tRAMFS_Dir RootDir;
+
+ int MaxPages;
+ Uint32 *Bitmap;
+ int nUsedPages;
+ tPAddr PhysPages[];
+};
+
+#endif
+
void *IPStack_Adapter_Add(const tIPStack_AdapterType *Type, void *Ptr, const void *HWAddr);
void IPStack_Adapter_Del(void *Handle);
// --- VFS API ---
-char *Adapter_ReadDir(tVFS_Node *Node, int Pos);
+ int Adapter_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]);
tVFS_Node *Adapter_FindDir(tVFS_Node *Node, const char *Name);
int Adapter_DirIOCtl(tVFS_Node *Node, int Num, void *Data);
int Adapter_IOCtl(tVFS_Node *Node, int Num, void *Data);
ret->Node.Type = &gIP_AdapterType;
ret->Node.ImplPtr = ret;
- // TODO: Locking
+ Mutex_Acquire( &glIP_Adapters );
gpIP_AdapterList_Last->Next = ret;
gpIP_AdapterList_Last = ret;
+ Mutex_Release( &glIP_Adapters );
// Watch the adapter for incoming packets
- tTID tid = Proc_SpawnWorker(Adapter_int_WatchThread, ret);
- if(tid < 0) {
+ void *worker = Proc_SpawnWorker(Adapter_int_WatchThread, ret);
+ if(!worker) {
Log_Warning("IPStack", "Unable to create watcher thread for %p", ret);
}
// Get MAC Address
VFS_IOCtl(fd, NET_IOCTL_GETMAC, mac);
- return IPStack_Adapter_Add(NULL, (void*)fd, mac);
+ return IPStack_Adapter_Add(NULL, (void*)(tVAddr)fd, mac);
}
void IPStack_Adapter_Del(void *Handle)
}
// --- VFS API ---
-char *Adapter_ReadDir(tVFS_Node *Node, int Pos)
+int Adapter_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
- if( Pos < 0 ) return NULL;
+ if( Pos < 0 ) return -EINVAL;
// Loopback
if( Pos == 0 ) {
- return strdup("lo");
+ strcpy(Dest, "lo");
+ return 0;
}
Pos --;
tAdapter *a; int i;\
for(i=0,a=list; i < Pos && a; i ++, a = a->Next ); \
if( a ) { \
- return Adapter_GetName(a);\
+ strncpy(Dest, Adapter_GetName(a), FILENAME_MAX);\
+ return 0;\
} \
Pos -= i; \
} while(0);
CHECK_LIST(gpIP_AdapterList, "eth");
// TODO: Support other types of adapters (wifi, tap, ...)
- return NULL;
+ return -EINVAL;
}
tVFS_Node *Adapter_FindDir(tVFS_Node *Node, const char *Name)
return 0;
}
+// --- Broadcast Debugging ---
+extern Uint16 IPv4_Checksum(const void *Buf, size_t Length);
+void IPStack_SendDebugText(const char *Text)
+{
+ const Uint8 pkt_hdr[] = {
+ 0xFF,0xFF, 0xFF,0xFF, 0xFF,0xFF,
+ 0x00,0x00, 0x00,0x00, 0x00,0x00,
+ 0x08,0x00,
+
+ 0x45,0x00, // Version/Length, DiffServices
+ 0xFF,0xFF, // Total Length
+ 0x00,0x00, // Identifcation
+ 0x00,0x00, 0xFF,0x11, // Flags,Fragment, TTL=255,proto=UDP
+ 0x00,0x00, // Header checksum
+ 0x00,0x00,0x00,0x00, // Source
+ 0xFF,0xFF,0xFF,0xFF, // Destination
+
+ 0x80,0x00, 0x80,0x00,
+ 0xFF,0xFF, 0xFF,0xFF,
+ };
+ static tShortSpinlock lLock;
+
+ // Fast return if there's no avaliable adapters
+ if( !gpIP_AdapterList )
+ return ;
+
+ if( CPU_HAS_LOCK(&lLock) )
+ return ; // Nested!
+ SHORTLOCK(&lLock);
+ #if ARCHDIR_is_x86
+ __asm__ __volatile__ ("sti"); // Start interrupts (x86 specific)
+ #endif
+
+ // Cache packets until a newline
+ static char cache[1500 - (sizeof(pkt_hdr) + 4)];
+ static int cache_len;
+
+ int len = strlen(Text);
+
+ // Append to cache
+ strncpy(cache + cache_len, Text, sizeof(cache) - cache_len);
+ cache_len += len;
+ // TODO: Detect overflows.
+
+ // If there's no newline, only buffer
+ if( strpos(Text, '\n') == -1 ) {
+ SHORTREL(&lLock);
+ return ;
+ }
+
+ // Build packet
+ int link_checksum_ofs = sizeof(pkt_hdr) + cache_len;
+ char buffer[sizeof(pkt_hdr) + cache_len + 4];
+
+ memcpy(buffer, pkt_hdr, sizeof(pkt_hdr));
+ memcpy(buffer + sizeof(pkt_hdr), cache, cache_len);
+
+ ((Uint16*)buffer)[(14+2)/2] = BigEndian16( sizeof(pkt_hdr)-14 + cache_len ); // IP Size
+ ((Uint16*)buffer)[(14+10)/2] = BigEndian16( 0 ); // IP Header
+ ((Uint16*)buffer)[(14+20+4)/2] = BigEndian16( 8+cache_len ); // UDP Size
+ ((Uint16*)buffer)[(14+20+6)/2] = BigEndian16( 0 ); // UDP Checksum
+// *(Uint32*)&buffer[link_checksum_ofs] = BigEndian32( 0 ); // 802.3 checksum?
+ // TODO: Calculate checksums
+ ((Uint16*)buffer)[(14+10)/2] = BigEndian16( IPv4_Checksum(buffer+14,20) ); // IP Header
+
+ // Create buffer
+ tIPStackBuffer *buf = IPStack_Buffer_CreateBuffer(1);
+ IPStack_Buffer_AppendSubBuffer(buf, link_checksum_ofs+4, 0, buffer, NULL, NULL);
+
+ // Send 'er off
+ for( tAdapter *a = gpIP_AdapterList; a; a = a->Next )
+ {
+ a->Type->SendPacket( a->CardHandle, buf );
+ }
+
+ IPStack_Buffer_DestroyBuffer(buf);
+
+ cache_len = 0;
+
+ SHORTREL(&lLock);
+}
+
return -1;
}
- if( Index > Buffer->nSubBuffers )
+ if( Index >= Buffer->nSubBuffers )
{
// Appended buffers
Index -= Buffer->nSubBuffers;
}
else
{
- Index = Buffer->nSubBuffers - Index;
+ int rv = Index + 1;
+ Index = Buffer->nSubBuffers - Index - 1;
// Prepended buffers
*DataPtr = Buffer->SubBuffers[Index].Data;
*Length = Buffer->SubBuffers[Index].PreLength;
- return Buffer->nSubBuffers - (Index - 1);
+ return rv;
}
}
end = ts + Interface->TimeoutDelay;
while( !gICMP_PingSlots[i].bArrived && now() < end) Threads_Yield();
- if(now() >= end)
+ if( !gICMP_PingSlots[i].bArrived )
return -1;
return (int)( now() - ts );
#include "buffer.h"
+enum eIPStack_AdapterTypes
+{
+ ADAPTERTYPE_ETHERNET_10M,
+ ADAPTERTYPE_ETHERNET_100M,
+ ADAPTERTYPE_ETHERNET_1G
+};
+
+// Checksum offloading
+#define ADAPTERFLAG_OFFLOAD_MAC (1 << 0)
+#define ADAPTERFLAG_OFFLOAD_IP4 (1 << 1)
+#define ADAPTERFLAG_OFFLOAD_IP6 (1 << 2)
+#define ADAPTERFLAG_OFFLOAD_TCP (1 << 3)
+#define ADAPTERFLAG_OFFLOAD_UDP (1 << 4)
+
typedef struct sIPStack_AdapterType tIPStack_AdapterType;
struct sIPStack_AdapterType
--- /dev/null
+
+#ifndef _IPSTACK__INIT_H_
+#define _IPSTACK__INIT_H_
+
+extern int ARP_Initialise();
+extern void UDP_Initialise();
+extern void TCP_Initialise();
+extern int IPv4_Initialise();
+extern int IPv6_Initialise();
+
+#endif
+
#include "link.h"
#include <api_drv_common.h>
#include "include/adapters.h"
+#include "interface.h"
// === CONSTANTS ===
-//! Default timeout value, 30 seconds
-#define DEFAULT_TIMEOUT (30*1000)
+//! Default timeout value, 5 seconds
+#define DEFAULT_TIMEOUT (5*1000)
// === IMPORTS ===
extern int IPv4_Ping(tInterface *Iface, tIPv4 Addr);
extern tVFS_Node gIP_AdaptersNode;
// === PROTOTYPES ===
-char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
+ int IPStack_Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
int IPStack_AddFile(tSocketFile *File);
tInterface *IPStack_AddInterface(const char *Device, const char *Name);
-char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos);
+ int IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *IPStack_Iface_FindDir(tVFS_Node *Node, const char *Name);
int IPStack_Iface_IOCtl(tVFS_Node *Node, int ID, void *Data);
// === GLOBALS ===
+tVFS_NodeType gIP_RootNodeType = {
+ .ReadDir = IPStack_Root_ReadDir,
+ .FindDir = IPStack_Root_FindDir,
+ .IOCtl = IPStack_Root_IOCtl
+};
tVFS_NodeType gIP_InterfaceNodeType = {
.ReadDir = IPStack_Iface_ReadDir,
.FindDir = IPStack_Iface_FindDir,
/**
* \brief Read from the IP Stack's Device Directory
*/
-char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos)
+int IPStack_Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
tInterface *iface;
- char *name;
ENTER("pNode iPos", Node, Pos);
// Routing Subdir
if( Pos == 0 ) {
- LEAVE('s', "routes");
- return strdup("routes");
+ strcpy(Dest, "routes");
+ return 0;
}
// Adapters
if( Pos == 1 ) {
- LEAVE('s', "adapters");
- return strdup("adapters");
+ strcpy(Dest, "adapters");
+ return 0;
}
// Pseudo Interfaces
if( Pos == 2 ) {
- LEAVE('s', "lo");
- return strdup("lo");
+ strcpy(Dest, "lo");
+ return 0;
}
Pos -= 3;
// Did we run off the end?
if(!iface) {
- LEAVE('n');
- return NULL;
- }
-
- name = malloc(4);
- if(!name) {
- Log_Warning("IPStack", "IPStack_Root_ReadDir - malloc error");
- LEAVE('n');
- return NULL;
+ LEAVE('i', -EINTERNAL);
+ return -EINVAL;
}
// Create the name
Pos = iface->Node.ImplInt;
- if(Pos < 10) {
- name[0] = '0' + Pos;
- name[1] = '\0';
- }
- else if(Pos < 100) {
- name[0] = '0' + Pos/10;
- name[1] = '0' + Pos%10;
- name[2] = '\0';
- }
- else {
- name[0] = '0' + Pos/100;
- name[1] = '0' + (Pos/10)%10;
- name[2] = '0' + Pos%10;
- name[3] = '\0';
- }
+ snprintf(Dest, FILENAME_MAX, "%i", Pos);
- LEAVE('s', name);
- // Return the pre-generated name
- return name;
+ LEAVE('i', 0);
+ return 0;
}
/**
iface->Next = NULL;
iface->Type = 0; // Unset type
iface->Address = iface->Name + nameLen + 1; // Address
+ memset(&iface->Route, 0, sizeof(iface->Route));
iface->Route.Network = iface->Address + IPStack_GetAddressSize(-1);
iface->Route.NextHop = iface->Route.Network + IPStack_GetAddressSize(-1);
/**
* \brief Read from an interface's directory
*/
-char *IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos)
+int IPStack_Iface_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
tSocketFile *file = gIP_FileTemplates;
while(Pos-- && file) {
file = file->Next;
}
- if(!file) return NULL;
+ if(!file)
+ return -EINVAL;
- return strdup(file->Name);
+ strncpy(Dest, file->Name, FILENAME_MAX);
+ return 0;
}
/**
--- /dev/null
+
+#ifndef _IPSTACK__INTERFACE_H_
+#define _IPSTACK__INTERFACE_H_
+
+extern tInterface gIP_LoopInterface;
+extern tVFS_NodeType gIP_RootNodeType;
+extern tInterface *IPStack_AddInterface(const char *Device, const char *Name);
+
+#endif
+
// TODO: Handle packet fragmentation
-
Log_Debug("IPv4", " From %i.%i.%i.%i to %i.%i.%i.%i",
hdr->Source.B[0], hdr->Source.B[1], hdr->Source.B[2], hdr->Source.B[3],
hdr->Destination.B[0], hdr->Destination.B[1], hdr->Destination.B[2], hdr->Destination.B[3]
// Routing
if(!iface)
{
+ #if 0
tMacAddr to;
tRoute *rt;
-
+
+
+ // TODO: Put this in another thread to avoid delays in the RX thread
Log_Debug("IPv4", "Route the packet");
// Drop the packet if the TTL is zero
if( hdr->TTL == 0 ) {
((tIPv4*)rt->NextHop)->B[2], ((tIPv4*)rt->NextHop)->B[3]);
Log_Warning("IPv4", "TODO: Implement forwarding with tIPStackBuffer");
// Link_SendPacket(rt->Interface->Adapter, IPV4_ETHERNET_ID, to, Length, Buffer);
+ #endif
return ;
}
*/
tInterface *IPv4_GetInterface(tAdapter *Adapter, tIPv4 Address, int Broadcast)
{
- tInterface *iface = NULL;
+ tInterface *iface = NULL, *zero_iface = NULL;
Uint32 netmask;
Uint32 addr, this;
LEAVE('p', iface);
return iface;
}
-
+
+ LOG("iface->Address = 0x%x", *(Uint32*)iface->Address);
+
+ if( *(Uint32*)iface->Address == 0 ) {
+ if( zero_iface ) {
+ Log_Notice("IPv4", "Multiple 0.0.0.0 interfaces on the same adapter, ignoring");
+ }
+ else {
+ zero_iface = iface;
+ LOG("Zero IF %p", iface);
+ }
+ continue ;
+ }
+
if( !Broadcast ) continue;
// Check for broadcast
return iface;
}
}
+
+ // Special case for intefaces that are being DHCP configured
+ // - If the interface address is 0.0.0.0, then if there is no match for the
+ // destination the packet is treated as if it was addressed to 0.0.0.0
+ if( zero_iface && Broadcast )
+ {
+ LOG("Using 0.0.0.0 interface with magic!");
+ LEAVE('p', zero_iface);
+ return zero_iface;
+ }
+
LEAVE('n');
return NULL;
}
{
tInterface *iface;
tIPv6Header *hdr = Buffer;
- int ret, dataLength;
+ int ret;
char *dataPtr;
Uint8 nextHeader;
// Process Options
nextHeader = hdr->NextHeader;
dataPtr = hdr->Data;
- dataLength = hdr->PayloadLength;
for( ;; )
{
struct {
void *data = IPStack_Buffer_CompactBuffer(Buffer, &len);
tEthernetHeader *hdr = (void*)data;
- int i;
- Uint32 checksum;
if(len < sizeof(tEthernetHeader)) {
Log_Log("Net Link", "Recieved an undersized packet (%i < %i)",
hdr->Dest.B[3], hdr->Dest.B[4], hdr->Dest.B[5],
ntohs(hdr->Type)
);
- checksum = *(Uint32*)&hdr->Data[len-sizeof(tEthernetHeader)-4];
+// Uint32 checksum = *(Uint32*)(data + len + 4);
//Log_Log("NET", "Checksum 0x%08x", checksum);
// TODO: Check checksum
// Check if there is a registered callback for this packet type
+ int i;
for( i = giRegisteredTypes; i--; )
{
if(gaRegisteredTypes[i].Type == ntohs(hdr->Type)) break;
#include <modules.h>
#include <fs_devfs.h>
#include "include/adapters.h"
+#include "interface.h"
+#include "init.h"
// === IMPORTS ===
-extern int ARP_Initialise();
-extern void UDP_Initialise();
-extern void TCP_Initialise();
-extern int IPv4_Initialise();
-extern int IPv6_Initialise();
-
-extern char *IPStack_Root_ReadDir(tVFS_Node *Node, int Pos);
-extern tVFS_Node *IPStack_Root_FindDir(tVFS_Node *Node, const char *Name);
-extern int IPStack_Root_IOCtl(tVFS_Node *Node, int ID, void *Data);
-extern tInterface gIP_LoopInterface;
-extern tInterface *IPStack_AddInterface(const char *Device, const char *Name);
extern tRoute *IPStack_AddRoute(const char *Interface, void *Network, int SubnetBits, void *NextHop, int Metric);
// === PROTOTYPES ===
// === GLOBALS ===
MODULE_DEFINE(0, VERSION, IPStack, IPStack_Install, NULL, NULL);
-tVFS_NodeType gIP_RootNodeType = {
- .ReadDir = IPStack_Root_ReadDir,
- .FindDir = IPStack_Root_FindDir,
- .IOCtl = IPStack_Root_IOCtl
-};
tDevFS_Driver gIP_DriverInfo = {
NULL, "ip",
{
// === PROTOTYPES ===
// - Routes directory
-char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos);
+ int IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *IPStack_RouteDir_FindDir(tVFS_Node *Node, const char *Name);
- int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
- int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName);
+tVFS_Node *IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags);
+ int IPStack_RouteDir_Unlink(tVFS_Node *Node, const char *OldName);
tRoute *_Route_FindExactRoute(int Type, void *Network, int Subnet, int Metric);
int _Route_ParseRouteName(const char *Name, void *Addr, int *SubnetBits, int *Metric);
int IPStack_RouteDir_IOCtl(tVFS_Node *Node, int ID, void *Data);
.ReadDir = IPStack_RouteDir_ReadDir,
.FindDir = IPStack_RouteDir_FindDir,
.MkNod = IPStack_RouteDir_MkNod,
- .Relink = IPStack_RouteDir_Relink,
+ .Unlink = IPStack_RouteDir_Unlink,
.IOCtl = IPStack_RouteDir_IOCtl
};
tVFS_Node gIP_RouteNode = {
/**
* \brief ReadDir for the /Devices/ip/routes/ directory
*/
-char *IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos)
+int IPStack_RouteDir_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
tRoute *rt;
for(rt = gIP_Routes; rt && Pos --; rt = rt->Next);
- if( !rt ) return NULL;
+ if( !rt ) return -EINVAL;
{
int addrlen = IPStack_GetAddressSize(rt->AddressType);
- int len = sprintf(NULL, "%i::%i:%i", rt->AddressType, rt->SubnetBits, rt->Metric) + addrlen*2;
- char buf[len+1];
int ofs;
- ofs = sprintf(buf, "%i:", rt->AddressType);
- ofs += Hex(buf+ofs, addrlen, rt->Network);
- sprintf(buf+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
- return strdup(buf);
+ ofs = sprintf(Dest, "%i:", rt->AddressType);
+ ofs += Hex(Dest+ofs, addrlen, rt->Network);
+ sprintf(Dest+ofs, ":%i:%i", rt->SubnetBits, rt->Metric);
+ return 0;
}
}
/**
* \brief Create a new route node
*/
-int IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
+tVFS_Node *IPStack_RouteDir_MkNod(tVFS_Node *Node, const char *Name, Uint Flags)
{
- if( Flags ) return -EINVAL;
- if( Threads_GetUID() != 0 ) return -EACCES;
+ if( Flags ) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if( Threads_GetUID() != 0 ) {
+ errno = EACCES;
+ return NULL;
+ }
int type = _Route_ParseRouteName(Name, NULL, NULL, NULL);
- if( type <= 0 ) return -EINVAL;
+ if( type <= 0 ) {
+ errno = EINVAL;
+ return NULL;
+ }
int size = IPStack_GetAddressSize(type);
Uint8 addrdata[size];
_Route_ParseRouteName(Name, addrdata, &subnet, &metric);
// Check for duplicates
- if( _Route_FindExactRoute(type, addrdata, subnet, metric) )
- return -EEXIST;
+ if( _Route_FindExactRoute(type, addrdata, subnet, metric) ) {
+ errno = EEXIST;
+ return NULL;
+ }
- IPStack_Route_Create(type, addrdata, subnet, metric);
+ tRoute *rt = IPStack_Route_Create(type, addrdata, subnet, metric);
+ rt->Node.ReferenceCount ++;
- return 0;
+ return &rt->Node;
}
/**
* \brief Rename / Delete a route
*/
-int IPStack_RouteDir_Relink(tVFS_Node *Node, const char *OldName, const char *NewName)
+int IPStack_RouteDir_Unlink(tVFS_Node *Node, const char *OldName)
{
tRoute *rt;
rt = _Route_FindExactRoute(type, addr, subnet, metric);
}
- if( NewName == NULL )
- {
- // Delete the route
- tRoute *prev = NULL;
- for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
-
- if(prev)
- prev->Next = rt->Next;
- else
- gIP_Routes = rt->Next;
- free(rt);
- }
- else
- {
- // Change the route
- int type = _Route_ParseRouteName(NewName, NULL, NULL, NULL);
- if(type <= 0) return -EINVAL;
- Uint8 addr[IPStack_GetAddressSize(type)];
- int subnet, metric;
- _Route_ParseRouteName(NewName, addr, &subnet, &metric);
+ // Delete the route
+ tRoute *prev = NULL;
+ for(tRoute *r = gIP_Routes; r && r != rt; prev = r, r = r->Next);
- return -ENOTIMPL;
- }
+ if(prev)
+ prev->Next = rt->Next;
+ else
+ gIP_Routes = rt->Next;
+ free(rt);
return 0;
}
int TCP_DeallocatePort(Uint16 Port);
// --- Server
tVFS_Node *TCP_Server_Init(tInterface *Interface);
-char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos);
+ int TCP_Server_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX]);
tVFS_Node *TCP_Server_FindDir(tVFS_Node *Node, const char *Name);
int TCP_Server_IOCtl(tVFS_Node *Node, int ID, void *Data);
void TCP_Server_Close(tVFS_Node *Node);
* \param Node Server node
* \param Pos Position (ignored)
*/
-char *TCP_Server_ReadDir(tVFS_Node *Node, int Pos)
+int TCP_Server_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
tTCPListener *srv = Node->ImplPtr;
tTCPConnection *conn;
- char *ret;
ENTER("pNode iPos", Node, Pos);
LOG("srv->NewConnections = %p", srv->NewConnections);
LOG("srv->ConnectionsTail = %p", srv->ConnectionsTail);
- ret = malloc(9);
- itoa(ret, conn->Node.ImplInt, 16, 8, '0');
- Log_Log("TCP", "Thread %i got '%s'", Threads_GetTID(), ret);
- LEAVE('s', ret);
- return ret;
+ itoa(Dest, conn->Node.ImplInt, 16, 8, '0');
+ Log_Log("TCP", "Thread %i got connection '%s'", Threads_GetTID(), Dest);
+ LEAVE('i', 0);
+ return 0;
}
/**
#include <Input/Keyboard/include/keyboard.h>
#include "keymap_int.h"
#include "layout_kbdus.h"
+#include <hal_proc.h>
#define USE_KERNEL_MAGIC 1
// === PROTOTYPES ===
int Keyboard_Install(char **Arguments);
-void Keyboard_Cleanup(void);
+ int Keyboard_Cleanup(void);
// - Internal
tKeymap *Keyboard_LoadMap(const char *Name);
void Keyboard_FreeMap(tKeymap *Keymap);
/**
* \brief Pre-unload cleanup function
*/
-void Keyboard_Cleanup(void)
+int Keyboard_Cleanup(void)
{
// TODO: Do I need this?
+ return 0;
}
// --- Map Management ---
Uint32 flag;
Uint8 layer;
+ if( !Source ) {
+ Log_Error("Keyboard", "Passed NULL handle");
+ return ;
+ }
+ if( !Source->Node ) {
+ Log_Error("Keyboard", "Passed handle with NULL node");
+ return ;
+ }
+
bPressed = !(HIDKeySym & (1 << 31));
HIDKeySym &= 0x7FFFFFFF;
case 'p': Threads_Dump(); return;
// Heap Statistics
case 'h': Heap_Stats(); return;
+ // PMem Statistics
+ case 'm': MM_DumpStatistics(); return;
// Dump Structure
case 's': return;
}
// === PROTOTYPES ===
int Mouse_Install(char **Arguments);
-void Mouse_Cleanup(void);
+ int Mouse_Cleanup(void);
// - "User" side
-char *Mouse_Root_ReadDir(tVFS_Node *Node, int Pos);
+ int Mouse_Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *Mouse_Root_FindDir(tVFS_Node *Node, const char *Name);
int Mouse_Dev_IOCtl(tVFS_Node *Node, int ID, void *Data);
size_t Mouse_Dev_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Data);
/**
* \brief Pre-unload cleanup function
*/
-void Mouse_Cleanup(void)
+int Mouse_Cleanup(void)
{
+ return 0;
}
// --- VFS Interface ---
-char *Mouse_Root_ReadDir(tVFS_Node *Node, int Pos)
+int Mouse_Root_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
- if( Pos != 0 ) return NULL;
- return strdup("system");
+ if( Pos != 0 )
+ return -EINVAL;
+ strcpy(Dest, "system");
+ return 0;
}
tVFS_Node *Mouse_Root_FindDir(tVFS_Node *Node, const char *Name)
void KBC8042_KeyboardHandler(int IRQ, void *Ptr)
{
- Uint8 scancode;
-
-// Log("KBC8042_KeyboardHandler: (IRQ=%i, Ptr=%p)", IRQ, Ptr);
-
- scancode = inb(0x60);
+ Uint8 scancode = inb(0x60);
KB_HandleScancode( scancode );
}
return ;
}
- while( --timeout && gpPL050_KeyboardBase[1] & PL050_TXBUSY );
+ while( --timeout && (gpPL050_KeyboardBase[1] & PL050_TXBUSY) );
if(timeout)
gpPL050_KeyboardBase[2] = Data;
else
CPPFLAGS += -I$(ACESSDIR)/KernelLand/Modules
CPPFLAGS += -DARCH=$(ARCH) -DARCH_is_$(ARCH) -DARCHDIR_is_$(ARCHDIR)
CPPFLAGS += $(_CPPFLAGS)
-CPPFLAGS += $(LIBINCLUDES)
+CPPFLAGS += $(LIBINCLUDES) -ffreestanding
CFLAGS := -std=gnu99 -Wall -fno-stack-protector -g -O3
CFLAGS += -Werror
install: $(BIN)
ifneq ($(BUILDTYPE),static)
- @$(xMKDIR) $(DISTROOT)/Modules/$(ARCH); true
- $(xCP) $(BIN) $(DISTROOT)/Modules/$(ARCH)/$(NAME).kmd
+ @$(xMKDIR) $(DISTROOT)/$(ARCH)/Modules; true
+ @gzip -c $(BIN) > $(BIN).gz
+ $(xCP) $(BIN).gz $(DISTROOT)/$(ARCH)/Modules/$(NAME).kmd.gz
else
+ @true
endif
--- /dev/null
+#
+# Acess2 Intel E1000 driver
+#
+
+OBJ = e1000.o
+NAME = E1000
+
+-include ../Makefile.tpl
+
--- /dev/null
+/*
+ * Acess2 E1000 Network Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * e1000.c
+ * - Intel E1000 Network Card Driver (core)
+ */
+#define DEBUG 1
+#define VERSION VER2(0,1)
+#include <acess.h>
+#include "e1000.h"
+#include <modules.h>
+#include <drv_pci.h>
+#include <IPStack/include/adapters_api.h>
+
+// === PROTOTYPES ===
+ int E1000_Install(char **Arguments);
+ int E1000_Cleanup(void);
+tIPStackBuffer *E1000_WaitForPacket(void *Ptr);
+ int E1000_SendPacket(void *Ptr, tIPStackBuffer *Buffer);
+void E1000_IRQHandler(int Num, void *Ptr);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, E1000, E1000_Install, E1000_Cleanup, NULL);
+tIPStack_AdapterType gE1000_AdapterType = {
+ .Name = "E1000",
+ .Type = 0, // TODO: Differentiate differnet wire protos and speeds
+ .Flags = 0, // TODO: IP checksum offloading, MAC checksum offloading etc
+ .SendPacket = E1000_SendPacket,
+ .WaitForPacket = E1000_WaitForPacket
+ };
+
+// === CODE ===
+int E1000_Install(char **Arguments)
+{
+ for( int id = -1; (id = PCI_GetDevice(0x8086, 0x100E, id)) != -1; )
+ {
+
+ }
+ return MODULE_ERR_NOTNEEDED;
+}
+
+int E1000_Cleanup(void)
+{
+ return 0;
+}
+
+tIPStackBuffer *E1000_WaitForPacket(void *Ptr)
+{
+ return NULL;
+}
+
+int E1000_SendPacket(void *Ptr, tIPStackBuffer *Buffer)
+{
+ return -1;
+}
+
+void E1000_IRQHandler(int Num, void *Ptr)
+{
+}
--- /dev/null
+/*
+ * Acess2 E1000 Network Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * e1000.h
+ * - Driver core header
+ */
+#ifndef _E1000_H_
+#define _E1000_H_
+
+
+
+#endif
+
* Acess2 VIA Rhine II Driver (VT6102)
* - By John Hodge (thePowersGang)
*/
-#define DEBUG 0
+#define DEBUG 1
#define VERSION ((0<<8)|10)
#include <acess.h>
#include <modules.h>
#include "rhine2_hw.h"
#include <IPStack/include/adapters_api.h>
+#define DESC_SIZE 16
+#define N_RX_DESCS 16
+#define RX_BUF_SIZE 1024
+#define N_RX_BUF_PER_PAGE (PAGE_SIZE/RX_BUF_SIZE)
+#define N_RX_BUF_PAGES ((N_RX_DESCS*RX_BUF_SIZE)/PAGE_SIZE)
+#define N_TX_DESCS ((PAGE_SIZE/DESC_SIZE)-N_RX_DESCS)
+
+#define CR0_BASEVAL (CR0_STRT|CR0_TXON|CR0_RXON)
+
// === CONSTANTS ===
#define VENDOR_ID 0x1106
#define DEVICE_ID 0x3065
Uint8 IRQ;
tSemaphore ReadSemaphore;
+ tSemaphore SendSemaphore;
- Uint32 RXBuffersPhys;
- void *RXBuffers;
+ struct {
+ Uint32 Phys;
+ void *Virt;
+ } RXBuffers[N_RX_BUF_PAGES];
Uint32 DescTablePhys;
void *DescTable;
+
+ struct sTXDesc *TXDescs;
+ int NextTX;
+ int nFreeTX;
- struct sTXDesc *FirstTX;
- struct sTXDesc *LastTX; // Most recent unsent packet
-
- struct sRXDesc *FirstRX; // Most recent unread packet
- struct sRXDesc *LastRX; // End of RX descriptor queue
+ struct sRXDesc *NextRX; // Most recent unread packet
void *IPHandle;
Uint8 MacAddr[6];
// === PROTOTYPES ===
int Rhine2_Install(char **Options);
+void Rhine2_int_InitialiseCard(tCard *Card);
tIPStackBuffer *Rhine2_WaitPacket(void *Ptr);
int Rhine2_SendPacket(void *Ptr, tIPStackBuffer *Buffer);
-void Rhine2_IRQHandler(int Num);
+void Rhine2_IRQHandler(int Num, void *Pt);
// --- Helpers ---
struct sRXDesc *Rhine2_int_GetDescFromPhys(tCard *Card, Uint32 Addr);
void *Rhine2_int_GetBufferFromPhys(tCard *Card, Uint32 Addr);
void Rhine2_int_FreeRXDesc(void *Desc, size_t, size_t, const void*);
-struct sTXDesc *Rhine2_int_AllocTXDesc(tCard *Card);
-// --- IO ---
-void _WriteDWord(tCard *Card, int Offset, Uint32 Value);
// === GLOBALS ===
MODULE_DEFINE(0, VERSION, VIARhineII, Rhine2_Install, NULL, NULL);
tCard *card;
giRhine2_CardCount = PCI_CountDevices(VENDOR_ID, DEVICE_ID);
- Log_Debug("Rhine2", "%i cards", giRhine2_CardCount);
-
+ Log_Debug("Rhine2", "giRhine2_CardCount = %i", giRhine2_CardCount);
if( giRhine2_CardCount == 0 ) return MODULE_ERR_NOTNEEDED;
gaRhine2_Cards = calloc( giRhine2_CardCount, sizeof(tCard) );
LOG("BAR4 = 0x%08x", PCI_GetBAR(id, 4));
LOG("BAR5 = 0x%08x", PCI_GetBAR(id, 5));
-// card->IOBase = base;
+ card->IOBase = PCI_GetBAR(id, 0);
+ if( !(card->IOBase & 1) ) {
+ // Oops?
+ Log_Warning("Rhine2", "BAR0 is not in IO space");
+ continue ;
+ }
+ card->IOBase &= ~1;
card->IRQ = PCI_GetIRQ( id );
// Install IRQ Handler
-// IRQ_AddHandler(card->IRQ, Rhine2_IRQHandler);
-
+ IRQ_AddHandler(card->IRQ, Rhine2_IRQHandler, card);
-
-// Log_Log("PCnet3", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
-// i, card->IOBase, card->IRQ,
-// card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
-// card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
-// );
+ Rhine2_int_InitialiseCard(card);
+
+ card->IPHandle = IPStack_Adapter_Add(&gRhine2_AdapterType, card, card->MacAddr);
+
+ Log_Log("Rhine2", "Card %i 0x%04x, IRQ %i %02x:%02x:%02x:%02x:%02x:%02x",
+ i, card->IOBase, card->IRQ,
+ card->MacAddr[0], card->MacAddr[1], card->MacAddr[2],
+ card->MacAddr[3], card->MacAddr[4], card->MacAddr[5]
+ );
i ++;
}
return MODULE_ERR_OK;
}
+void Rhine2_int_InitialiseCard(tCard *Card)
+{
+ tPAddr phys;
+
+ Card->MacAddr[0] = inb(Card->IOBase + REG_PAR0);
+ Card->MacAddr[1] = inb(Card->IOBase + REG_PAR1);
+ Card->MacAddr[2] = inb(Card->IOBase + REG_PAR2);
+ Card->MacAddr[3] = inb(Card->IOBase + REG_PAR3);
+ Card->MacAddr[4] = inb(Card->IOBase + REG_PAR4);
+ Card->MacAddr[5] = inb(Card->IOBase + REG_PAR5);
+
+ LOG("Resetting card");
+ outb(Card->IOBase + REG_CR1, CR1_SFRST);
+ // TODO: Timeout
+ while( inb(Card->IOBase + REG_CR1) & CR1_SFRST ) ;
+
+ LOG("Allocaating RX buffers");
+ // Allocate memory for things
+ for( int i = 0; i < N_RX_BUF_PAGES; i ++ )
+ {
+ Card->RXBuffers[i].Virt = (void*)MM_AllocDMA(1, 32, &phys);
+ Card->RXBuffers[i].Phys = phys;
+ }
+
+ LOG("Allocating and filling RX/TX Descriptors");
+ Card->DescTable = (void*)MM_AllocDMA(1, 32, &phys);
+ Card->DescTablePhys = phys;
+
+ // Initialise RX Descriptors
+ struct sRXDesc *rxdescs = Card->DescTable;
+ for( int i = 0; i < N_RX_DESCS; i ++ )
+ {
+ rxdescs[i].RSR = 0;
+ rxdescs[i].BufferSize = RX_BUF_SIZE;
+ rxdescs[i].RXBufferStart = Card->RXBuffers[i/N_RX_BUF_PER_PAGE].Phys
+ + (i % N_RX_BUF_PER_PAGE) * RX_BUF_SIZE;
+ rxdescs[i].RDBranchAddress = Card->DescTablePhys + (i+1) * DESC_SIZE;
+ rxdescs[i].Length = (1 << 15); // set OWN
+ LOG("RX Desc %p = {Buf:0x%8x, Next:0x%x}", rxdescs,
+ rxdescs[i].RXBufferStart, rxdescs[i].RDBranchAddress
+ );
+ }
+ rxdescs[ N_RX_DESCS - 1 ].RDBranchAddress = Card->DescTablePhys;
+ Card->NextRX = &rxdescs[0];
+
+ Card->TXDescs = (void*)(rxdescs + N_RX_DESCS);
+ memset(Card->TXDescs, 0, sizeof(struct sTXDesc)*N_TX_DESCS);
+ for( int i = 0; i < N_TX_DESCS; i ++ )
+ {
+ Card->TXDescs[i].TDBranchAddress = Card->DescTablePhys + (N_RX_DESCS + i + 1) * DESC_SIZE;
+ }
+ Card->TXDescs[N_TX_DESCS-1].TDBranchAddress = Card->DescTablePhys + N_RX_DESCS * DESC_SIZE;
+ Card->nFreeTX = N_TX_DESCS;
+ Card->NextTX = 0;
+
+ // - Initialise card state
+ LOG("Initialising card state");
+ outb(Card->IOBase + REG_IMR0, 0xFF);
+ outb(Card->IOBase + REG_IMR1, 0xFF);
+ outd(Card->IOBase + REG_CUR_RX_DESC, Card->DescTablePhys);
+ outd(Card->IOBase + REG_CUR_TX_DESC, Card->DescTablePhys + N_RX_DESCS * DESC_SIZE);
+
+ outb(Card->IOBase + REG_TCR, TCR_TRSF(4));
+
+ LOG("RX started");
+ outb(Card->IOBase + REG_CR0, CR0_BASEVAL);
+ outb(Card->IOBase + REG_CR1, 0); // Disabled TX polling only?
+
+ LOG("ISR state: %02x %02x", inb(Card->IOBase + REG_ISR0), inb(Card->IOBase + REG_ISR1));
+}
+
// --- File Functions ---
tIPStackBuffer *Rhine2_WaitPacket(void *Ptr)
{
ENTER("pPtr", Ptr);
+ LOG("CR0 state: %02x", inb(card->IOBase + REG_CR0));
if( Semaphore_Wait( &card->ReadSemaphore, 1 ) != 1 )
{
LEAVE('n');
}
nDesc = 0;
- desc = card->FirstRX;
- while( desc->BufferSize & (1 << 15) )
+ desc = card->NextRX;
+ while( !(desc->Length & (1 << 15)) )
{
+// LOG("desc(%p) = {RSR:%04x,Length:%04x,BufferSize:%04x,RXBufferStart:%08x,RDBranchAddress:%08x}",
+// desc, desc->RSR, desc->Length, desc->BufferSize, desc->RXBufferStart, desc->RDBranchAddress);
+ // TODO: This kinda expensive call can be changed for an increment, but cbf
desc = Rhine2_int_GetDescFromPhys(card, desc->RDBranchAddress);
nDesc ++;
}
LOG("%i descriptors in packet", nDesc);
ret = IPStack_Buffer_CreateBuffer(nDesc);
- desc = card->FirstRX;
- while( desc->BufferSize & (1 << 15) )
+ desc = card->NextRX;
+ while( !(desc->Length & (1 << 15)) )
{
void *data = Rhine2_int_GetBufferFromPhys(card, desc->RXBufferStart);
IPStack_Buffer_AppendSubBuffer(ret,
);
desc = Rhine2_int_GetDescFromPhys(card, desc->RDBranchAddress);
}
- card->FirstRX = desc;
+ card->NextRX = desc;
LEAVE('p', ret);
return ret;
tCard *card = Ptr;
size_t len;
const void *data;
+ int nDescs, first_desc_id;
+ struct sTXDesc *desc = NULL;
struct sTXDesc *first_desc = NULL;
struct sTXDesc *last_desc = NULL;
ENTER("pPtr pBuffer", Ptr, Buffer);
+ #if 0
// Iterate buffers
+ nDescs = 0;
+ for( int id = -1; -1 != (id = IPStack_Buffer_GetBuffer(Buffer, id, &len, &data)); )
+ {
+ if( ((tVAddr)data & (PAGE_SIZE-1)) + len > PAGE_SIZE )
+ nDescs ++;
+ nDescs ++;
+ }
+ if( nDescs == 0 ) {
+ LEAVE('i', -1);
+ return -1;
+ }
+
+ LOG("%i descriptors needed", nDescs);
+
+ if( card->nFreeTX < nDescs ) {
+ // Oops... wait?
+ // TODO: Semaphore instead?
+ LEAVE('i', 1);
+ return 1;
+ }
+
+ first_desc_id = card->NextTX;
+ card->NextTX = (card->NextTX + nDescs) % N_TX_DESCS;
+
+ desc = card->TXDescs + first_desc_id;
+
+ nDescs = 0;
for( int id = -1; -1 != (id = IPStack_Buffer_GetBuffer(Buffer, id, &len, &data)); )
{
tPAddr pdata = MM_GetPhysAddr( (tVAddr)data );
- struct sTXDesc *desc;
#if PHYS_BITS > 32
if( pdata >> 32 ) {
// TODO: re-map
+ Log_Warning("Rhine2", "TODO: Bounce-buffer >32 pbit buffers");
}
#endif
+
+ if( (pdata & (PAGE_SIZE-1)) + len > PAGE_SIZE )
+ {
+ // Need to split into to descriptors
+ Log_Warning("Rhine2", "TODO: Split cross-page buffers");
+ }
- desc = Rhine2_int_AllocTXDesc(card);
- if(!last_desc)
- first_desc = desc;
- else
- last_desc->TDBranchAddress = MM_GetPhysAddr( (tVAddr)desc );
+ LOG("Buffer %i (%p+0x%x) placed in %p", id-1, data, len, desc);
+ // TODO: Rhine I requires 4-byte alignment (fsck that, I don't have one)
+
desc->TXBufferStart = pdata;
- desc->BufferSize = len;
+ desc->BufferSize = len | (1 << 15);
// TODO: TCR
desc->TCR = 0;
- desc->TDBranchAddress = 0;
+ if( nDescs == 0 )
+ desc->TSR = 0; // OWN will be set below
+ else
+ desc->TSR = TD_TSR_OWN;
- last_desc = desc;
+ nDescs ++;
+ if(first_desc_id + nDescs == N_TX_DESCS)
+ desc = card->TXDescs;
+ else
+ desc ++;
}
+ #else
+ data = IPStack_Buffer_CompactBuffer(Buffer, &len);
- if( !first_desc ) {
- LEAVE('i', -1);
- return -1;
- }
-
- first_desc->TCR |= TD_TCR_STP;
- last_desc->TCR |= TD_TCR_EDP;
-
- if( card->LastTX )
- card->LastTX->TDBranchAddress = MM_GetPhysAddr( (tVAddr)first_desc );
- else {
- card->FirstTX = first_desc;
- card->LastTX = first_desc;
- _WriteDWord(card, REG_CUR_TX_DESC, MM_GetPhysAddr( (tVAddr)first_desc ));
- }
+ nDescs = 1;
+ first_desc_id = card->NextTX;
+ card->NextTX = (card->NextTX + nDescs) % N_TX_DESCS;
+ desc = card->TXDescs + first_desc_id;
+
+ desc->TXBufferStart = MM_GetPhysAddr( data );
+ desc->BufferSize = len | (1 << 15);
+ desc->TSR = 0;
+ desc->TCR = 0;
+ #endif
+
+ first_desc = card->TXDescs + first_desc_id;
+ last_desc = desc;
- // TODO: Wait until the packet has sent, then clean up
+ first_desc->TCR |= TD_TCR_STP;
+ last_desc->TCR |= TD_TCR_EDP|TD_TCR_IC;
+// last_desc->BufferSize &= ~(1 << 15);
+
+ first_desc->TSR |= TD_TSR_OWN;
+
+ LOG("%i descriptors allocated, first = %p, last = %p", nDescs, first_desc, last_desc);
+
+
+ LOG("Waiting for TX to complete");
+ outb(card->IOBase + REG_CR0, CR0_TDMD|CR0_BASEVAL);
+ Semaphore_Wait(&card->SendSemaphore, 1);
+
+ #if 1
+ free((void*)data);
+ #endif
+ LEAVE('i', 0);
return 0;
}
-void Rhine2_IRQHandler(int Num)
+void Rhine2_IRQHandler(int Num, void *Ptr)
{
+ tCard *card = Ptr;
+ Uint8 isr0 = inb(card->IOBase + REG_ISR0);
+ Uint8 isr1 = inb(card->IOBase + REG_ISR1);
+
+ if( isr0 == 0 ) return ;
+
+ LOG("ISR0 = 0x%02x, ISR1 = 0x%02x", isr0, isr1);
+
+ if( isr0 & ISR0_PRX )
+ {
+ LOG("PRX");
+ Semaphore_Signal(&card->ReadSemaphore, 1);
+ }
+
+ if( isr0 & ISR0_PTX )
+ {
+ LOG("PTX");
+ Semaphore_Signal(&card->SendSemaphore, 1);
+ }
+ if( isr0 & ISR0_TXE )
+ {
+ LOG("TX Error... oops");
+ Semaphore_Signal(&card->SendSemaphore, 1);
+ }
+
+ if( isr0 & ISR0_TU )
+ {
+ LOG("Transmit buffer underflow");
+ }
+
+ LOG("Acking interrupts");
+ outb(card->IOBase + REG_ISR0, isr0);
+ outb(card->IOBase + REG_ISR1, isr1);
}
// --- Helpers ---
struct sRXDesc *Rhine2_int_GetDescFromPhys(tCard *Card, Uint32 Addr)
{
- return NULL;
+ if( Card->DescTablePhys > Addr ) return NULL;
+ if( Card->DescTablePhys + PAGE_SIZE <= Addr ) return NULL;
+ if( Addr & 15 ) return NULL;
+ return (struct sRXDesc*)Card->DescTable + ((Addr & (PAGE_SIZE-1)) / 16);
}
void *Rhine2_int_GetBufferFromPhys(tCard *Card, Uint32 Addr)
{
+ for( int i = 0; i < N_RX_BUF_PAGES; i ++ )
+ {
+ if( Card->RXBuffers[i].Phys > Addr ) continue;
+ if( Card->RXBuffers[i].Phys + PAGE_SIZE <= Addr ) continue;
+ return Card->RXBuffers[i].Virt + (Addr & (PAGE_SIZE-1));
+ }
return NULL;
}
-void Rhine2_int_FreeRXDesc(void *Desc, size_t u1, size_t u2, const void *u3)
-{
-
-}
-
-struct sTXDesc *Rhine2_int_AllocTXDesc(tCard *Card)
+void Rhine2_int_FreeRXDesc(void *Ptr, size_t u1, size_t u2, const void *u3)
{
- return NULL;
-}
+ struct sRXDesc *desc = Ptr;
-// --- IO ---
-void _WriteDWord(tCard *Card, int Offset, Uint32 Value)
-{
+ LOG("Descriptor %p returned to card", desc);
+ desc->RSR = 0;
+ desc->Length = (1 << 15); // Reset OWN
}
+
#define TCR_RSVD1 (1 << 4) // reserved
#define TCR_TRSF(v) (((v)&7)<<5) // Transmit FIFO threshold
+#define CR0_INIT (1 << 0)
+#define CR0_STRT (1 << 1)
+#define CR0_STOP (1 << 2)
+#define CR0_RXON (1 << 3)
+#define CR0_TXON (1 << 4)
+#define CR0_TDMD (1 << 5)
+#define CR0_RDMD (1 << 6)
+#define CR0_RESV (1 << 7) // reserved
+
+#define CR1_EREN (1 << 0) // Early recieve enable
+#define CR1_RESV0 (1 << 1)
+#define CR1_FDX (1 << 2) // Full/Half-duplex selector
+#define CR1_DPOLL (1 << 3) // Disable automatic polling
+#define CR1_RESV1 (1 << 4)
+#define CR1_TDMD (1 << 5)
+#define CR1_RDMD (1 << 6)
+#define CR1_SFRST (1 << 7) // Software reset
+
+#define ISR0_PRX (1 << 0) // Packet recieved
+#define ISR0_PTX (1 << 1) // Packet transmitted successfully
+#define ISR0_RXE (1 << 2) // RX Error
+#define ISR0_TXE (1 << 3) // TX Error
+#define ISR0_TU (1 << 4) // Transmit buffer underflow
+#define ISR0_RU (1 << 5) // Recieve buffer link error
+#define ISR0_BE (1 << 6) // PCI Bus error
+#define ISR0_CNT (1 << 7) // CRC error / missed packet counter overflow
+
+#define ISR1_ERI (1 << 0) // Early recieve interrupt
+#define ISR1_UDFI (1 << 1) // TX FIFO underflow event
+#define ISR1_OVFI (1 << 2) // Recieve overflow
+#define ISR1_PKTR (1 << 3) // FIFO overflow (?"next packet race with current packet")
+#define ISR1_NORBF (1 << 4) // No more recieve buffers avaiable (overflow essentialy)
+#define ISR1_ABTI (1 << 5) // Transmission abort due to excessive collisions
+#define ISR1_SRCI (1 << 6) // Port state change
+#define ISR1_GENI (1 << 7) // General purpose interrupt
+
// TODO: Other Regs?
struct sRXDesc
Uint16 _resvd;
Uint32 RXBufferStart;
Uint32 RDBranchAddress; // ? - I'm guessing it's the next descriptor in the chain
-};
+} PACKED;
#define RSR_RERR (1 << 0) // Receiver error
#define RSR_CRC (1 << 1) // CRC Error
Uint8 _resvd;
Uint32 TXBufferStart;
Uint32 TDBranchAddress; // Bit 0: Disable interrupt
-};
+} PACKED;
#define TD_TCR_CRC (1 << 0) // Disable CRC generation
#define TD_TCR_STP (1 << 5) // First descriptor in packet
#define TD_TCR_EDP (1 << 6) // Last descriptor in packet
#define TD_TCR_IC (1 << 7) // Interrupt when transmitted
+#define TD_TSR_OWN (1 << 31)
+
#endif
#
#
-OBJ = main.o io.o mbr.o
+OBJ = main.o io.o
NAME = ATA
-include ../Makefile.tpl
// Needed out of io.c because it's the max for Read/WriteDMA
#define MAX_DMA_SECTORS (0x1000 / SECTOR_SIZE)
-// === STRUCTURES ===
-typedef struct
-{
- Uint8 BootCode[0x1BE];
- struct {
- Uint8 Boot;
- Uint8 Unused1; // Also CHS Start
- Uint16 StartHi; // Also CHS Start
- Uint8 SystemID;
- Uint8 Unused2; // Also CHS Length
- Uint16 LengthHi; // Also CHS Length
- Uint32 LBAStart;
- Uint32 LBALength;
- } __attribute__ ((packed)) Parts[4];
- Uint16 BootFlag; // = 0xAA 55
-} __attribute__ ((packed)) tMBR;
-
-typedef struct
-{
- Uint64 Start;
- Uint64 Length;
- char Name[4];
- tVFS_Node Node;
-} tATA_Partition;
-
-typedef struct
-{
- Uint64 Sectors;
- char Name[2];
- tVFS_Node Node;
- int NumPartitions;
- tATA_Partition *Partitions;
-} tATA_Disk;
-
-// === GLOBALS ===
-extern tATA_Disk gATA_Disks[];
-
// === FUNCTIONS ===
-// --- Common ---
-extern void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
-
-// --- MBR Parsing ---
-extern void ATA_ParseMBR(int Disk, tMBR *MBR);
-
// --- IO Functions ---
extern int ATA_SetupIO(void);
extern Uint64 ATA_GetDiskSize(int Disk);
#include <modules.h> // Needed for error codes
#include <drv_pci.h>
#include "common.h"
+#include <events.h>
+#include <timers.h>
// === MACROS ===
#define IO_DELAY() do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
int gATA_IRQPri = 14;
int gATA_IRQSec = 15;
volatile int gaATA_IRQs[2] = {0};
+tThread *gATA_WaitingThreads[2];
// - Locks to avoid tripping
tMutex glaATA_ControllerLock[2];
// - Buffers!
-Uint8 gATA_Buffers[2][(MAX_DMA_SECTORS+0xFFF)&~0xFFF] __attribute__ ((section(".padata")));
+void *gATA_Buffers[2];
// - PRDTs
tPRDT_Ent gATA_PRDTs[2] = {
{0, 512, IDE_PRDT_LAST},
IRQ_AddHandler( gATA_IRQPri, ATA_IRQHandlerPri, NULL );
IRQ_AddHandler( gATA_IRQSec, ATA_IRQHandlerSec, NULL );
- gATA_PRDTs[0].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[0] );
- gATA_PRDTs[1].PBufAddr = MM_GetPhysAddr( (tVAddr)&gATA_Buffers[1] );
+ tPAddr paddr;
+ gATA_Buffers[0] = (void*)MM_AllocDMA(1, 32, &paddr);
+ gATA_PRDTs[0].PBufAddr = paddr;
+ gATA_Buffers[1] = (void*)MM_AllocDMA(1, 32, &paddr);
+ gATA_PRDTs[1].PBufAddr = paddr;
LOG("gATA_PRDTs = {PBufAddr: 0x%x, PBufAddr: 0x%x}", gATA_PRDTs[0].PBufAddr, gATA_PRDTs[1].PBufAddr);
- gaATA_PRDT_PAddrs[0] = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[0] );
- LOG("gaATA_PRDT_PAddrs[0] = 0x%x", gaATA_PRDT_PAddrs[0]);
+ // TODO: Ensure that this is within 32-bits
+ gaATA_PRDT_PAddrs[0] = MM_GetPhysAddr( &gATA_PRDTs[0] );
+ gaATA_PRDT_PAddrs[1] = MM_GetPhysAddr( &gATA_PRDTs[1] );
+ LOG("gaATA_PRDT_PAddrs = {0x%P, 0x%P}", gaATA_PRDT_PAddrs[0], gaATA_PRDT_PAddrs[1]);
+ #if PHYS_BITS > 32
+ if( gaATA_PRDT_PAddrs[0] >> 32 || gaATA_PRDT_PAddrs[1] >> 32 ) {
+ Log_Error("ATA", "Physical addresses of PRDTs are not in 32-bits (%P and %P)",
+ gaATA_PRDT_PAddrs[0], gaATA_PRDT_PAddrs[1]);
+ LEAVE('i', MODULE_ERR_MISC);
+ return MODULE_ERR_MISC;
+ }
+ #endif
ATA_int_BusMasterWriteDWord(4, gaATA_PRDT_PAddrs[0]);
-
- gaATA_PRDT_PAddrs[1] = MM_GetPhysAddr( (tVAddr)&gATA_PRDTs[1] );
- LOG("gaATA_PRDT_PAddrs[1] = 0x%x", gaATA_PRDT_PAddrs[1]);
ATA_int_BusMasterWriteDWord(12, gaATA_PRDT_PAddrs[1]);
// Enable controllers
return 0;
}
-/**
- * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
- * \return Boolean Failure
- */
-int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+int ATA_DoDMA(Uint8 Disk, Uint64 Address, Uint Count, int bWrite, void *Buffer)
{
int cont = (Disk>>1)&1; // Controller ID
int disk = Disk & 1;
Uint16 base;
- Sint64 timeoutTime;
+ int bUseBounceBuffer;
- ENTER("iDisk XAddress iCount pBuffer", Disk, Address, Count, Buffer);
+ ENTER("iDisk XAddress iCount bbWrite pBuffer", Disk, Address, Count, bWrite, Buffer);
// Check if the count is small enough
if(Count > MAX_DMA_SECTORS) {
- Log_Warning("ATA", "Passed too many sectors for a bulk DMA read (%i > %i)",
+ Log_Warning("ATA", "Passed too many sectors for a bulk DMA (%i > %i)",
Count, MAX_DMA_SECTORS);
LEAVE('i');
return 1;
// Set Size
gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
+
+ // Detemine if the transfer can be done directly
+ tPAddr buf_ps = MM_GetPhysAddr(Buffer);
+ tPAddr buf_pe = MM_GetPhysAddr((char*)Buffer + Count * SECTOR_SIZE - 1);
+ if( buf_pe == buf_ps + Count * SECTOR_SIZE - 1 ) {
+ // Contiguous, nice
+ #if PHYS_BITS > 32
+ if( buf_pe >> 32 ) {
+ // Over 32-bits, need to copy anyway
+ bUseBounceBuffer = 1;
+ LOG("%P over 32-bit, using bounce buffer", buf_pe);
+ }
+ #endif
+ }
+ else {
+ // TODO: Handle splitting the read into two?
+ bUseBounceBuffer = 1;
+ LOG("%P + 0x%x != %P, using bounce buffer", buf_ps, Count * SECTOR_SIZE, buf_pe);
+ }
+
+ // Set up destination / source buffers
+ if( bUseBounceBuffer ) {
+ gATA_PRDTs[cont].PBufAddr = MM_GetPhysAddr(gATA_Buffers[cont]);
+ if( bWrite )
+ memcpy(gATA_Buffers[cont], Buffer, Count * SECTOR_SIZE);
+ }
+ else {
+ gATA_PRDTs[cont].PBufAddr = MM_GetPhysAddr(Buffer);
+ }
// Get Port Base
base = ATA_GetBasePort(Disk);
// Reset IRQ Flag
gaATA_IRQs[cont] = 0;
+
+ // TODO: What the ____ does this do?
#if 1
if( cont == 0 ) {
outb(IDE_PRI_CTRL, 4);
LOG("gATA_PRDTs[%i].Bytes = %i", cont, gATA_PRDTs[cont].Bytes);
if( Address > 0x0FFFFFFF )
- outb(base+0x07, HDD_DMA_R48); // Read Command (LBA48)
+ outb(base+0x07, bWrite ? HDD_DMA_W48 : HDD_DMA_R48); // Command (LBA48)
else
- outb(base+0x07, HDD_DMA_R28); // Read Command (LBA28)
+ outb(base+0x07, bWrite ? HDD_DMA_W28 : HDD_DMA_R28); // Command (LBA28)
+ // Intialise timeout timer
+ Threads_ClearEvent(THREAD_EVENT_SHORTWAIT|THREAD_EVENT_TIMER);
+ tTimer *timeout = Time_AllocateTimer(NULL, NULL);
+ Time_ScheduleTimer(timeout, ATA_TIMEOUT);
+ gATA_WaitingThreads[cont] = Proc_GetCurThread();
+
// Start transfer
- ATA_int_BusMasterWriteByte( cont * 8, 9 ); // Read and start
+ ATA_int_BusMasterWriteByte( cont * 8, (bWrite ? 0 : 8) | 1 ); // Write(0)/Read(8) and start
// Wait for transfer to complete
- timeoutTime = now() + ATA_TIMEOUT;
- while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
- {
- HALT();
+ Uint32 ev = Threads_WaitEvents(THREAD_EVENT_SHORTWAIT|THREAD_EVENT_TIMER);
+ Time_FreeTimer(timeout);
+
+ if( ev & THREAD_EVENT_TIMER ) {
+ Log_Notice("ATA", "Timeout of %i ms exceeded", ATA_TIMEOUT);
}
// Complete Transfer
- ATA_int_BusMasterWriteByte( cont * 8, 8 ); // Read and stop
+ ATA_int_BusMasterWriteByte( cont * 8, (bWrite ? 0 : 8) ); // Write/Read and stop
#if DEBUG
{
if( ATA_int_BusMasterReadByte(cont * 8 + 2) & 0x4 ) {
Log_Error("ATA", "BM Status reports an interrupt, but none recieved");
ATA_int_BusMasterWriteByte(cont*8 + 2, 4); // Clear interrupt
- memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
- Mutex_Release( &glaATA_ControllerLock[ cont ] );
- LEAVE('i', 0);
- return 0;
+ goto _success;
}
#if 1
// Release controller lock
Mutex_Release( &glaATA_ControllerLock[ cont ] );
Log_Warning("ATA",
- "Read timeout on disk %i (Reading sector 0x%llx)",
- Disk, Address);
+ "Timeout on disk %i (%s sector 0x%llx)",
+ Disk, bWrite ? "Writing" : "Reading", Address);
// Return error
LEAVE('i', 1);
return 1;
}
- else {
- LOG("Transfer Completed & Acknowledged");
- // Copy to destination buffer
+
+ LOG("Transfer Completed & Acknowledged");
+_success:
+ // Copy to destination buffer (if bounce was used and it was a read)
+ if( bUseBounceBuffer && !bWrite )
memcpy( Buffer, gATA_Buffers[cont], Count*SECTOR_SIZE );
- // Release controller lock
- Mutex_Release( &glaATA_ControllerLock[ cont ] );
+ // Release controller lock
+ Mutex_Release( &glaATA_ControllerLock[ cont ] );
- LEAVE('i', 0);
- return 0;
- }
+ LEAVE('i', 0);
+ return 0;
}
+/**
+ * \fn int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+ * \return Boolean Failure
+ */
+int ATA_ReadDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
+{
+ return ATA_DoDMA(Disk, Address, Count, 0, Buffer);
+}
+
+
/**
* \fn int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, void *Buffer)
* \brief Write up to \a MAX_DMA_SECTORS to a disk
*/
int ATA_WriteDMA(Uint8 Disk, Uint64 Address, Uint Count, const void *Buffer)
{
- int cont = (Disk>>1)&1; // Controller ID
- int disk = Disk & 1;
- Uint16 base;
- Sint64 timeoutTime;
-
- // Check if the count is small enough
- if(Count > MAX_DMA_SECTORS) return 1;
-
- // Get exclusive access to the disk controller
- Mutex_Acquire( &glaATA_ControllerLock[ cont ] );
-
- // Set Size
- gATA_PRDTs[ cont ].Bytes = Count * SECTOR_SIZE;
-
- // Get Port Base
- base = ATA_GetBasePort(Disk);
-
- // Reset IRQ Flag
- gaATA_IRQs[cont] = 0;
-
- // Set up transfer
- outb(base+0x01, 0x00);
- if( Address > 0x0FFFFFFF ) // Use LBA48
- {
- outb(base+0x6, 0x40 | (disk << 4));
- outb(base+0x2, 0 >> 8); // Upper Sector Count
- outb(base+0x3, Address >> 24); // Low 2 Addr
- outb(base+0x3, Address >> 28); // Mid 2 Addr
- outb(base+0x3, Address >> 32); // High 2 Addr
- }
- else
- {
- // Magic, Disk, High Address nibble
- outb(base+0x06, 0xE0 | (disk << 4) | ((Address >> 24) & 0x0F));
- }
-
- outb(base+0x02, (Uint8) Count); // Sector Count
- outb(base+0x03, (Uint8) Address); // Low Addr
- outb(base+0x04, (Uint8) (Address >> 8)); // Middle Addr
- outb(base+0x05, (Uint8) (Address >> 16)); // High Addr
- if( Address > 0x0FFFFFFF )
- outb(base+0x07, HDD_DMA_W48); // Write Command (LBA48)
- else
- outb(base+0x07, HDD_DMA_W28); // Write Command (LBA28)
-
- // Copy to output buffer
- memcpy( gATA_Buffers[cont], Buffer, Count*SECTOR_SIZE );
-
- // Start transfer
- ATA_int_BusMasterWriteByte( cont << 3, 1 ); // Write and start
-
- // Wait for transfer to complete
- timeoutTime = now() + ATA_TIMEOUT;
- while( gaATA_IRQs[cont] == 0 && now() < timeoutTime)
- {
- HALT();
- }
-
- // Complete Transfer
- ATA_int_BusMasterWriteByte( cont << 3, 0 ); // Write and stop
-
- // If the IRQ is unset, return error
- if( gaATA_IRQs[cont] == 0 ) {
- // Release controller lock
- Mutex_Release( &glaATA_ControllerLock[ cont ] );
- return 1; // Error
- }
- else {
- Mutex_Release( &glaATA_ControllerLock[ cont ] );
- return 0;
- }
+ return ATA_DoDMA(Disk, Address, Count, 1, (void*)Buffer);
}
/**
// IRQ bit set for Primary Controller
val = ATA_int_BusMasterReadByte( 0x2 );
LOG("IRQ val = 0x%x", val);
- if(val & 4) {
+ if(val & 4)
+ {
LOG("IRQ hit (val = 0x%x)", val);
ATA_int_BusMasterWriteByte( 0x2, 4 );
gaATA_IRQs[0] = 1;
+ Threads_PostEvent(gATA_WaitingThreads[0], THREAD_EVENT_SHORTWAIT);
return ;
}
}
LOG("IRQ hit (val = 0x%x)", val);
ATA_int_BusMasterWriteByte( 0xA, 4 );
gaATA_IRQs[1] = 1;
+ Threads_PostEvent(gATA_WaitingThreads[1], THREAD_EVENT_SHORTWAIT);
return ;
}
}
#include <api_drv_common.h>
#include <api_drv_disk.h>
#include "common.h"
+#include <Storage/LVM/include/lvm.h>
// === MACROS ===
#define IO_DELAY() do{inb(0x80); inb(0x80); inb(0x80); inb(0x80);}while(0)
// === PROTOTYPES ===
int ATA_Install(char **Arguments);
void ATA_SetupPartitions(void);
-void ATA_SetupVFS(void);
int ATA_ScanDisk(int Disk);
void ATA_ParseGPT(int Disk);
-void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length);
Uint16 ATA_GetBasePort(int Disk);
-// Filesystem Interface
-char *ATA_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name);
-size_t ATA_ReadFS(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
-size_t ATA_WriteFS(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
- int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data);
// Read/Write Interface/Quantiser
-Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, void *Argument);
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, void *Argument);
+int ATA_ReadRaw(void *Ptr, Uint64 Address, size_t Count, void *Buffer);
+int ATA_WriteRaw(void *Ptr, Uint64 Address, size_t Count, const void *Buffer);
// === GLOBALS ===
-MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", NULL);
-tVFS_NodeType gATA_RootNodeType = {
- .TypeName = "ATA Root Node",
- .ReadDir = ATA_ReadDir,
- .FindDir = ATA_FindDir
+MODULE_DEFINE(0, VERSION, i386ATA, ATA_Install, NULL, "PCI", "LVM", NULL);
+tLVM_VolType gATA_VolType = {
+ .Name = "ATA",
+ .Read = ATA_ReadRaw,
+ .Write = ATA_WriteRaw
};
-tVFS_NodeType gATA_DiskNodeType = {
- .TypeName = "ATA Volume",
- .Read = ATA_ReadFS,
- .Write = ATA_WriteFS,
- .IOCtl = ATA_IOCtl
- };
-tDevFS_Driver gATA_DriverInfo = {
- NULL, "ata",
- {
- .NumACLs = 1,
- .Size = -1,
- .Flags = VFS_FFLAG_DIRECTORY,
- .ACLs = &gVFS_ACL_EveryoneRX,
- .Type = &gATA_RootNodeType
- }
-};
-tATA_Disk gATA_Disks[MAX_ATA_DISKS];
- int giATA_NumNodes;
-tVFS_Node **gATA_Nodes;
// === CODE ===
/**
ATA_SetupPartitions();
- ATA_SetupVFS();
-
- if( DevFS_AddDevice( &gATA_DriverInfo ) == 0 )
- return MODULE_ERR_MISC;
-
return MODULE_ERR_OK;
}
for( i = 0; i < MAX_ATA_DISKS; i ++ )
{
if( !ATA_ScanDisk(i) ) {
- gATA_Disks[i].Name[0] = '\0'; // Mark as unused
continue;
}
}
}
-/**
- * \brief Sets up the ATA drivers VFS information and registers with DevFS
- */
-void ATA_SetupVFS(void)
-{
- int i, j, k;
-
- // Count number of nodes needed
- giATA_NumNodes = 0;
- for( i = 0; i < MAX_ATA_DISKS; i++ )
- {
- if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
- giATA_NumNodes ++;
- giATA_NumNodes += gATA_Disks[i].NumPartitions;
- }
-
- // Allocate Node space
- gATA_Nodes = malloc( giATA_NumNodes * sizeof(void*) );
-
- // Set nodes
- k = 0;
- for( i = 0; i < MAX_ATA_DISKS; i++ )
- {
- if(gATA_Disks[i].Name[0] == '\0') continue; // Ignore
- gATA_Nodes[ k++ ] = &gATA_Disks[i].Node;
- for( j = 0; j < gATA_Disks[i].NumPartitions; j ++ )
- gATA_Nodes[ k++ ] = &gATA_Disks[i].Partitions[j].Node;
- }
-
- gATA_DriverInfo.RootNode.Size = giATA_NumNodes;
-}
-
/**
* \brief Scan a disk, getting the size and any paritions
* \param Disk Disk ID to scan
*/
int ATA_ScanDisk(int Disk)
{
- tVFS_Node *node;
- tMBR mbr;
-
+ Uint64 sector_count;
ENTER("iDisk", Disk);
// Get the disk size
- gATA_Disks[ Disk ].Sectors = ATA_GetDiskSize(Disk);
- if(gATA_Disks[ Disk ].Sectors == 0)
+ sector_count = ATA_GetDiskSize(Disk);
+ if(sector_count == 0)
{
LEAVE('i', 0);
return 0;
}
- LOG("gATA_Disks[ %i ].Sectors = 0x%x", Disk, gATA_Disks[ Disk ].Sectors);
-
- // Create Name
- gATA_Disks[ Disk ].Name[0] = 'A'+Disk;
- gATA_Disks[ Disk ].Name[1] = '\0';
-
#if 1
{
- Uint64 val = gATA_Disks[ Disk ].Sectors / 2;
+ Uint64 val = sector_count / 2;
char *units = "KiB";
if( val > 4*1024 ) {
val /= 1024;
val /= 1024;
units = "TiB";
}
- Log_Notice("ATA", "Disk %s: 0x%llx Sectors (%lli %s)",
- gATA_Disks[ Disk ].Name, gATA_Disks[ Disk ].Sectors, val, units);
+ Log_Notice("ATA", "Disk %i: 0x%llx Sectors (%lli %s)",
+ Disk, sector_count, val, units);
}
#endif
- // Get pointer to vfs node and populate it
- node = &gATA_Disks[ Disk ].Node;
- node->Size = gATA_Disks[Disk].Sectors * SECTOR_SIZE;
- node->NumACLs = 0; // Means Superuser only can access it
- node->Inode = (Disk << 8) | 0xFF;
- node->ImplPtr = gATA_Disks[ Disk ].Name;
-
- node->ATime = node->MTime = node->CTime = now();
+ char name[] = "ata0";
+ sprintf(name, "ata%i", Disk);
+ LVM_AddVolume(&gATA_VolType, name, (void*)(Uint)Disk, 512, sector_count);
- node->Type = &gATA_DiskNodeType;
-
- // --- Scan Partitions ---
- LOG("Reading MBR");
- // Read Boot Sector
- if( ATA_ReadDMA( Disk, 0, 1, &mbr ) != 0 ) {
- Log_Warning("ATA", "Error in reading MBR on %i", Disk);
- LEAVE('i', 0);
- return 0;
- }
-
- // Check for a GPT table
- if(mbr.Parts[0].SystemID == 0xEE)
- ATA_ParseGPT(Disk);
- else // No? Just parse the MBR
- ATA_ParseMBR(Disk, &mbr);
-
#if DEBUG >= 2
+ {
+ char mbr[512];
ATA_ReadDMA( Disk, 1, 1, &mbr );
Debug_HexDump("ATA_ScanDisk", &mbr, 512);
+ }
#endif
LEAVE('i', 1);
return 1;
}
-/**
- * \fn void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
- * \brief Fills a parition's information structure
- */
-void ATA_int_MakePartition(tATA_Partition *Part, int Disk, int Num, Uint64 Start, Uint64 Length)
-{
- ENTER("pPart iDisk iNum XStart XLength", Part, Disk, Num, Start, Length);
- Part->Start = Start;
- Part->Length = Length;
- Part->Name[0] = 'A'+Disk;
- if(Num >= 10) {
- Part->Name[1] = '1'+Num/10;
- Part->Name[2] = '1'+Num%10;
- Part->Name[3] = '\0';
- } else {
- Part->Name[1] = '1'+Num;
- Part->Name[2] = '\0';
- }
- Part->Node.NumACLs = 0; // Only root can read/write raw block devices
- Part->Node.Inode = (Disk << 8) | Num;
- Part->Node.ImplPtr = Part->Name;
-
- Part->Node.Type = &gATA_DiskNodeType;
- Log_Notice("ATA", "Partition %s at 0x%llx+0x%llx", Part->Name, Part->Start, Part->Length);
- LOG("Made '%s' (&Node=%p)", Part->Name, &Part->Node);
- LEAVE('-');
-}
-
-/**
- * \fn void ATA_ParseGPT(int Disk)
- * \brief Parses the GUID Partition Table
- */
-void ATA_ParseGPT(int Disk)
-{
- ///\todo Support GPT Disks
- Warning("GPT Disks are currently unsupported (Disk %i)", Disk);
-}
-
-/**
- * \fn char *ATA_ReadDir(tVFS_Node *Node, int Pos)
- */
-char *ATA_ReadDir(tVFS_Node *UNUSED(Node), int Pos)
-{
- if(Pos >= giATA_NumNodes || Pos < 0) return NULL;
- return strdup( gATA_Nodes[Pos]->ImplPtr );
-}
-
-/**
- * \fn tVFS_Node *ATA_FindDir(tVFS_Node *Node, const char *Name)
- */
-tVFS_Node *ATA_FindDir(tVFS_Node *UNUSED(Node), const char *Name)
-{
- int part;
- tATA_Disk *disk;
-
- // Check first character
- if(Name[0] < 'A' || Name[0] > 'A'+MAX_ATA_DISKS)
- return NULL;
- disk = &gATA_Disks[Name[0]-'A'];
- // Raw Disk
- if(Name[1] == '\0') {
- if( disk->Sectors == 0 && disk->Name[0] == '\0')
- return NULL;
- return &disk->Node;
- }
-
- // Partitions
- if(Name[1] < '0' || '9' < Name[1]) return NULL;
- if(Name[2] == '\0') { // <= 9
- part = Name[1] - '0';
- part --;
- return &disk->Partitions[part].Node;
- }
- // > 9
- if('0' > Name[2] || '9' < Name[2]) return NULL;
- if(Name[3] != '\0') return NULL;
-
- part = (Name[1] - '0') * 10;
- part += Name[2] - '0';
- part --;
- return &disk->Partitions[part].Node;
-
-}
-
-/**
- * \brief Read handler for VFS interface
- */
-size_t ATA_ReadFS(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
-{
- int disk = Node->Inode >> 8;
- int part = Node->Inode & 0xFF;
-
- ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
-
- // Raw Disk Access
- if(part == 0xFF)
- {
- if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE ) {
- LEAVE('i', 0);
- return 0;
- }
- if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
- Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
- }
- // Partition
- else
- {
- if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE ) {
- LEAVE('i', 0);
- return 0;
- }
- if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
- Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
- Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
- }
-
- {
- int ret = DrvUtil_ReadBlock(
- Offset, Length, Buffer,
- ATA_ReadRaw, SECTOR_SIZE, (void*)(Uint)disk
- );
- //Log("ATA_ReadFS: disk=%i, Offset=%lli, Length=%lli", disk, Offset, Length);
- //Debug_HexDump("ATA_ReadFS", Buffer, Length);
- LEAVE('i', ret);
- return ret;
- }
-}
-
-/**
- * \brief Write handler for VFS interface
- */
-size_t ATA_WriteFS(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
-{
- int disk = Node->Inode >> 8;
- int part = Node->Inode & 0xFF;
-
- // Raw Disk Access
- if(part == 0xFF)
- {
- if( Offset >= gATA_Disks[disk].Sectors * SECTOR_SIZE )
- return 0;
- if( Offset + Length > gATA_Disks[disk].Sectors*SECTOR_SIZE )
- Length = gATA_Disks[disk].Sectors*SECTOR_SIZE - Offset;
- }
- // Partition
- else
- {
- if( Offset >= gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
- return 0;
- if( Offset + Length > gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE )
- Length = gATA_Disks[disk].Partitions[part].Length * SECTOR_SIZE - Offset;
- Offset += gATA_Disks[disk].Partitions[part].Start * SECTOR_SIZE;
- }
-
- Log("ATA_WriteFS: (Node=%p, Offset=0x%llx, Length=0x%llx, Buffer=%p)", Node, Offset, Length, Buffer);
- Debug_HexDump("ATA_WriteFS", Buffer, Length);
- return DrvUtil_WriteBlock(
- Offset, Length, Buffer,
- ATA_ReadRaw, ATA_WriteRaw, SECTOR_SIZE, (void*)(Uint)disk
- );
-}
-
-const char *csaATA_IOCtls[] = {DRV_IOCTLNAMES, DRV_DISK_IOCTLNAMES, NULL};
-/**
- * \fn int ATA_IOCtl(tVFS_Node *Node, int Id, void *Data)
- * \brief IO Control Funtion
- */
-int ATA_IOCtl(tVFS_Node *UNUSED(Node), int Id, void *Data)
-{
- switch(Id)
- {
- BASE_IOCTLS(DRV_TYPE_DISK, "i386ATA", VERSION, csaATA_IOCtls);
-
- case DISK_IOCTL_GETBLOCKSIZE:
- return 512;
-
- default:
- return 0;
- }
- return 0;
-}
-
// --- Disk Access ---
/**
* \fn Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, Uint Disk)
*/
-Uint ATA_ReadRaw(Uint64 Address, Uint Count, void *Buffer, void *Argument)
+int ATA_ReadRaw(void *Ptr, Uint64 Address, Uint Count, void *Buffer)
{
- int Disk = (tVAddr)Argument;
+ int Disk = (tVAddr)Ptr;
int ret;
Uint offset;
Uint done = 0;
+ LOG("Reading %i sectors from 0x%llx of disk %i", Count, Address, Disk);
+
// Pass straight on to ATA_ReadDMAPage if we can
if(Count <= MAX_DMA_SECTORS)
{
ret = ATA_ReadDMA(Disk, Address, Count, Buffer);
- if(ret == 0) return 0;
+ if(ret) return 0;
return Count;
}
offset += MAX_DMA_SECTORS*SECTOR_SIZE;
}
- ret = ATA_ReadDMA(Disk, Address+offset, Count, Buffer+offset);
- if(ret != 1) return 0;
+ ret = ATA_ReadDMA(Disk, Address+done, Count, Buffer+offset);
+ if(ret) return 0;
return done+Count;
}
/**
* \fn Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, Uint Disk)
*/
-Uint ATA_WriteRaw(Uint64 Address, Uint Count, const void *Buffer, void *Argument)
+int ATA_WriteRaw(void *Ptr, Uint64 Address, Uint Count, const void *Buffer)
{
- int Disk = (tVAddr)Argument;
+ int Disk = (tVAddr)Ptr;
int ret;
Uint offset;
Uint done = 0;
+++ /dev/null
-/*
- * Acess2 IDE Harddisk Driver
- * - MBR Parsing Code
- * mbr.c
- */
-#define DEBUG 0
-#include <acess.h>
-#include "common.h"
-
-// === PROTOTYPES ===
-void ATA_ParseMBR(int Disk, tMBR *MBR);
-Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length);
-
-// === GLOBALS ===
-
-// === CODE ===
-/**
- * \fn void ATA_ParseMBR(int Disk, tMBR *MBR)
- */
-void ATA_ParseMBR(int Disk, tMBR *MBR)
-{
- int i, j = 0, k = 4;
- Uint64 extendedLBA;
- Uint64 base, len;
-
- ENTER("iDisk", Disk);
-
- // Count Partitions
- gATA_Disks[Disk].NumPartitions = 0;
- extendedLBA = 0;
- for( i = 0; i < 4; i ++ )
- {
- if( MBR->Parts[i].SystemID == 0 ) continue;
-
- if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 ) // LBA 28
- {
- base = MBR->Parts[i].LBAStart;
- }
- else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 ) // LBA 48
- {
- base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
- }
- else
- continue; // Invalid, don't count
-
- if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
- LOG("Extended Partition at 0x%llx", base);
- if(extendedLBA != 0) {
- Warning("Disk %i has multiple extended partitions, ignoring rest", Disk);
- continue;
- }
- extendedLBA = base;
- }
- else {
- LOG("Primary Partition at 0x%llx", base);
-
- gATA_Disks[Disk].NumPartitions ++;
- }
- }
- while(extendedLBA != 0)
- {
- extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
- if( extendedLBA == -1 ) break;
- gATA_Disks[Disk].NumPartitions ++;
- }
- LOG("gATA_Disks[Disk].NumPartitions = %i", gATA_Disks[Disk].NumPartitions);
-
- // Create patition array
- gATA_Disks[Disk].Partitions = malloc( gATA_Disks[Disk].NumPartitions * sizeof(tATA_Partition) );
-
- // --- Fill Partition Info ---
- extendedLBA = 0;
- for( j = 0, i = 0; i < 4; i ++ )
- {
- LOG("MBR->Parts[%i].SystemID = 0x%02x", i, MBR->Parts[i].SystemID);
- if( MBR->Parts[i].SystemID == 0 ) continue;
- if( MBR->Parts[i].Boot == 0x0 || MBR->Parts[i].Boot == 0x80 ) // LBA 28
- {
- base = MBR->Parts[i].LBAStart;
- len = MBR->Parts[i].LBALength;
- }
- else if( MBR->Parts[i].Boot == 0x1 || MBR->Parts[i].Boot == 0x81 ) // LBA 48
- {
- base = (MBR->Parts[i].StartHi << 16) | MBR->Parts[i].LBAStart;
- len = (MBR->Parts[i].LengthHi << 16) | MBR->Parts[i].LBALength;
- }
- else
- continue;
-
- if( MBR->Parts[i].SystemID == 0xF || MBR->Parts[i].SystemID == 5 ) {
- if(extendedLBA != 0) {
- Log_Warning("ATA", "Disk %i has multiple extended partitions, ignoring rest", Disk);
- continue;
- }
- extendedLBA = base;
- continue;
- }
- // Create Partition
- ATA_int_MakePartition(
- &gATA_Disks[Disk].Partitions[j], Disk, j,
- base, len
- );
- j ++;
-
- }
- // Scan extended partitions
- while(extendedLBA != 0)
- {
- extendedLBA = ATA_MBR_int_ReadExt(Disk, extendedLBA, &base, &len);
- if(extendedLBA == -1) break;
- ATA_int_MakePartition(
- &gATA_Disks[Disk].Partitions[j], Disk, k, base, len
- );
- }
-
- LEAVE('-');
-}
-
-/**
- * \brief Reads an extended partition
- * \return LBA of next Extended, -1 on error, 0 for last
- */
-Uint64 ATA_MBR_int_ReadExt(int Disk, Uint64 Addr, Uint64 *Base, Uint64 *Length)
-{
- Uint64 link = 0;
- int bFoundPart = 0;;
- int i;
- tMBR mbr;
- Uint64 base, len;
-
- if( ATA_ReadDMA( Disk, Addr, 1, &mbr ) != 0 )
- return -1; // Stop on Errors
-
- for( i = 0; i < 4; i ++ )
- {
- if( mbr.Parts[i].SystemID == 0 ) continue;
-
- // LBA 24
- if( mbr.Parts[i].Boot == 0x0 || mbr.Parts[i].Boot == 0x80 ) {
- base = mbr.Parts[i].LBAStart;
- len = mbr.Parts[i].LBALength;
- }
- // LBA 48
- else if( mbr.Parts[i].Boot == 0x1 || mbr.Parts[i].Boot == 0x81 ) {
- base = (mbr.Parts[i].StartHi << 16) | mbr.Parts[i].LBAStart;
- len = (mbr.Parts[i].LengthHi << 16) | mbr.Parts[i].LBALength;
- }
- else {
- Log_Warning("ATA MBR",
- "Unknown partition type 0x%x, Disk %i Ext 0x%llx Part %i",
- mbr.Parts[i].Boot, Disk, Addr, i
- );
- return -1;
- }
- base += Addr; // Addresses are relative
-
- switch(mbr.Parts[i].SystemID)
- {
- case 0xF:
- case 0x5:
- if(link != 0) {
- Log_Warning("ATA MBR",
- "Disk %i has two forward links in the extended partition",
- Disk
- );
- return -1;
- }
- link = base;
- break;
- default:
- if(bFoundPart) {
- Warning("ATA MBR",
- "Disk %i has more than one partition in the extended partition at 0x%llx",
- Disk, Addr
- );
- return -1;
- }
- bFoundPart = 1;
- *Base = base;
- *Length = len;
- break;
- }
- }
-
- if(!bFoundPart) {
- Log_Warning("ATA MBR",
- "No partition in extended partiton, Disk %i 0x%llx",
- Disk, Addr);
- return -1;
- }
-
- return link;
-}
int FDD_Install(char **Arguments);
int FDD_RegisterFS(void);
// --- VFS
-char *FDD_ReadDir(tVFS_Node *Node, int pos);
+ int FDD_ReadDir(tVFS_Node *Node, int pos, char dest[FILENAME_MAX]);
tVFS_Node *FDD_FindDir(tVFS_Node *dirNode, const char *Name);
int FDD_IOCtl(tVFS_Node *Node, int ID, void *Data);
size_t FDD_ReadFS(tVFS_Node *node, off_t Offset, size_t Len, void *buffer);
* \param Pos Position
* \return Heap string of node name
*/
-char *FDD_ReadDir(tVFS_Node *Node, int Pos)
+int FDD_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
- char ret_tpl[2];
if(Pos < 0 || Pos > MAX_DISKS )
- return NULL;
+ return -ENOENT;
if(gaFDD_Disks[Pos].bValid)
- return VFS_SKIP;
+ return 1;
- ret_tpl[0] = '0' + Pos;
- ret_tpl[1] = '\0';
- return strdup(ret_tpl);
+ Dest[0] = '0' + Pos;
+ Dest[1] = '\0';
+ return 0;
}
/**
#include <acess.h>
-typedef int (*tLVM_ReadFcn)(void *, Uint64, size_t, void *);
-typedef int (*tLVM_WriteFcn)(void *, Uint64, size_t, const void *);
+typedef struct sLVM_VolType tLVM_VolType;
-extern int LVM_AddVolume(const char *Name, void *Ptr, tLVM_ReadFcn Read, tLVM_WriteFcn Write);
+struct sLVM_VolType
+{
+ const char *Name;
+
+ int (*Read)(void *, Uint64, size_t, void *);
+ int (*Write)(void *, Uint64, size_t, const void *);
+ void (*Cleanup)(void *);
+};
+
+
+extern int LVM_AddVolume(const tLVM_VolType *Type, const char *Name, void *Ptr, size_t BlockSize, size_t BlockCount);
#endif
// === TYPES ===
typedef struct sLVM_Vol tLVM_Vol;
+typedef struct sLVM_Format tLVM_Format;
+
+// === STRUCTURES ===
+struct sLVM_Format
+{
+ tLVM_Format *Next;
+ const char *Name;
+ int (*CountSubvolumes)(tLVM_Vol *Volume, void *FirstBlockData);
+ void (*PopulateSubvolumes)(tLVM_Vol *Volume, void *FirstBlockData);
+};
// === FUNCTIONS ===
extern size_t LVM_int_ReadVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, void *Dest);
// --- Subvolume Management ---
extern void LVM_int_SetSubvolume_Anon(tLVM_Vol *Volume, int Index, Uint64 FirstBlock, Uint64 LastBlock);
+// --- Global Fromats ---
+extern tLVM_Format gLVM_MBRType;
+
#endif
{
tLVM_Vol *Next;
- tVFS_Node Node;
+ tVFS_Node DirNode;
+ tVFS_Node VolNode;
void *Ptr;
- tLVM_ReadFcn Read;
- tLVM_WriteFcn Write;
+ const tLVM_VolType *Type;
size_t BlockSize;
+ Uint64 BlockCount;
int nSubVolumes;
tLVM_SubVolume **SubVolumes;
};
extern tVFS_NodeType gLVM_SubVolNodeType;
+extern tVFS_NodeType gLVM_VolNodeType;
+
+extern tLVM_Vol *gpLVM_FirstVolume;
+extern tLVM_Vol *gpLVM_LastVolume;
#endif
// === PROTOTYPES ===
// ---
int LVM_Initialise(char **Arguments);
-void LVM_Cleanup(void);
+ int LVM_Cleanup(void);
// ---
-char *LVM_Root_ReadDir(tVFS_Node *Node, int ID);
+ int LVM_Root_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
tVFS_Node *LVM_Root_FindDir(tVFS_Node *Node, const char *Name);
-char *LVM_Vol_ReadDir(tVFS_Node *Node, int ID);
+ int LVM_Vol_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX]);
tVFS_Node *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name);
+size_t LVM_Vol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
+size_t LVM_Vol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer);
size_t LVM_SubVol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer);
+void LVM_CloseNode(tVFS_Node *Node);
Uint LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument);
Uint LVM_int_DrvUtil_WriteBlock(Uint64 Address, Uint Count, const void *Buffer, void *Argument);
};
tVFS_NodeType gLVM_VolNodeType = {
.ReadDir = LVM_Vol_ReadDir,
- .FindDir = LVM_Vol_FindDir
+ .FindDir = LVM_Vol_FindDir,
+ .Read = LVM_Vol_Read,
+ .Write = LVM_Vol_Write,
+ .Close = LVM_CloseNode
};
tVFS_NodeType gLVM_SubVolNodeType = {
.Read = LVM_SubVol_Read,
- .Write = LVM_SubVol_Write
+ .Write = LVM_SubVol_Write,
+ .Close = LVM_CloseNode
};
tDevFS_Driver gLVM_DevFS = {
NULL, "LVM",
- {.Flags = VFS_FFLAG_DIRECTORY, .Type = &gLVM_RootNodeType}
+ {.Flags = VFS_FFLAG_DIRECTORY, .Type = &gLVM_RootNodeType, .Size = -1}
};
tLVM_Vol *gpLVM_FirstVolume;
return 0;
}
-void LVM_Cleanup(void)
+int LVM_Cleanup(void)
{
+ // Attempt to destroy all volumes
+ tLVM_Vol *vol, *prev = NULL, *next;
+ // TODO: Locks?
+ for( vol = gpLVM_FirstVolume; vol; prev = vol, vol = next )
+ {
+ next = vol->Next;
+ int nFree = 0;
+
+ for( int i = 0; i < vol->nSubVolumes; i ++ )
+ {
+ tLVM_SubVolume *sv;
+ sv = vol->SubVolumes[i];
+ if( sv == NULL ) {
+ nFree ++;
+ continue;
+ }
+
+ Mutex_Acquire(&sv->Node.Lock);
+ if(sv->Node.ReferenceCount == 0) {
+ nFree ++;
+ vol->SubVolumes[i] = NULL;
+ Mutex_Release(&sv->Node.Lock);
+ }
+ else {
+ Mutex_Release(&sv->Node.Lock);
+ continue ;
+ }
+
+ Mutex_Acquire(&sv->Node.Lock);
+ LOG("Removed subvolume %s:%s", vol->Name, sv->Name);
+ free(sv);
+ }
+
+ if( nFree != vol->nSubVolumes )
+ continue ;
+
+ if(prev)
+ prev->Next = next;
+ else
+ gpLVM_FirstVolume = next;
+
+ Mutex_Acquire(&vol->DirNode.Lock);
+ Mutex_Acquire(&vol->VolNode.Lock);
+ if( vol->Type->Cleanup )
+ vol->Type->Cleanup( vol->Ptr );
+ LOG("Removed volume %s", vol->Name);
+ free(vol);
+ }
+
+ if( gpLVM_FirstVolume )
+ return EBUSY;
+
+ return EOK;
}
// --------------------------------------------------------------------
// VFS Inteface
// --------------------------------------------------------------------
-char *LVM_Root_ReadDir(tVFS_Node *Node, int ID)
+int LVM_Root_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
{
tLVM_Vol *vol;
- if( ID < 0 ) return NULL;
+ if( ID < 0 ) return -EINVAL;
for( vol = gpLVM_FirstVolume; vol && ID --; vol = vol->Next );
- if(vol)
- return strdup(vol->Name);
+ if(vol) {
+ strncpy(Dest, vol->Name, FILENAME_MAX);
+ return 0;
+ }
else
- return NULL;
+ return -ENOENT;
}
tVFS_Node *LVM_Root_FindDir(tVFS_Node *Node, const char *Name)
{
{
if( strcmp(vol->Name, Name) == 0 )
{
- return &vol->Node;
+ vol->DirNode.ReferenceCount ++;
+ return &vol->DirNode;
}
}
return NULL;
}
-char *LVM_Vol_ReadDir(tVFS_Node *Node, int ID)
+int LVM_Vol_ReadDir(tVFS_Node *Node, int ID, char Dest[FILENAME_MAX])
{
tLVM_Vol *vol = Node->ImplPtr;
+ const char *src;
- if( ID < 0 || ID >= vol->nSubVolumes )
- return NULL;
-
- return strdup( vol->SubVolumes[ID]->Name );
+ if( ID < 0 || ID >= vol->nSubVolumes+1 )
+ return -EINVAL;
+
+ if( ID == 0 ) {
+ src = "ROOT";
+ }
+ else {
+ src = vol->SubVolumes[ID-1]->Name;
+ }
+ strncpy(Dest, src, FILENAME_MAX);
+ return 0;
}
tVFS_Node *LVM_Vol_FindDir(tVFS_Node *Node, const char *Name)
{
tLVM_Vol *vol = Node->ImplPtr;
+
+ if( strcmp("ROOT", Name) == 0 )
+ return &vol->VolNode;
for( int i = 0; i < vol->nSubVolumes; i ++ )
{
if( strcmp(vol->SubVolumes[i]->Name, Name) == 0 )
{
+ vol->SubVolumes[i]->Node.ReferenceCount ++;
return &vol->SubVolumes[i]->Node;
}
}
return NULL;
}
+size_t LVM_Vol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
+{
+ tLVM_Vol *vol = Node->ImplPtr;
+ Uint64 byte_size = vol->BlockCount * vol->BlockSize;
+
+ if( Offset > byte_size )
+ return 0;
+ if( Length > byte_size )
+ Length = byte_size;
+ if( Offset + Length > byte_size )
+ Length = byte_size - Offset;
+
+ return DrvUtil_ReadBlock(
+ Offset, Length, Buffer,
+ LVM_int_DrvUtil_ReadBlock, vol->BlockSize, vol
+ );
+}
+
+size_t LVM_Vol_Write(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer)
+{
+ return 0;
+}
+
size_t LVM_SubVol_Read(tVFS_Node *Node, off_t Offset, size_t Length, void *Buffer)
{
tLVM_SubVolume *sv = Node->ImplPtr;
if( Offset + Length > byte_size )
Length = byte_size - Offset;
- Offset += sv->FirstBlock * sv->Vol->BlockSize;
+ LOG("Reading (0x%llx+0x%llx)+0x%x to %p",
+ (Uint64)(sv->FirstBlock * sv->Vol->BlockSize), Offset,
+ Length, Buffer
+ );
+ Offset += sv->FirstBlock * sv->Vol->BlockSize;
+
return DrvUtil_ReadBlock(
Offset, Length, Buffer,
LVM_int_DrvUtil_ReadBlock, sv->Vol->BlockSize, sv->Vol
);
}
+void LVM_CloseNode(tVFS_Node *Node)
+{
+ Node->ReferenceCount --;
+}
+
Uint LVM_int_DrvUtil_ReadBlock(Uint64 Address, Uint Count, void *Buffer, void *Argument)
{
return LVM_int_ReadVolume( Argument, Address, Count, Buffer );
Uint64 LVM_MBR_int_ReadExt(tLVM_Vol *Volume, Uint64 Addr, Uint64 *Base, Uint64 *Length);
// === GLOBALS ===
+tLVM_Format gLVM_MBRType = {
+ .Name = "MBR",
+ .CountSubvolumes = LVM_MBR_CountSubvolumes,
+ .PopulateSubvolumes = LVM_MBR_PopulateSubvolumes
+};
// === CODE ===
/**
while(extendedLBA != 0)
{
extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
- if( extendedLBA == -1 ) break;
+ if( extendedLBA == (Uint64)-1 )
+ break;
numPartitions ++;
}
LOG("numPartitions = %i", numPartitions);
while(extendedLBA != 0)
{
extendedLBA = LVM_MBR_int_ReadExt(Volume, extendedLBA, &base, &len);
- if(extendedLBA == -1) break;
+ if(extendedLBA == (Uint64)-1)
+ break;
LVM_int_SetSubvolume_Anon( Volume, j, base, len );
j ++ ;
}
* volumes.c
* - Volume management
*/
+#define DEBUG 1
#include "lvm_int.h"
// === PROTOTYPES ===
// --------------------------------------------------------------------
int LVM_AddVolumeVFS(const char *Name, int FD)
{
- return LVM_AddVolume(Name, (void*)(Uint)FD, LVM_int_VFSReadEmul, LVM_int_VFSWriteEmul);
+ // Assuming 512-byte blocks, not a good idea
+// return LVM_AddVolume(Name, (void*)(Uint)FD, 512, LVM_int_VFSReadEmul, LVM_int_VFSWriteEmul);
+ return 0;
}
-int LVM_AddVolume(const char *Name, void *Ptr, tLVM_ReadFcn Read, tLVM_WriteFcn Write)
+int LVM_AddVolume(const tLVM_VolType *Type, const char *Name, void *Ptr, size_t BlockSize, size_t BlockCount)
{
tLVM_Vol dummy_vol;
-// tLVM_Vol *real_vol;
+ tLVM_Vol *real_vol;
+ tLVM_Format *fmt;
+ void *first_block;
+
+ if( BlockCount == 0 || BlockSize == 0 ) {
+ Log_Error("LVM", "BlockSize(0x%x)/BlockCount(0x%x) invalid in LVM_AddVolume",
+ BlockSize, BlockCount);
+ return 1;
+ }
+ dummy_vol.Type = Type;
dummy_vol.Ptr = Ptr;
- dummy_vol.Read = Read;
- dummy_vol.Write = Write;
+ dummy_vol.BlockCount = BlockCount;
+ dummy_vol.BlockSize = BlockSize;
+
+ // Read the first block of the volume
+ first_block = malloc(BlockSize);
+ if( !first_block ) {
+ Log_Error("VLM", "LVM_AddVolume - malloc error on %i bytes", BlockSize);
+ return -1;
+ }
+ Type->Read(Ptr, 0, 1, first_block);
- // Determine Type
+ // Determine Format
+ // TODO: Determine format
+ fmt = &gLVM_MBRType;
// Type->CountSubvolumes
+ dummy_vol.nSubVolumes = fmt->CountSubvolumes(&dummy_vol, first_block);
// Create real volume descriptor
+ // TODO: If this needs to be rescanned later, having the subvolume list separate might be an idea
+ real_vol = malloc( sizeof(tLVM_Vol) + strlen(Name) + 1 + sizeof(tLVM_SubVolume*) * dummy_vol.nSubVolumes );
+ real_vol->Next = NULL;
+ real_vol->Type = Type;
+ real_vol->Ptr = Ptr;
+ real_vol->BlockSize = BlockSize;
+ real_vol->BlockCount = BlockCount;
+ real_vol->nSubVolumes = dummy_vol.nSubVolumes;
+ real_vol->SubVolumes = (void*)( real_vol->Name + strlen(Name) + 1 );
+ real_vol->BlockSize = BlockSize;
+ strcpy(real_vol->Name, Name);
+ memset(real_vol->SubVolumes, 0, sizeof(tLVM_SubVolume*) * real_vol->nSubVolumes);
+ // - VFS Nodes
+ memset(&real_vol->DirNode, 0, sizeof(tVFS_Node));
+ real_vol->DirNode.Type = &gLVM_VolNodeType;
+ real_vol->DirNode.ImplPtr = real_vol;
+ real_vol->DirNode.Flags = VFS_FFLAG_DIRECTORY;
+ real_vol->DirNode.Size = -1;
+ memset(&real_vol->VolNode, 0, sizeof(tVFS_Node));
+ real_vol->VolNode.Type = &gLVM_VolNodeType;
+ real_vol->VolNode.ImplPtr = real_vol;
+ real_vol->VolNode.Size = BlockCount * BlockSize;
// Type->PopulateSubvolumes
+ fmt->PopulateSubvolumes(real_vol, first_block);
+ free(first_block);
// Add to volume list
+ gpLVM_LastVolume->Next = real_vol;
+ gpLVM_LastVolume = real_vol;
return 0;
}
sv->Node.ImplPtr = sv;
sv->Node.Type = &gLVM_SubVolNodeType;
+ sv->Node.Size = BlockCount * Volume->BlockSize;
+
+ Log_Log("LVM", "Partition %s/%s - 0x%llx+0x%llx blocks",
+ Volume->Name, sv->Name, FirstBlock, BlockCount);
}
// --------------------------------------------------------------------
// --------------------------------------------------------------------
size_t LVM_int_ReadVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, void *Dest)
{
- return Volume->Read(Volume->Ptr, BlockNum, BlockCount, Dest);
+ return Volume->Type->Read(Volume->Ptr, BlockNum, BlockCount, Dest);
}
size_t LVM_int_WriteVolume(tLVM_Vol *Volume, Uint64 BlockNum, size_t BlockCount, const void *Src)
{
- return Volume->Write(Volume->Ptr, BlockNum, BlockCount, Src);
+ return Volume->Type->Write(Volume->Ptr, BlockNum, BlockCount, Src);
}
int LVM_int_VFSReadEmul(void *Arg, Uint64 BlockStart, size_t BlockCount, void *Dest)
#
OBJ = main.o
-OBJ += usb.o usb_lowlevel.o usb_devinit.o usb_io.o usb_poll.o
-OBJ += hub.o
+OBJ += usb.o usb_lowlevel.o usb_devinit.o usb_io.o usb_poll.o usb_info.o
+OBJ += hub.o portctl.o
CPPFLAGS = -Iinclude
NAME = Core
// resvd
#define SET_FEATURE 3
-#define PORT_CONNECTION 0
-#define PORT_ENABLE 1
-#define PORT_SUSPEND 2
-#define PORT_OVER_CURRENT 3
-#define PORT_RESET 4
-#define PORT_POWER 8
-#define PORT_LOW_SPEED 9
-#define C_PORT_CONNECTION 16
-#define C_PORT_ENABLE 17
-#define C_PORT_SUSPEND 18
-#define C_PORT_OVER_CURRENT 19
-#define C_PORT_RESET 20
-#define PORT_TEST 21
-#define PORT_INDICATOR 21
-
struct sHubDescriptor
{
Uint8 DescLength;
void Hub_Disconnected(tUSBInterface *Dev);
void Hub_PortStatusChange(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
void Hub_int_HandleChange(tUSBInterface *Dev, int Port);
+void Hub_SetPortFeature(tUSBInterface *Dev, int Port, int Feat);
+void Hub_ClearPortFeature(tUSBInterface *HubDev, int Port, int Feat);
+int Hub_GetPortStatus(tUSBInterface *HubDev, int Port, int Flag);
// === GLOBALS ===
tUSBDriver gUSBHub_Driver = {
// - Power on port
USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_POWER, Port, 0, NULL);
Time_Delay(info->PowerOnDelay);
- // - Reset
- USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_RESET, Port, 0, NULL);
- Time_Delay(20); // Spec says 10ms after reset, but how long is reset?
- // - Enable
- USB_Request(Dev, 0, 0x23, SET_FEATURE, PORT_ENABLE, Port, 0, NULL);
- // - Poke USB Stack
- USB_DeviceConnected(info->HubPtr, Port);
+ // - Start reset process
+ USB_PortCtl_BeginReset(info->HubPtr, Port);
}
else {
// Disconnected
USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, C_PORT_RESET, Port, 0, NULL);
}
}
+
+void Hub_SetPortFeature(tUSBInterface *Dev, int Port, int Feat)
+{
+ USB_Request(Dev, 0, 0x23, SET_FEATURE, Feat, Port, 0, NULL);
+}
+
+void Hub_ClearPortFeature(tUSBInterface *Dev, int Port, int Feat)
+{
+ USB_Request(Dev, 0, 0x23, CLEAR_FEATURE, Feat, Port, 0, NULL);
+}
+
+int Hub_GetPortStatus(tUSBInterface *Dev, int Port, int Flag)
+{
+ Uint16 status[2]; // Status, Change
+ USB_Request(Dev, 0, 0xA3, GET_STATUS, 0, Port, 4, status);
+ return !!(status[0] & (1 << Flag));
+}
extern void USB_RegisterDriver(tUSBDriver *Driver);
+// --- Driver Pointer ---
extern void *USB_GetDeviceDataPtr(tUSBInterface *Dev);
extern void USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr);
+// --- Device/Interface information ---
+extern Uint32 USB_GetInterfaceClass(tUSBInterface *Dev);
+extern void USB_GetDeviceVendor(tUSBInterface *Dev, Uint16 *VendorID, Uint16 *DeviceID);
+extern char *USB_GetSerialNumber(tUSBInterface *Dev);
+
+// --- Device IO ---
extern void USB_StartPollingEndpoint(tUSBInterface *Dev, int Endpoint);
extern void USB_ReadDescriptor(tUSBInterface *Dev, int Type, int Index, int Length, void *Data);
extern void USB_Request(tUSBInterface *Dev, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
// TODO: Async
-extern void USB_SendData(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
-extern void USB_RecvData(tUSBInterface *Dev, int Endpoint, int Length, void *Data);
-extern void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf, tUSB_DataCallback Callback);
+extern void USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *Data);
+extern void USB_RecvData(tUSBInterface *Dev, int Endpoint, size_t Length, void *Data);
+extern void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, size_t Length, void *DataBuf);
#endif
typedef void (*tUSBHostCb)(void *DataPtr, void *Data, size_t Length);
-typedef void *(*tUSBHostOp)(void *Ptr, int Dest, int DataTgl, tUSBHostCb CB, void *CbData, void *Data, size_t Length);
-typedef void *(*tUSBIntOp)(void *Ptr, int Dest, int Period, tUSBHostCb CB, void *CbData, void *Data, size_t Length);
+typedef void *(*tUSBInitInt)(void *Ptr, int Endpt, int bOutbound, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len);
+typedef void *(*tUSBInit)(void *Ptr, int Endpt, size_t MaxPacketSize);
+typedef void *(*tUSBDataOp)(void *Dest, tUSBHostCb Cb, void *CbData, void *Data, size_t Length);
+
+typedef void *(*tUSBControlOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+ int bOutbound, // (1) SETUP, OUT, IN vs (0) SETUP, IN, OUT
+ const void *SetupData, size_t SetupLength,
+ const void *OutData, size_t OutLength,
+ void *InData, size_t InLength
+ );
+typedef void *(*tUSBBulkOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+ int bOutbound, void *Data, size_t Length
+ );
+typedef void *(*tUSBIsochOp)(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+ int bOutbound, void *Data, size_t Length, int When
+ );
/**
* \brief Defines a USB Host Controller type
*/
struct sUSBHostDef
{
- tUSBIntOp InterruptIN;
- tUSBIntOp InterruptOUT;
- void (*StopInterrupt)(void *Ptr, void *Handle);
-
- void *(*ControlSETUP)(void *Ptr, int Dest, int DataTgl, void *Data, size_t Length);
- tUSBHostOp ControlIN;
- tUSBHostOp ControlOUT;
+ tUSBInitInt InitInterrupt;
+ tUSBInit InitIsoch;
+ tUSBInit InitControl;
+ tUSBInit InitBulk;
+ void (*RemEndpoint)(void *Ptr, void *Handle);
- tUSBHostOp BulkIN;
- tUSBHostOp BulkOUT;
-
+ // NOTE: If \a Cb is ERRPTR, the handle returned must be free'd by the calling code
+ // otherwise the controller will free it once done
+ tUSBIsochOp SendIsoch;
+ tUSBControlOp SendControl;
+ tUSBBulkOp SendBulk;
+ void (*FreeOp)(void *Ptr, void *Handle);
+
+ // Root hub stuff
void (*CheckPorts)(void *Ptr);
+ void (*SetPortFeature)(void *Ptr, int PortNum, int Feat);
+ void (*ClearPortFeature)(void *Ptr, int PortNum, int Feat);
+ int (*GetPortStatus)(void *Ptr, int PortNum, int Flag);
};
extern tUSBHub *USB_RegisterHost(tUSBHostDef *HostDef, void *ControllerPtr, int nPorts);
extern void USB_DeviceConnected(tUSBHub *Hub, int Port);
extern void USB_DeviceDisconnected(tUSBHub *Hub, int Port);
+#define PORT_CONNECTION 0
+#define PORT_ENABLE 1
+#define PORT_SUSPEND 2
+#define PORT_OVER_CURRENT 3
+#define PORT_RESET 4
+#define PORT_POWER 8
+#define PORT_LOW_SPEED 9
+#define C_PORT_CONNECTION 16
+#define C_PORT_ENABLE 17
+#define C_PORT_SUSPEND 18
+#define C_PORT_OVER_CURRENT 19
+#define C_PORT_RESET 20
+#define PORT_TEST 21
+#define PORT_INDICATOR 21
+
+extern void Hub_SetPortFeature(tUSBInterface *HubDev, int Port, int Feat);
+extern void Hub_ClearPortFeature(tUSBInterface *HubDev, int Port, int Feat);
+extern int Hub_GetPortStatus(tUSBInterface *HubDev, int Port, int Flag);
+
+extern void USB_PortCtl_BeginReset(tUSBHub *Hub, int Port);
+
#endif
// === IMPORTS ===
extern void USB_PollThread(void *unused);
extern void USB_AsyncThread(void *Unused);
+extern void USB_PortCtl_Init(void);
// === PROTOTYPES ===
int USB_Install(char **Arguments);
void USB_Cleanup(void);
-char *USB_ReadDir(tVFS_Node *Node, int Pos);
+ int USB_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX]);
tVFS_Node *USB_FindDir(tVFS_Node *Node, const char *Name);
int USB_IOCtl(tVFS_Node *Node, int Id, void *Data);
*/
int USB_Install(char **Arguments)
{
- Log_Warning("USB", "Not Complete - Devel Only");
-
+ USB_PortCtl_Init();
Proc_SpawnWorker(USB_PollThread, NULL);
Proc_SpawnWorker(USB_AsyncThread, NULL);
* \fn char *USB_ReadDir(tVFS_Node *Node, int Pos)
* \brief Read from the USB root
*/
-char *USB_ReadDir(tVFS_Node *Node, int Pos)
+int USB_ReadDir(tVFS_Node *Node, int Pos, char Dest[FILENAME_MAX])
{
- return NULL;
+ return -ENOTIMPL;
}
/**
--- /dev/null
+/*
+ * Acess2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * portctl.c
+ * - Port control code
+ */
+#define DEBUG 1
+#define SANITY 1
+#include <acess.h>
+#include "usb.h"
+#include <workqueue.h>
+#include <timers.h>
+#include <usb_hub.h>
+
+// === PROTOTYPES ===
+void USB_PortCtl_Init(void);
+void USB_PortCtl_Worker(void *Unused);
+void USB_PortCtl_SetPortFeature(tUSBHub *Hub, int Port, int Feat);
+void USB_PortCtl_ClearPortFeature(tUSBHub *Hub, int Port, int Feat);
+ int USB_PortCtl_GetPortStatus(tUSBHub *Hub, int Port, int Flag);
+
+// === GLOBALS ===
+tWorkqueue gUSB_PortCtl_WorkQueue;
+
+// === CODE ===
+void USB_PortCtl_Init(void)
+{
+ Workqueue_Init(&gUSB_PortCtl_WorkQueue, "USB Port Reset Work Queue", offsetof(tUSBHubPort, ListNext));
+ Proc_SpawnWorker(USB_PortCtl_Worker, NULL);
+}
+
+void USB_PortCtl_Worker(void *Unused)
+{
+ Threads_SetName("USB PortCtl Worker");
+ for(;;)
+ {
+ tUSBHubPort *port;
+ tUSBHub *hub;
+
+ port = Workqueue_GetWork(&gUSB_PortCtl_WorkQueue);
+ if( !port ) {
+ Log_Warning("USB", "PortCtl Workqueue returned NULL");
+ break;
+ }
+ hub = (tUSBHub*)(port - port->PortNum) - 1;
+
+ LOG("port = %p, hub = %p", port, hub);
+
+ switch(port->Status)
+ {
+ case 1:
+ // Assert reset
+ USB_PortCtl_SetPortFeature(hub, port->PortNum, PORT_RESET);
+ LOG("Port reset starting");
+ // Wait 50 ms
+ Time_Delay(50);
+ USB_PortCtl_ClearPortFeature(hub, port->PortNum, PORT_RESET);
+ Time_Delay(10); // May take up to 2ms for reset to clear
+ // Enable port
+ LOG("Port enabling");
+ USB_PortCtl_SetPortFeature(hub, port->PortNum, PORT_ENABLE);
+ // Begin connect processing
+ port->Status = 2;
+ USB_DeviceConnected(hub, port->PortNum);
+ break;
+ }
+ }
+}
+
+void USB_PortCtl_BeginReset(tUSBHub *Hub, int Port)
+{
+ LOG("Starting %p %i", Hub, Port);
+ // Set status field in hub structure
+ Hub->Ports[Port].Status = 1;
+ Hub->Ports[Port].PortNum = Port;
+ // Add to the work queue
+ Workqueue_AddWork(&gUSB_PortCtl_WorkQueue, &Hub->Ports[Port]);
+}
+
+void USB_PortCtl_SetPortFeature(tUSBHub *Hub, int Port, int Feat)
+{
+ if( Hub->Interface->Driver == NULL ) {
+ // - Host Port
+ tUSBHost *host = Hub->Interface->Dev->Host;
+ ASSERT(host->HostDef->SetPortFeature);
+ host->HostDef->SetPortFeature(host->Ptr, Port, Feat);
+ }
+ else {
+ // - Hub Port
+ Hub_SetPortFeature(Hub->Interface, Port, Feat);
+ }
+}
+
+void USB_PortCtl_ClearPortFeature(tUSBHub *Hub, int Port, int Feat)
+{
+ if( Hub->Interface->Driver == NULL ) {
+ // - Host Port
+ tUSBHost *host = Hub->Interface->Dev->Host;
+ ASSERT(host->HostDef->ClearPortFeature);
+ host->HostDef->ClearPortFeature(host->Ptr, Port, Feat);
+ }
+ else {
+ // - Hub Port
+ Hub_ClearPortFeature(Hub->Interface, Port, Feat);
+ }
+}
+
+int USB_PortCtl_GetPortStatus(tUSBHub *Hub, int Port, int Flag)
+{
+ if( Hub->Interface->Driver == NULL ) {
+ // - Host Port
+ tUSBHost *host = Hub->Interface->Dev->Host;
+ ASSERT(host->HostDef->GetPortStatus);
+ return host->HostDef->GetPortStatus(host->Ptr, Port, Flag);
+ }
+ else {
+ // - Hub Port
+ return Hub_GetPortStatus(Hub->Interface, Port, Flag);
+ }
+ return 0;
+}
+
{
tUSBHost *host;
- host = malloc(sizeof(tUSBHost) + nPorts*sizeof(void*));
+ host = malloc(sizeof(tUSBHost) + nPorts*sizeof(tUSBHubPort));
if(!host) {
// Oh, bugger.
return NULL;
host->RootHubDev.ParentHub = NULL;
host->RootHubDev.Host = host;
host->RootHubDev.Address = 0;
+ ASSERT(HostDef->InitControl);
+ host->RootHubDev.EndpointHandles[0] = HostDef->InitControl(ControllerPtr, 0, 64);
// host->RootHubIf.Next = NULL;
host->RootHubIf.Dev = &host->RootHubDev;
host->RootHub.Interface = &host->RootHubIf;
host->RootHub.nPorts = nPorts;
- memset(host->RootHub.Devices, 0, sizeof(void*)*nPorts);
+ memset(host->RootHub.Ports, 0, sizeof(tUSBHubPort)*nPorts);
// Append to list
Mutex_Acquire( &glUSB_Hosts );
{
tUSBHub *ret;
- ret = malloc(sizeof(tUSBHub) + sizeof(ret->Devices[0])*PortCount);
+ ret = malloc(sizeof(tUSBHub) + sizeof(ret->Ports[0])*PortCount);
ret->Interface = Device;
ret->nPorts = PortCount;
- memset(ret->Devices, 0, sizeof(ret->Devices[0])*PortCount);
+ memset(ret->Ports, 0, sizeof(ret->Ports[0])*PortCount);
return ret;
}
{
for( int i = 0; i < Hub->nPorts; i ++ )
{
- if( Hub->Devices[i] )
+ if( Hub->Ports[i].Dev )
{
USB_DeviceDisconnected( Hub, i );
}
#include <usb_core.h>
#include <usb_hub.h>
#include <usb_host.h>
+#include "usb_proto.h"
+typedef struct sUSBHubPort tUSBHubPort;
typedef struct sUSBHost tUSBHost;
typedef struct sUSBDevice tUSBDevice;
typedef struct sUSBEndpoint tUSBEndpoint;
// === STRUCTURES ===
+struct sUSBHubPort
+{
+ void *ListNext;
+ char Status;
+ char PortNum;
+ tUSBDevice *Dev;
+};
+
/**
* \brief USB Hub data
*/
tUSBInterface *Interface;
int nPorts;
- tUSBDevice *Devices[];
+ struct sUSBHubPort Ports[];
};
struct sUSBEndpoint
tUSBInterface *Interface;
int EndpointIdx; // Interface endpoint index
int EndpointNum; // Device endpoint num
+ void *EndpointHandle;
int PollingPeriod; // In 1ms intervals
int MaxPacketSize; // In bytes
tUSBDriver *Driver;
void *Data;
+
+ struct sDescriptor_Interface IfaceDesc;
int nEndpoints;
tUSBEndpoint Endpoints[];
tUSBHost *Host;
int Address;
+ void *EndpointHandles[16];
+
+ struct sDescriptor_Device DevDesc;
+
int nInterfaces;
tUSBInterface *Interfaces[];
};
* usb_devinit.c
* - USB Device Initialisation
*/
-#define DEBUG 1
+#define DEBUG 0
#include <acess.h>
#include <vfs.h>
#include <drv_pci.h>
#include "usb_proto.h"
#include "usb_lowlevel.h"
-#define DUMP_DESCRIPTORS 0
+#define DUMP_DESCRIPTORS 1
// === PROTOTYPES ===
void USB_DeviceConnected(tUSBHub *Hub, int Port);
void *USB_GetDeviceDataPtr(tUSBInterface *Dev);
void USB_SetDeviceDataPtr(tUSBInterface *Dev, void *Ptr);
int USB_int_AllocateAddress(tUSBHost *Host);
+void USB_int_DeallocateAddress(tUSBHost *Host, int Address);
// === CODE ===
void USB_DeviceConnected(tUSBHub *Hub, int Port)
tUSBDevice tmpdev;
tUSBDevice *dev = &tmpdev;
if( Port >= Hub->nPorts ) return ;
- if( Hub->Devices[Port] ) return ;
+ if( Hub->Ports[Port].Dev ) return ;
ENTER("pHub iPort", Hub, Port);
}
USB_int_SendSetupSetAddress(dev->Host, dev->Address);
LOG("Assigned address %i", dev->Address);
-
+
+ dev->EndpointHandles[0] = dev->Host->HostDef->InitControl(dev->Host->Ptr, dev->Address << 4, 64);
+ for( int i = 1; i < 16; i ++ )
+ dev->EndpointHandles[i] = 0;
+
// 2. Get device information
{
struct sDescriptor_Device desc;
+ desc.Length = 0;
LOG("Getting device descriptor");
// Endpoint 0, Desc Type 1, Index 0
USB_int_ReadDescriptor(dev, 0, 1, 0, sizeof(desc), &desc);
+ if( desc.Length < sizeof(desc) ) {
+ Log_Error("USB", "Device descriptor undersized (%i<%i)", desc.Length, sizeof(desc));
+ USB_int_DeallocateAddress(dev->Host, dev->Address);
+ LEAVE('-');
+ return;
+ }
+ if( desc.Type != 1 ) {
+ Log_Error("USB", "Device descriptor type invalid (%i!=1)", desc.Type);
+ USB_int_DeallocateAddress(dev->Host, dev->Address);
+ LEAVE('-');
+ return;
+ }
+
#if DUMP_DESCRIPTORS
LOG("Device Descriptor = {");
LOG(" .Length = %i", desc.Length);
LOG(" .Type = %i", desc.Type);
- LOG(" .USBVersion = 0x%04x", desc.USBVersion);
+ LOG(" .USBVersion = 0x%04x", LittleEndian16(desc.USBVersion));
LOG(" .DeviceClass = 0x%02x", desc.DeviceClass);
LOG(" .DeviceSubClass = 0x%02x", desc.DeviceSubClass);
LOG(" .DeviceProtocol = 0x%02x", desc.DeviceProtocol);
LOG(" .MaxPacketSize = 0x%02x", desc.MaxPacketSize);
- LOG(" .VendorID = 0x%04x", desc.VendorID);
- LOG(" .ProductID = 0x%04x", desc.ProductID);
- LOG(" .DeviceID = 0x%04x", desc.DeviceID);
+ LOG(" .VendorID = 0x%04x", LittleEndian16(desc.VendorID));
+ LOG(" .ProductID = 0x%04x", LittleEndian16(desc.ProductID));
+ LOG(" .DeviceID = 0x%04x", LittleEndian16(desc.DeviceID));
LOG(" .ManufacturerStr = Str %i", desc.ManufacturerStr);
LOG(" .ProductStr = Str %i", desc.ProductStr);
LOG(" .SerialNumberStr = Str %i", desc.SerialNumberStr);
- LOG(" .NumConfigurations = %i", desc.SerialNumberStr);
+ LOG(" .NumConfigurations = %i", desc.NumConfigurations);
LOG("}");
- #if DEBUG
+ #if DEBUG
if( desc.ManufacturerStr )
{
char *tmp = USB_int_GetDeviceString(dev, 0, desc.ManufacturerStr);
}
#endif
#endif
+
+ memcpy(&dev->DevDesc, &desc, sizeof(desc));
}
- // TODO: Support alternate configurations
-
// 3. Get configurations
+ // TODO: Support alternate configurations
for( int i = 0; i < 1; i ++ )
{
struct sDescriptor_Configuration desc;
size_t total_length;
USB_int_ReadDescriptor(dev, 0, 2, i, sizeof(desc), &desc);
+ if( desc.Length < sizeof(desc) ) {
+ // ERROR:
+ }
+ if( desc.Type != 2 ) {
+ // ERROR:
+ }
+ // TODO: Check return length? (Do we get a length?)
#if DUMP_DESCRIPTORS
LOG("Configuration Descriptor %i = {", i);
LOG(" .Length = %i", desc.Length);
}
#endif
+ if( desc.NumInterfaces == 0 ) {
+ Log_Notice("USB", "Device does not have any interfaces");
+ continue ;
+ }
+
// TODO: Split here and allow some method of selection
// Allocate device now that we have the configuration
total_length = LittleEndian16(desc.TotalLength);
full_buf = malloc( total_length );
USB_int_ReadDescriptor(dev, 0, 2, i, total_length, full_buf);
-
ptr_ofs += desc.Length;
- // TODO: Interfaces
+
+ // Interfaces!
for( int j = 0; ptr_ofs < total_length && j < desc.NumInterfaces; j ++ )
{
struct sDescriptor_Interface *iface;
LOG(" .InterfaceClass = 0x%x", iface->InterfaceClass);
LOG(" .InterfaceSubClass = 0x%x", iface->InterfaceSubClass);
LOG(" .InterfaceProcol = 0x%x", iface->InterfaceProtocol);
- # if DEBUG
if( iface->InterfaceStr ) {
char *tmp = USB_int_GetDeviceString(dev, 0, iface->InterfaceStr);
LOG(" .InterfaceStr = %i '%s'", iface->InterfaceStr, tmp);
free(tmp);
}
- # endif
LOG("}");
#endif
- dev_if = malloc(sizeof(tUSBInterface) + iface->NumEndpoints*sizeof(dev_if->Endpoints[0]));
+ dev_if = malloc(
+ sizeof(tUSBInterface)
+ + iface->NumEndpoints*sizeof(dev_if->Endpoints[0])
+ );
dev_if->Dev = dev;
dev_if->Driver = NULL;
dev_if->Data = NULL;
dev_if->nEndpoints = iface->NumEndpoints;
+ memcpy(&dev_if->IfaceDesc, iface, sizeof(*iface));
dev->Interfaces[j] = dev_if;
// Copy interface data
LOG(" .MaxPacketSize = %i", LittleEndian16(endpt->MaxPacketSize));
LOG(" .PollingInterval = %i", endpt->PollingInterval);
LOG("}");
-
+
+ // Make sure things don't break
+ if( !((endpt->Address & 0x7F) < 15) ) {
+ Log_Error("USB", "Endpoint number %i>16", endpt->Address & 0x7F);
+ k --;
+ continue ;
+ }
+
dev_if->Endpoints[k].Next = NULL;
dev_if->Endpoints[k].Interface = dev_if;
dev_if->Endpoints[k].EndpointIdx = k;
dev_if->Endpoints[k].Type = endpt->Attributes | (endpt->Address & 0x80);
dev_if->Endpoints[k].PollingAtoms = 0;
dev_if->Endpoints[k].InputData = NULL;
+
+ // TODO: Register endpoint early
+ int ep_num = endpt->Address & 15;
+ if( dev->EndpointHandles[ep_num] ) {
+ Log_Notice("USB", "Device %p:%i ep %i reused", dev->Host->Ptr, dev->Address, ep_num);
+ }
+ else {
+ int addr = dev->Address*16+ep_num;
+ int mps = dev_if->Endpoints[k].MaxPacketSize;
+ void *handle = NULL;
+ switch( endpt->Attributes & 3)
+ {
+ case 0: // Control
+ handle = dev->Host->HostDef->InitControl(dev->Host->Ptr, addr, mps);
+ break;
+ case 1: // Isochronous
+ // handle = dev->Host->HostDef->InitIsoch(dev->Host->Ptr, addr, mps);
+ break;
+ case 2: // Bulk
+ handle = dev->Host->HostDef->InitBulk(dev->Host->Ptr, addr, mps);
+ break;
+ case 3: // Interrupt
+ // handle = dev->Host->HostDef->InitInterrupt(dev->Host->Ptr, addr, ...);
+ break;
+ }
+ dev->EndpointHandles[ep_num] = handle;
+ }
}
// Initialise driver
);
}
else {
+ LOG("Driver '%s' in use", dev_if->Driver->Name);
dev_if->Driver->Connected(
dev_if,
full_buf + iface_base_ofs, ptr_ofs - iface_base_ofs
);
- // dev_if->Driver->Connected( dev_if );
}
}
free(full_buf);
}
-
+
+ Hub->Ports[Port].Dev = dev;
+
// Done.
LEAVE('-');
}
void USB_DeviceDisconnected(tUSBHub *Hub, int Port)
{
-
+ tUSBDevice *dev;
+ if( !Hub->Ports[Port].Dev ) {
+ Log_Error("USB", "Non-registered device disconnected");
+ return;
+ }
+ dev = Hub->Ports[Port].Dev;
+
+ // TODO: Free related resources
+ // - Endpoint registrations
+ for( int i = 0; i < 16; i ++ )
+ {
+ if(dev->EndpointHandles[i])
+ dev->Host->HostDef->RemEndpoint(dev->Host->Ptr, dev->EndpointHandles[i]);
+ }
+
+ // - Bus Address
+ USB_int_DeallocateAddress(dev->Host, dev->Address);
+ // - Inform handler
+ // - Release memory
+ free(dev);
+ Hub->Ports[Port].Dev = NULL;
}
void *USB_GetDeviceDataPtr(tUSBInterface *Dev) { return Dev->Data; }
--- /dev/null
+/*
+ * Acess 2 USB Stack
+ * - By John Hodge (thePowersGang)
+ *
+ * usb_info.c
+ * - USB Device Information Functions (helpers for drivers)
+ */
+#include <usb_core.h>
+#include "usb.h"
+#include "usb_lowlevel.h"
+
+// === CODE ===
+Uint32 USB_GetInterfaceClass(tUSBInterface *Dev)
+{
+ return ((Uint32)Dev->IfaceDesc.InterfaceClass << 16)
+ |((Uint32)Dev->IfaceDesc.InterfaceSubClass << 8)
+ |((Uint32)Dev->IfaceDesc.InterfaceProtocol << 0);
+}
+
+void USB_GetDeviceVendor(tUSBInterface *Dev, Uint16 *VendorID, Uint16 *DeviceID)
+{
+ *VendorID = LittleEndian16( Dev->Dev->DevDesc.VendorID );
+ *DeviceID = LittleEndian16( Dev->Dev->DevDesc.DeviceID );
+}
+char *USB_GetSerialNumber(tUSBInterface *Dev)
+{
+ return USB_int_GetDeviceString(Dev->Dev, 0, Dev->Dev->DevDesc.SerialNumberStr);
+}
+
#include "usb.h"
#include "usb_lowlevel.h"
#include <workqueue.h>
+#include <events.h>
#include "usb_async.h"
// === PROTOTYPES ===
void USB_ReadDescriptor(tUSBInterface *Iface, int Type, int Index, int Length, void *Data);
void USB_Request(tUSBInterface *Iface, int Endpoint, int Type, int Req, int Value, int Index, int Len, void *Data);
+void USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *Data);
+void USB_WakeCallback(void *Ptr, void *Buf, size_t Length);
void USB_AsyncCallback(void *Ptr, void *Buf, size_t Length);
void USB_AsyncThread(void *unused);
else
endpt = 0;
- USB_int_Request(Iface->Dev->Host, Iface->Dev->Address, endpt, Type, Req, Value, Index, Len, Data);
+ USB_int_Request(Iface->Dev, endpt, Type, Req, Value, Index, Len, Data);
}
-void USB_SendData(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
+void USB_SendData(tUSBInterface *Dev, int Endpoint, size_t Length, const void *Data)
{
- Log_Warning("USB", "TODO: Implement USB_SendData");
+ tUSBHost *host;
+ tUSBEndpoint *ep;
+ void *dest_hdl;
+ ENTER("pDev iEndpoint iLength pData", Dev, Endpoint, Length, Data);
+
+ host = Dev->Dev->Host;
+ ep = &Dev->Endpoints[Endpoint-1];
+ dest_hdl = Dev->Dev->EndpointHandles[ep->EndpointNum];
+ LOG("dest_hdl = %p", dest_hdl);
+ if( !dest_hdl ) {
+ Log_Notice("USB", "_SendData on uninitialised enpoint (%p#%i)", Dev->Dev, ep->EndpointNum);
+ LEAVE('-');
+ return;
+ }
+
+ Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
+ host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_WakeCallback, Proc_GetCurThread(), 1, (void*)Data, Length);
+ Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
+
+ LEAVE('-');
}
-void USB_RecvData(tUSBInterface *Dev, int Endpoint, int Length, void *Data)
+void USB_RecvData(tUSBInterface *Dev, int Endpoint, size_t Length, void *Data)
{
- Log_Warning("USB", "TODO: Implement USB_RecvData");
+ tUSBHost *host;
+ tUSBEndpoint *ep;
+ void *dest_hdl;
+ ENTER("pDev iEndpoint iLength pData", Dev, Endpoint, Length, Data);
+
+ host = Dev->Dev->Host;
+ ep = &Dev->Endpoints[Endpoint-1];
+ dest_hdl = Dev->Dev->EndpointHandles[ep->EndpointNum];
+ LOG("dest_hdl = %p", dest_hdl);
+ if( !dest_hdl ) {
+ Log_Notice("USB", "_RecvData on uninitialised enpoint (%p#%i)", Dev->Dev, ep->EndpointNum);
+ LEAVE('-');
+ return;
+ }
+
+ Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
+ host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_WakeCallback, Proc_GetCurThread(), 0, Data, Length);
+ Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
+
+ LEAVE('-');
}
-void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, int Length, void *DataBuf, tUSB_DataCallback Callback)
+void USB_RecvDataA(tUSBInterface *Dev, int Endpoint, size_t Length, void *DataBuf)
{
tAsyncOp *op;
tUSBHost *host;
+ void *dest_hdl;
ENTER("pDev iEndpoint iLength pDataBuf", Dev, Endpoint, Length, DataBuf);
op->Length = Length;
op->Data = DataBuf;
- // TODO: Handle transfers that are larger than one packet
- // TODO: Data toggle
-
host = Dev->Dev->Host;
+ dest_hdl = Dev->Dev->EndpointHandles[op->Endpt->EndpointNum];
+ if( !dest_hdl ) {
+ Log_Notice("USB", "_SendData on uninitialised enpoint (%p#%i)", Dev->Dev, op->Endpt->EndpointNum);
+ LEAVE('-');
+ return;
+ }
+
LOG("IN from %p %i:%i", host->Ptr, Dev->Dev->Address, op->Endpt->EndpointNum);
- host->HostDef->BulkIN(
- host->Ptr, Dev->Dev->Address*16 + op->Endpt->EndpointNum,
- 0, USB_AsyncCallback, op,
- DataBuf, Length
- );
+ host->HostDef->SendBulk(host->Ptr, dest_hdl, USB_AsyncCallback, op, 0, DataBuf, Length);
LEAVE('-');
// Log_Warning("USB", "TODO: Implement USB_RecvDataA");
}
+void USB_WakeCallback(void *Ptr, void *Buf, size_t Length)
+{
+ Threads_PostEvent(Ptr, THREAD_EVENT_SHORTWAIT);
+}
+
void USB_AsyncCallback(void *Ptr, void *Buf, size_t Length)
{
tAsyncOp *op = Ptr;
#include <events.h>
// === PROTOTYPES ===
-void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
+void *USB_int_Request(tUSBDevice *Dev, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
void USB_int_WakeThread(void *Thread, void *Data, size_t Length);
int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
int _UTF16to8(Uint16 *Input, int InputLen, char *Dest);
// === CODE ===
-void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
+void *USB_int_Request(tUSBDevice *Device, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data)
{
+ tUSBHost *Host = Device->Host;
void *hdl;
// TODO: Sanity check (and check that Type is valid)
struct sDeviceRequest req;
- int dest = Addr * 16 + EndPt; // TODO: Validate
tThread *thisthread = Proc_GetCurThread();
+ void *dest_hdl;
+
+ ENTER("pDevice xEndPt iType iReq iVal iIndx iLen pData",
+ Device, EndPt, Type, Req, Val, Indx, Len, Data);
- ENTER("pHost xdest iType iReq iVal iIndx iLen pData",
- Host, dest, Type, Req, Val, Indx, Len, Data);
+ if( EndPt < 0 || EndPt >= 16 ) {
+ LEAVE('n');
+ return NULL;
+ }
+
+ dest_hdl = Device->EndpointHandles[EndPt];
+ if( !dest_hdl ) {
+ LEAVE('n');
+ return NULL;
+ }
req.ReqType = Type;
req.Request = Req;
Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
- LOG("SETUP");
- hdl = Host->HostDef->ControlSETUP(Host->Ptr, dest, 0, &req, sizeof(req));
-
- // TODO: Data toggle?
- // TODO: Multi-packet transfers
- if( Len > 0 )
- {
- if( Type & 0x80 )
- {
- LOG("IN");
- hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, NULL, NULL, Data, Len);
-
- LOG("OUT (Status)");
- hdl = Host->HostDef->ControlOUT(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0);
- }
- else
- {
- LOG("OUT");
- Host->HostDef->ControlOUT(Host->Ptr, dest, 1, NULL, NULL, Data, Len);
-
- // Status phase (DataToggle=1)
- LOG("IN (Status)");
- hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0);
- }
+ LOG("Send");
+ if( Type & 0x80 ) {
+ // Inbound data
+ hdl = Host->HostDef->SendControl(Host->Ptr, dest_hdl, USB_int_WakeThread, thisthread, 0,
+ &req, sizeof(req),
+ NULL, 0,
+ Data, Len
+ );
}
- else
- {
- // Zero length, IN status
- LOG("IN (Status)");
- hdl = Host->HostDef->ControlIN(Host->Ptr, dest, 1, USB_int_WakeThread, thisthread, NULL, 0);
+ else {
+ // Outbound data
+ hdl = Host->HostDef->SendControl(Host->Ptr, dest_hdl, USB_int_WakeThread, thisthread, 1,
+ &req, sizeof(req),
+ Data, Len,
+ NULL, 0
+ );
}
LOG("Wait...");
Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address)
{
- USB_int_Request(Host, 0, 0, 0x00, 5, Address & 0x7F, 0, 0, NULL);
+ USB_int_Request(&Host->RootHubDev, 0, 0x00, 5, Address & 0x7F, 0, 0, NULL);
return 0;
}
int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest)
{
- const int ciMaxPacketSize = 0x400;
struct sDeviceRequest req;
- int bToggle = 0;
- void *final;
- int dest = Dev->Address*16 + Endpoint;
+ void *dest_hdl;
+
+ dest_hdl = Dev->EndpointHandles[Endpoint];
+ if( !dest_hdl ) {
+ return -1;
+ }
- ENTER("pDev xdest iType iIndex iLength pDest",
- Dev, dest, Type, Index, Length, Dest);
+ ENTER("pDev xEndpoint iType iIndex iLength pDest",
+ Dev, Endpoint, Type, Index, Length, Dest);
req.ReqType = 0x80;
req.ReqType |= ((Type >> 8) & 0x3) << 5; // Bits 5/6
req.Index = LittleEndian16( 0 ); // TODO: Language ID / Interface
req.Length = LittleEndian16( Length );
- LOG("SETUP");
- Dev->Host->HostDef->ControlSETUP(Dev->Host->Ptr, dest, 0, &req, sizeof(req));
-
- bToggle = 1;
- while( Length > ciMaxPacketSize )
- {
- LOG("IN (%i rem)", Length - ciMaxPacketSize);
- Dev->Host->HostDef->ControlIN(
- Dev->Host->Ptr, dest,
- bToggle, NULL, NULL,
- Dest, ciMaxPacketSize
- );
- bToggle = !bToggle;
- Length -= ciMaxPacketSize;
- }
-
- LOG("IN (final)");
- Dev->Host->HostDef->ControlIN( Dev->Host->Ptr, dest, bToggle, NULL, NULL, Dest, Length );
-
Threads_ClearEvent(THREAD_EVENT_SHORTWAIT);
- LOG("OUT (Status)");
- final = Dev->Host->HostDef->ControlOUT(
- Dev->Host->Ptr, dest, 1,
- USB_int_WakeThread, Proc_GetCurThread(),
- NULL, 0
+
+ LOG("Send");
+ Dev->Host->HostDef->SendControl(Dev->Host->Ptr, dest_hdl, USB_int_WakeThread, Proc_GetCurThread(), 0,
+ &req, sizeof(req),
+ NULL, 0,
+ Dest, Length
);
LOG("Waiting");
+ // TODO: Detect errors?
Threads_WaitEvents(THREAD_EVENT_SHORTWAIT);
-
+
LEAVE('i', 0);
return 0;
}
#ifndef _USB_LOWLEVEL_H_
#define _USB_LOWLEVEL_H_
-extern void *USB_int_Request(tUSBHost *Host, int Addr, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
+extern void *USB_int_Request(tUSBDevice *Dev, int EndPt, int Type, int Req, int Val, int Indx, int Len, void *Data);
extern int USB_int_SendSetupSetAddress(tUSBHost *Host, int Address);
extern int USB_int_ReadDescriptor(tUSBDevice *Dev, int Endpoint, int Type, int Index, int Length, void *Dest);
extern char *USB_int_GetDeviceString(tUSBDevice *Dev, int Endpoint, int Index);
endpt->InputData = malloc(endpt->MaxPacketSize);
LOG("Polling 0x%x at %i ms", Iface->Dev->Address * 16 + endpt->EndpointNum, endpt->PollingPeriod);
- Iface->Dev->Host->HostDef->InterruptIN(
- Iface->Dev->Host->Ptr,
- Iface->Dev->Address * 16 + endpt->EndpointNum,
- endpt->PollingPeriod,
+ Iface->Dev->Host->HostDef->InitInterrupt(
+ Iface->Dev->Host->Ptr, Iface->Dev->Address * 16 + endpt->EndpointNum,
+ 0, endpt->PollingPeriod,
USB_int_PollCallback, endpt,
endpt->InputData, endpt->MaxPacketSize
);
// Check hosts
for( tUSBHost *host = gUSB_Hosts; host; host = host->Next )
{
- host->HostDef->CheckPorts(host->Ptr);
+ if( host->HostDef->CheckPorts )
+ host->HostDef->CheckPorts(host->Ptr);
}
Time_Delay(100);
--- /dev/null
+#
+# Acess2 EHCI Driver
+#
+
+OBJ = ehci.o
+CPPFLAGS = -I../Core/include
+NAME = EHCI
+
+-include ../Makefile.tpl
--- /dev/null
+/*
+ * Acess2 EHCI Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * ehci.c
+ * - Driver Core
+ */
+#define DEBUG 1
+#define VERSION VER2(0,1)
+#include <acess.h>
+#include <modules.h>
+#include <usb_host.h>
+#include "ehci.h"
+#include <drv_pci.h>
+#include <limits.h>
+#include <events.h>
+#include <timers.h>
+
+// === CONSTANTS ===
+#define EHCI_MAX_CONTROLLERS 4
+#define EHCI_THREADEVENT_IOC THREAD_EVENT_USER1
+#define EHCI_THREADEVENT_PORTSC THREAD_EVENT_USER2
+
+// === PROTOTYPES ===
+ int EHCI_Initialise(char **Arguments);
+ int EHCI_Cleanup(void);
+ int EHCI_InitController(tPAddr BaseAddress, Uint8 InterruptNum);
+void EHCI_InterruptHandler(int IRQ, void *Ptr);
+// -- API ---
+void *EHCI_InitInterrupt(void *Ptr, int Endpoint, int bInput, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
+void *EHCI_InitIsoch (void *Ptr, int Endpoint, size_t MaxPacketSize);
+void *EHCI_InitControl(void *Ptr, int Endpoint, size_t MaxPacketSize);
+void *EHCI_InitBulk (void *Ptr, int Endpoint, size_t MaxPacketSize);
+void EHCI_RemEndpoint(void *Ptr, void *Handle);
+void *EHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData,
+ int isOutbound,
+ const void *SetupData, size_t SetupLength,
+ const void *OutData, size_t OutLength,
+ void *InData, size_t InLength
+ );
+void *EHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length);
+void EHCI_FreeOp(void *Ptr, void *Handle);
+Uint32 EHCI_int_RootHub_FeatToMask(int Feat);
+void EHCI_RootHub_SetPortFeature(void *Ptr, int Port, int Feat);
+void EHCI_RootHub_ClearPortFeature(void *Ptr, int Port, int Feat);
+ int EHCI_RootHub_GetPortStatus(void *Ptr, int Port, int Flag);
+// --- Internals ---
+tEHCI_qTD *EHCI_int_AllocateTD(tEHCI_Controller *Cont, int PID, void *Data, size_t Length, tUSBHostCb Cb, void *CbData);
+void EHCI_int_DeallocateTD(tEHCI_Controller *Cont, tEHCI_qTD *TD);
+void EHCI_int_AppendTD(tEHCI_Controller *Cont, tEHCI_QH *QH, tEHCI_qTD *TD);
+tEHCI_QH *EHCI_int_AllocateQH(tEHCI_Controller *Cont, int Endpoint, size_t MaxPacketSize);
+void EHCI_int_DeallocateQH(tEHCI_Controller *Cont, tEHCI_QH *QH);
+void EHCI_int_InterruptThread(void *ControllerPtr);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, USB_EHCI, EHCI_Initialise, NULL, "USB_Core", NULL);
+tEHCI_Controller gaEHCI_Controllers[EHCI_MAX_CONTROLLERS];
+tUSBHostDef gEHCI_HostDef = {
+ .InitInterrupt = EHCI_InitInterrupt,
+ .InitIsoch = EHCI_InitIsoch,
+ .InitControl = EHCI_InitControl,
+ .InitBulk = EHCI_InitBulk,
+ .RemEndpoint = EHCI_RemEndpoint,
+ .SendIsoch = NULL,
+ .SendControl = EHCI_SendControl,
+ .SendBulk = EHCI_SendBulk,
+ .FreeOp = EHCI_FreeOp,
+
+ .CheckPorts = NULL, // No need
+ .SetPortFeature = EHCI_RootHub_SetPortFeature,
+ .ClearPortFeature = EHCI_RootHub_ClearPortFeature,
+ .GetPortStatus = EHCI_RootHub_GetPortStatus,
+ };
+
+// === CODE ===
+int EHCI_Initialise(char **Arguments)
+{
+ for( int id = -1; (id = PCI_GetDeviceByClass(0x0C0320, 0xFFFFFF, id)) >= 0; )
+ {
+ Uint32 addr = PCI_GetBAR(id, 0);
+ if( addr == 0 ) {
+ // Oops, PCI BIOS emulation time
+ }
+ Uint8 irq = PCI_GetIRQ(id);
+ if( irq == 0 ) {
+ // TODO: The same
+ }
+
+ Log_Log("ECHI", "Controller at PCI %i 0x%x IRQ 0x%x",
+ id, addr, irq);
+
+ if( EHCI_InitController(addr, irq) )
+ {
+ // TODO: Detect other forms of failure than "out of slots"
+ break ;
+ }
+
+ // TODO: Register with the USB stack
+ }
+ return 0;
+}
+
+int EHCI_Cleanup(void)
+{
+ return 0;
+}
+
+// --- Driver Init ---
+int EHCI_InitController(tPAddr BaseAddress, Uint8 InterruptNum)
+{
+ tEHCI_Controller *cont = NULL;
+
+ for( int i = 0; i < EHCI_MAX_CONTROLLERS; i ++ )
+ {
+ if( gaEHCI_Controllers[i].PhysBase == 0 ) {
+ cont = &gaEHCI_Controllers[i];
+ cont->PhysBase = BaseAddress;
+ break;
+ }
+ }
+ if(!cont) {
+ Log_Notice("EHCI", "Too many controllers (EHCI_MAX_CONTROLLERS=%i)",
+ EHCI_MAX_CONTROLLERS);
+ return 1;
+ }
+
+ // - Nuke a couple of fields so error handling code doesn't derp
+ cont->CapRegs = NULL;
+ cont->PeriodicQueue = NULL;
+ cont->TDPool = NULL;
+
+ // -- Build up structure --
+ cont->CapRegs = (void*)MM_MapHWPages(BaseAddress, 1);
+ if( !cont->CapRegs ) {
+ Log_Warning("EHCI", "Can't map 1 page at %P into kernel space", BaseAddress);
+ goto _error;
+ }
+ // TODO: Error check
+ if( (cont->CapRegs->CapLength & 3) ) {
+ Log_Warning("EHCI", "Controller at %P non-aligned op regs", BaseAddress);
+ goto _error;
+ }
+ cont->OpRegs = (void*)( (Uint32*)cont->CapRegs + cont->CapRegs->CapLength / 4 );
+ // - Allocate periodic queue
+ tPAddr unused;
+ cont->PeriodicQueue = (void*)MM_AllocDMA(1, 32, &unused);
+ if( !cont->PeriodicQueue ) {
+ Log_Warning("ECHI", "Can't allocate 1 32-bit page for periodic queue");
+ goto _error;
+ }
+ for( int i = 0; i < 1024; i ++ )
+ cont->PeriodicQueue[i] = 1;
+ // TODO: Error check
+ // > Populate queue
+
+ // - Allocate TD pool
+ cont->TDPool = (void*)MM_AllocDMA(1, 32, &unused);
+ if( !cont->TDPool ) {
+ Log_Warning("ECHI", "Can't allocate 1 32-bit page for qTD pool");
+ goto _error;
+ }
+ for( int i = 0; i < TD_POOL_SIZE; i ++ ) {
+ cont->TDPool[i].Token = 3 << 8;
+ }
+
+ // Get port count
+ cont->nPorts = cont->CapRegs->HCSParams & 0xF;
+
+ // -- Bind IRQ --
+ IRQ_AddHandler(InterruptNum, EHCI_InterruptHandler, cont);
+ cont->InterruptThread = Proc_SpawnWorker(EHCI_int_InterruptThread, cont);
+ if( !cont->InterruptThread ) {
+ Log_Warning("EHCI", "Can't spawn interrupt worker thread");
+ goto _error;
+ }
+ LOG("cont->InterruptThread = %p", cont->InterruptThread);
+
+ // -- Initialisation procedure (from ehci-r10) --
+ // - Reset controller
+ cont->OpRegs->USBCmd = USBCMD_HCReset;
+ // - Set CTRLDSSEGMENT (TODO: 64-bit support)
+ // - Set USBINTR
+ cont->OpRegs->USBIntr = USBINTR_IOC|USBINTR_PortChange|USBINTR_FrameRollover;
+ // - Set PERIODICLIST BASE
+ cont->OpRegs->PeridocListBase = MM_GetPhysAddr( cont->PeriodicQueue );
+ // - Enable controller
+ cont->OpRegs->USBCmd = (0x40 << 16) | USBCMD_PeriodicEnable | USBCMD_Run;
+ // - Route all ports
+ cont->OpRegs->ConfigFlag = 1;
+
+ cont->DeadTD = EHCI_int_AllocateTD(cont, 0, NULL, 0, NULL, NULL);
+ cont->DeadTD->Link = 1;
+ cont->DeadTD->Link2 = 1;
+ cont->DeadTD->Token = 0;
+
+ // -- Register with USB Core --
+ cont->RootHub = USB_RegisterHost(&gEHCI_HostDef, cont, cont->nPorts);
+
+ return 0;
+_error:
+ cont->PhysBase = 0;
+ if( cont->CapRegs )
+ MM_Deallocate( (tVAddr)cont->CapRegs );
+ if( cont->PeriodicQueue )
+ MM_Deallocate( (tVAddr)cont->PeriodicQueue );
+ if( cont->TDPool )
+ MM_Deallocate( (tVAddr)cont->TDPool );
+ return 2;
+}
+
+void EHCI_InterruptHandler(int IRQ, void *Ptr)
+{
+ tEHCI_Controller *Cont = Ptr;
+ Uint32 sts = Cont->OpRegs->USBSts;
+
+ // Clear interrupts
+ Cont->OpRegs->USBSts = sts;
+
+ if( sts & 0xFFFF0FC0 ) {
+ LOG("Oops, reserved bits set (%08x), funny hardware?", sts);
+ sts &= ~0xFFFF0FFC0;
+ }
+
+ // Unmask read-only bits
+ sts &= ~(0xF000);
+
+ if( sts & USBINTR_IOC ) {
+ // IOC
+ Threads_PostEvent(Cont->InterruptThread, EHCI_THREADEVENT_IOC);
+ sts &= ~USBINTR_IOC;
+ }
+
+ if( sts & USBINTR_PortChange ) {
+ // Port change, determine what port and poke helper thread
+ LOG("Port status change");
+ Threads_PostEvent(Cont->InterruptThread, EHCI_THREADEVENT_PORTSC);
+ sts &= ~USBINTR_PortChange;
+ }
+
+ if( sts & USBINTR_FrameRollover ) {
+ // Frame rollover, used to aid timing (trigger per-second operations)
+ LOG("Frame rollover");
+ sts &= ~USBINTR_FrameRollover;
+ }
+
+ if( sts ) {
+ // Unhandled interupt bits
+ // TODO: Warn
+ LOG("WARN - Bitmask %x unhandled", sts);
+ }
+
+
+}
+
+// --------------------------------------------------------------------
+// USB API
+// --------------------------------------------------------------------
+void *EHCI_InitInterrupt(void *Ptr, int Endpoint, int bOutbound, int Period,
+ tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+{
+ tEHCI_Controller *Cont = Ptr;
+ int pow2period, period_pow;
+
+ if( Endpoint >= 256*16 )
+ return NULL;
+ if( Period <= 0 )
+ return NULL;
+ if( Period > 256 )
+ Period = 256;
+
+ // Round the period to the closest power of two
+ pow2period = 1;
+ period_pow = 0;
+ // - Find the first power above the period
+ while( pow2period < Period )
+ {
+ pow2period *= 2;
+ period_pow ++;
+ }
+ // - Check which is closest
+ if( Period - pow2period / 2 > pow2period - Period )
+ Period = pow2period;
+ else {
+ Period = pow2period/2;
+ period_pow --;
+ }
+
+ // Allocate a QH
+ tEHCI_QH *qh = EHCI_int_AllocateQH(Cont, Endpoint, Length);
+ qh->Impl.IntPeriodPow = period_pow;
+
+ Mutex_Acquire(&Cont->PeriodicListLock);
+
+ // Choose an interrupt slot to use
+ int minslot = 0, minslot_load = INT_MAX;
+ for( int slot = 0; slot < Period; slot ++ )
+ {
+ int load = 0;
+ for( int i = 0; i < PERIODIC_SIZE; i += Period )
+ load += Cont->InterruptLoad[i+slot];
+ if( load == 0 ) break;
+ if( load < minslot_load ) {
+ minslot = slot;
+ minslot_load = load;
+ }
+ }
+ // Increase loading on the selected slot
+ for( int i = minslot; i < PERIODIC_SIZE; i += Period )
+ Cont->InterruptLoad[i] += Length;
+ qh->Impl.IntOfs = minslot;
+
+ // Allocate TD for the data
+ tEHCI_qTD *td = EHCI_int_AllocateTD(Cont, (bOutbound ? PID_OUT : PID_IN), Buf, Length, Cb, CbData);
+ EHCI_int_AppendTD(Cont, qh, td);
+
+ // Insert into the periodic list
+ for( int i = 0; i < PERIODIC_SIZE; i += Period )
+ {
+ // Walk list until
+ // - the end is reached
+ // - this QH is found
+ // - A QH with a lower period is encountered
+ tEHCI_QH *pqh = NULL;
+ tEHCI_QH *nqh;
+ for( nqh = Cont->PeriodicQueueV[i]; nqh; pqh = nqh, nqh = nqh->Impl.Next )
+ {
+ if( nqh == qh )
+ break;
+ if( nqh->Impl.IntPeriodPow < period_pow )
+ break;
+ }
+
+ // Somehow, we've already been added to this queue.
+ if( nqh && nqh == qh )
+ continue ;
+
+ if( qh->Impl.Next && qh->Impl.Next != nqh ) {
+ Log_Warning("EHCI", "Suspected bookkeeping error on %p - int list %i+%i overlap",
+ Cont, period_pow, minslot);
+ break;
+ }
+
+ if( nqh ) {
+ qh->Impl.Next = nqh;
+ qh->HLink = MM_GetPhysAddr(nqh) | 2;
+ }
+ else {
+ qh->Impl.Next = NULL;
+ qh->HLink = 2|1; // QH, Terminate
+ }
+
+ if( pqh ) {
+ pqh->Impl.Next = qh;
+ pqh->HLink = MM_GetPhysAddr(qh) | 2;
+ }
+ else {
+ Cont->PeriodicQueueV[i] = qh;
+ Cont->PeriodicQueue[i] = MM_GetPhysAddr(qh) | 2;
+ }
+ }
+ Mutex_Release(&Cont->PeriodicListLock);
+
+ return qh;
+}
+
+void *EHCI_InitIsoch(void *Ptr, int Endpoint, size_t MaxPacketSize)
+{
+ return (void*)(tVAddr)(Endpoint + 1);
+}
+void *EHCI_InitControl(void *Ptr, int Endpoint, size_t MaxPacketSize)
+{
+ tEHCI_Controller *Cont = Ptr;
+
+ // Allocate a QH
+ tEHCI_QH *qh = EHCI_int_AllocateQH(Cont, Endpoint, MaxPacketSize);
+ qh->CurrentTD = MM_GetPhysAddr(Cont->DeadTD);
+
+ // Append to async list
+ if( Cont->LastAsyncHead ) {
+ Cont->LastAsyncHead->HLink = MM_GetPhysAddr(qh)|2;
+ Cont->LastAsyncHead->Impl.Next = qh;
+ LOG("- Placed after %p", Cont->LastAsyncHead);
+ }
+ else {
+ Cont->OpRegs->AsyncListAddr = MM_GetPhysAddr(qh)|2;
+ }
+ qh->HLink = Cont->OpRegs->AsyncListAddr;
+ Cont->OpRegs->USBCmd |= USBCMD_AsyncEnable;
+ Cont->LastAsyncHead = qh;
+
+ LOG("Created %p for %p Ep 0x%x - %i bytes MPS", qh, Ptr, Endpoint, MaxPacketSize);
+
+ return qh;
+}
+void *EHCI_InitBulk(void *Ptr, int Endpoint, size_t MaxPacketSize)
+{
+ return EHCI_InitControl(Ptr, Endpoint, MaxPacketSize);
+}
+void EHCI_RemEndpoint(void *Ptr, void *Handle)
+{
+ if( Handle == NULL )
+ return ;
+ else if( (tVAddr)Handle <= 256*16 )
+ return ; // Isoch
+ else {
+ tEHCI_QH *qh = Ptr;
+
+ // Remove QH from list
+ // - If it's a polling endpoint, need to remove from all periodic lists
+ if( qh->Impl.IntPeriodPow != 0xFF) {
+ // Poll
+ }
+ else {
+ // GP
+ }
+
+ // Deallocate QH
+ EHCI_int_DeallocateQH(Ptr, Handle);
+ }
+}
+
+void *EHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData,
+ int isOutbound,
+ const void *SetupData, size_t SetupLength,
+ const void *OutData, size_t OutLength,
+ void *InData, size_t InLength
+ )
+{
+ tEHCI_Controller *Cont = Ptr;
+ tEHCI_qTD *td_setup, *td_data, *td_status;
+
+ // Sanity checks
+ if( (tVAddr)Dest <= 256*16 )
+ return NULL;
+
+ // Check size of SETUP and status
+
+ // Allocate TDs
+ td_setup = EHCI_int_AllocateTD(Cont, PID_SETUP, (void*)SetupData, SetupLength, NULL, NULL);
+ if( isOutbound )
+ {
+ td_data = OutData ? EHCI_int_AllocateTD(Cont, PID_OUT, (void*)OutData, OutLength, NULL, NULL) : NULL;
+ td_status = EHCI_int_AllocateTD(Cont, PID_IN, InData, InLength, Cb, CbData);
+ }
+ else
+ {
+ td_data = InData ? EHCI_int_AllocateTD(Cont, PID_IN, InData, InLength, NULL, NULL) : NULL;
+ td_status = EHCI_int_AllocateTD(Cont, PID_OUT, (void*)OutData, OutLength, Cb, CbData);
+ td_status->Token |= (1 << 15); // IOC
+ }
+
+ // Append TDs
+ if( td_data ) {
+ td_setup->Link = MM_GetPhysAddr(td_data);
+ td_data->Link = MM_GetPhysAddr(td_status) | 1;
+ td_data->Token |= (1 << 8); // Active
+ }
+ else {
+ td_setup->Link = MM_GetPhysAddr(td_status) | 1;
+ }
+ td_setup->Token |= (1 << 8); // Active
+ td_status->Token |= (1 << 8);
+ EHCI_int_AppendTD(Cont, Dest, td_setup);
+
+ return td_status;
+}
+
+void *EHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length)
+{
+ tEHCI_Controller *Cont = Ptr;
+
+ // Sanity check the pointer
+ // - Can't be NULL or an isoch
+ if( (tVAddr)Dest <= 256*16 )
+ return NULL;
+
+ // Allocate single TD
+ tEHCI_qTD *td = EHCI_int_AllocateTD(Cont, (Dir ? PID_OUT : PID_IN), Data, Length, Cb, CbData);
+ EHCI_int_AppendTD(Cont, Dest, td);
+
+ return td;
+}
+
+void EHCI_FreeOp(void *Ptr, void *Handle)
+{
+ tEHCI_Controller *Cont = Ptr;
+
+ EHCI_int_DeallocateTD(Cont, Handle);
+}
+
+Uint32 EHCI_int_RootHub_FeatToMask(int Feat)
+{
+ switch(Feat)
+ {
+ case PORT_RESET: return PORTSC_PortReset;
+ case PORT_ENABLE: return PORTSC_PortEnabled;
+ default:
+ Log_Warning("EHCI", "Unknown root hub port feature %i", Feat);
+ return 0;
+ }
+}
+
+void EHCI_RootHub_SetPortFeature(void *Ptr, int Port, int Feat)
+{
+ tEHCI_Controller *Cont = Ptr;
+ if(Port >= Cont->nPorts) return;
+
+ Cont->OpRegs->PortSC[Port] |= EHCI_int_RootHub_FeatToMask(Feat);
+}
+
+void EHCI_RootHub_ClearPortFeature(void *Ptr, int Port, int Feat)
+{
+ tEHCI_Controller *Cont = Ptr;
+ if(Port >= Cont->nPorts) return;
+
+ Cont->OpRegs->PortSC[Port] &= ~EHCI_int_RootHub_FeatToMask(Feat);
+}
+
+int EHCI_RootHub_GetPortStatus(void *Ptr, int Port, int Flag)
+{
+ tEHCI_Controller *Cont = Ptr;
+ if(Port >= Cont->nPorts) return 0;
+
+ return !!(Cont->OpRegs->PortSC[Port] & EHCI_int_RootHub_FeatToMask(Flag));
+}
+
+// --------------------------------------------------------------------
+// Internals
+// --------------------------------------------------------------------
+tEHCI_qTD *EHCI_int_GetTDFromPhys(tEHCI_Controller *Cont, Uint32 Addr)
+{
+ if( Addr == 0 ) return NULL;
+ LOG("%p + (%x - %x)", Cont->TDPool, Addr, MM_GetPhysAddr(Cont->TDPool));
+ return Cont->TDPool + (Addr - MM_GetPhysAddr(Cont->TDPool))/sizeof(tEHCI_qTD);
+}
+
+tEHCI_qTD *EHCI_int_AllocateTD(tEHCI_Controller *Cont, int PID, void *Data, size_t Length, tUSBHostCb Cb, void *CbData)
+{
+// Semaphore_Wait(&Cont->TDSemaphore, 1);
+ Mutex_Acquire(&Cont->TDPoolMutex);
+ for( int i = 0; i < TD_POOL_SIZE; i ++ )
+ {
+ if( ((Cont->TDPool[i].Token >> 8) & 3) != 3 )
+ continue ;
+ Cont->TDPool[i].Token = (PID << 8) | (Length << 16);
+ // NOTE: Assumes that `Length` is <= PAGE_SIZE
+ Cont->TDPool[i].Pages[0] = MM_GetPhysAddr(Data);
+ if( (Cont->TDPool[i].Pages[0] & (PAGE_SIZE-1)) + Length - 1 > PAGE_SIZE )
+ Cont->TDPool[i].Pages[1] = MM_GetPhysAddr((char*)Data + Length - 1) & ~(PAGE_SIZE-1);
+ Mutex_Release(&Cont->TDPoolMutex);
+ LOG("Allocated %p for PID %i on %p", &Cont->TDPool[i], PID, Cont);
+ return &Cont->TDPool[i];
+ }
+
+ Mutex_Release(&Cont->TDPoolMutex);
+ return NULL;
+}
+
+void EHCI_int_DeallocateTD(tEHCI_Controller *Cont, tEHCI_qTD *TD)
+{
+ UNIMPLEMENTED();
+}
+
+void EHCI_int_AppendTD(tEHCI_Controller *Cont, tEHCI_QH *QH, tEHCI_qTD *TD)
+{
+ tEHCI_qTD *ptd = NULL;
+ Uint32 link = QH->CurrentTD;
+
+ // TODO: Need locking and validation here
+ while( link && !(link & 1) )
+ {
+ ptd = EHCI_int_GetTDFromPhys(Cont, link);
+ link = ptd->Link;
+ }
+ // TODO: Figure out how to follow this properly
+ if( !ptd ) {
+ QH->CurrentTD = MM_GetPhysAddr(TD);
+ LOG("Appended %p to beginning of %p", TD, QH);
+ }
+ else {
+ ptd->Link = MM_GetPhysAddr(TD);
+ LOG("Appended %p to end of %p", TD, QH);
+ }
+}
+
+tEHCI_QH *EHCI_int_AllocateQH(tEHCI_Controller *Cont, int Endpoint, size_t MaxPacketSize)
+{
+ tEHCI_QH *ret;
+ Mutex_Acquire(&Cont->QHPoolMutex);
+ for( int i = 0; i < QH_POOL_SIZE; i ++ )
+ {
+ if( !MM_GetPhysAddr( Cont->QHPools[i/QH_POOL_NPERPAGE] ) ) {
+ tPAddr tmp;
+ Cont->QHPools[i/QH_POOL_NPERPAGE] = (void*)MM_AllocDMA(1, 32, &tmp);
+ memset(Cont->QHPools[i/QH_POOL_NPERPAGE], 0, PAGE_SIZE);
+ }
+
+ ret = &Cont->QHPools[i/QH_POOL_NPERPAGE][i%QH_POOL_NPERPAGE];
+ if( ret->HLink == 0 ) {
+ ret->HLink = 1;
+ ret->Overlay.Link = 1;
+ ret->Endpoint = (Endpoint >> 4) | 0x80 | ((Endpoint & 0xF) << 8)
+ | (MaxPacketSize << 16);
+ // TODO: Endpoint speed (13:12) 0:Full, 1:Low, 2:High
+ // TODO: Control Endpoint Flag (27) 0:*, 1:Full/Low Control
+ Mutex_Release(&Cont->QHPoolMutex);
+ return ret;
+ }
+ }
+ Mutex_Release(&Cont->QHPoolMutex);
+ return NULL;
+}
+
+void EHCI_int_DeallocateQH(tEHCI_Controller *Cont, tEHCI_QH *QH)
+{
+ // TODO: Ensure it's unused (somehow)
+ QH->HLink = 0;
+}
+
+void EHCI_int_HandlePortConnectChange(tEHCI_Controller *Cont, int Port)
+{
+ // Connect Event
+ if( Cont->OpRegs->PortSC[Port] & PORTSC_CurrentConnectStatus )
+ {
+ // Is the device low-speed?
+ if( (Cont->OpRegs->PortSC[Port] & PORTSC_LineStatus_MASK) == PORTSC_LineStatus_Kstate )
+ {
+ LOG("Low speed device on %p Port %i, giving to companion", Cont, Port);
+ Cont->OpRegs->PortSC[Port] |= PORTSC_PortOwner;
+ }
+ // not a low-speed device, EHCI reset
+ else
+ {
+ LOG("Device connected on %p #%i", Cont, Port);
+ // Reset procedure.
+ USB_PortCtl_BeginReset(Cont->RootHub, Port);
+ }
+ }
+ // Disconnect Event
+ else
+ {
+ if( Cont->OpRegs->PortSC[Port] & PORTSC_PortOwner ) {
+ LOG("Companion port %i disconnected, taking it back", Port);
+ Cont->OpRegs->PortSC[Port] &= ~PORTSC_PortOwner;
+ }
+ else {
+ LOG("Port %i disconnected", Port);
+ USB_DeviceDisconnected(Cont->RootHub, Port);
+ }
+ }
+}
+
+void EHCI_int_InterruptThread(void *ControllerPtr)
+{
+ tEHCI_Controller *Cont = ControllerPtr;
+ while(Cont->OpRegs)
+ {
+ Uint32 events;
+
+ LOG("sleeping for events");
+ events = Threads_WaitEvents(EHCI_THREADEVENT_IOC|EHCI_THREADEVENT_PORTSC);
+ if( !events ) {
+ // TODO: Should this cause a termination?
+ }
+ LOG("events = 0x%x", events);
+
+ if( events & EHCI_THREADEVENT_IOC )
+ {
+ // IOC, Do whatever it is you do
+ }
+
+ // Port status change interrupt
+ if( events & EHCI_THREADEVENT_PORTSC )
+ {
+ // Check for port status changes
+ for(int i = 0; i < Cont->nPorts; i ++ )
+ {
+ Uint32 sts = Cont->OpRegs->PortSC[i];
+ LOG("Port %i: sts = %x", i, sts);
+ Cont->OpRegs->PortSC[i] = sts;
+ if( sts & PORTSC_ConnectStatusChange )
+ EHCI_int_HandlePortConnectChange(Cont, i);
+
+ if( sts & PORTSC_PortEnableChange )
+ {
+ // Handle enable/disable
+ }
+
+ if( sts & PORTSC_OvercurrentChange )
+ {
+ // Handle over-current change
+ }
+ }
+ }
+
+ LOG("Going back to sleep");
+ }
+}
#ifndef _EHCI_H_
#define _EHCI_H_
+#include <threads.h>
+
+#define PERIODIC_SIZE 1024
+
+typedef struct sEHCI_CapRegs tEHCI_CapRegs;
+typedef struct sEHCI_OpRegs tEHCI_OpRegs;
+typedef struct sEHCI_iTD tEHCI_iTD;
+typedef struct sEHCI_siTD tEHCI_siTD;
+typedef struct sEHCI_qTD tEHCI_qTD;
+typedef struct sEHCI_QH tEHCI_QH;
+typedef struct sEHCI_Controller tEHCI_Controller;
+
struct sEHCI_CapRegs
{
Uint8 CapLength; // Byte offset of Operational registers
* 15 = Asynchronous Schedule Status
* 16:31 = Reserved ?(Zero)
*/
- Uint32 USBSts;
+ volatile Uint32 USBSts;
/**
* USB Interrupt Enable Register
*
*
* Bits 14:3 are used as n index into PeridocListBase
*/
- Uint32 FrIndex;
+ volatile Uint32 FrIndex;
/**
* Control Data Structure Segment Register
*
* 22 = Wake on Over-current Enable
* 23:31 = Reserved (ZERO)
*/
- Uint32 PortSC[15];
+ volatile Uint32 PortSC[15];
+};
+
+#define USBCMD_Run 0x0001
+#define USBCMD_HCReset 0x0002
+#define USBCMD_PeriodicEnable 0x0010
+#define USBCMD_AsyncEnable 0x0020
+
+#define USBINTR_IOC 0x0001
+#define USBINTR_Error 0x0002
+#define USBINTR_PortChange 0x0004
+#define USBINTR_FrameRollover 0x0008
+#define USBINTR_HostSystemError 0x0010
+#define USBINTR_AsyncAdvance 0x0020
+
+#define PORTSC_CurrentConnectStatus 0x0001
+#define PORTSC_ConnectStatusChange 0x0002
+#define PORTSC_PortEnabled 0x0004
+#define PORTSC_PortEnableChange 0x0008
+#define PORTSC_OvercurrentActive 0x0010
+#define PORTSC_OvercurrentChange 0x0020
+#define PORTSC_ForcePortResume 0x0040
+#define PORTSC_Suspend 0x0080
+#define PORTSC_PortReset 0x0100
+#define PORTSC_Reserved1 0x0200
+#define PORTSC_LineStatus_MASK 0x0C00
+#define PORTSC_LineStatus_SE0 0x0000
+#define PORTSC_LineStatus_Jstate 0x0400
+#define PORTSC_LineStatus_Kstate 0x0800
+#define PORTSC_LineStatus_Undef 0x0C00
+#define PORTSC_PortPower 0x1000
+#define PORTSC_PortOwner 0x2000
+#define PORTSC_PortIndicator_MASK 0xC000
+#define PORTSC_PortIndicator_Off 0x0000
+#define PORTSC_PortIndicator_Amber 0x4000
+#define PORTSC_PortIndicator_Green 0x800
+
+// Isochronous (High-Speed) Transfer Descriptor
+struct sEHCI_iTD
+{
+ Uint32 Link;
+ struct {
+ Uint16 Offset;
+ Uint16 LengthSts;
+ } Transactions[8];
+ // -- 0 --
+ // 0:6 - Device
+ // 7 - Reserved
+ // 8:11 - Endpoint
+ // -- 1 --
+ // 0:10 - Max packet size
+ // 11 - IN/OUT
+ Uint32 BufferPointers[8]; // Page aligned, low 12 bits are overloaded
+};
+
+// Split Transaction Isochronous Transfer Descriptor
+struct sEHCI_siTD
+{
+ Uint32 Link;
+ Uint32 Dest;
+ Uint32 uFrame;
+ Uint32 StatusLength;
+ Uint32 Page0;
+ Uint32 Page1;
+ Uint32 BackLink;
+};
+
+// Queue Element Transfer Descriptor
+struct sEHCI_qTD
+{
+ Uint32 Link;
+ Uint32 Link2; // Used when there's a short packet
+ Uint32 Token;
+ Uint32 Pages[5]; //First has offset in low 12 bits
+
+ // Internals (32 bytes = 4x 64-bit pointers)
+ tUSBHostCb *Callback;
+ void *CallbackData;
+ tEHCI_qTD *Next;
+} __attribute__((aligned(32)));
+// sizeof = 64
+
+// Queue Head
+struct sEHCI_QH
+{
+ Uint32 HLink; // Horizontal link
+ Uint32 Endpoint;
+ Uint32 EndpointExt;
+ Uint32 CurrentTD;
+ struct {
+ Uint32 Link;
+ Uint32 Link2;
+ Uint32 Token;
+ Uint32 Pages[5];
+ } Overlay;
+ struct {
+ Uint8 IntOfs;
+ Uint8 IntPeriodPow;
+ tEHCI_QH *Next;
+ } Impl;
+} __attribute__((aligned(32)));
+// sizeof = 48 (round up to 64)
+
+#define PID_OUT 0
+#define PID_IN 1
+#define PID_SETUP 2
+
+#define TD_POOL_SIZE (PAGE_SIZE/sizeof(tEHCI_qTD))
+// - 256 addresses * 16 endpoints
+#define QH_POOL_SIZE (256*16)
+#define QH_POOL_PAGES (QH_POOL_SIZE*sizeof(tEHCI_QH)/PAGE_SIZE)
+#define QH_POOL_NPERPAGE (PAGE_SIZE/sizeof(tEHCI_QH))
+
+struct sEHCI_Controller
+{
+ tUSBHub *RootHub;
+ tThread *InterruptThread;
+ int nPorts;
+
+ tPAddr PhysBase;
+ tEHCI_CapRegs *CapRegs;
+ tEHCI_OpRegs *OpRegs;
+
+ tEHCI_qTD *DeadTD;
+
+ int InterruptLoad[PERIODIC_SIZE];
+ tEHCI_QH *LastAsyncHead;
+
+ tMutex PeriodicListLock;
+ Uint32 *PeriodicQueue;
+ tEHCI_QH *PeriodicQueueV[PERIODIC_SIZE];
+
+ tMutex QHPoolMutex;
+ tEHCI_QH *QHPools[QH_POOL_PAGES]; // [PAGE_SIZE/64]
+ tMutex TDPoolMutex;
+ tEHCI_qTD *TDPool; // [TD_POOL_SIZE]
};
#endif
info->Info = NULL;
info->CollectionDepth = 1;
info->bIsBoot = 1; // TODO: Detect non-boot keyboards and parse descriptor
- Log_Warning("USB HID", "TODO: Handle non-boot keyboards!");
+ Log_Warning("USB HID", "TODO: Detect and handle non-boot keyboards!");
info->Info = Keyboard_CreateInstance(0, "USBKeyboard");
}
}
// --- Read and parse report descriptor ---
// NOTE: Also does sub-driver selection and initialisation
- Uint8 *report_data = alloca(report_len);
+ Uint8 report_data[report_len];
USB_ReadDescriptor(Dev, 0x1022, 0, report_len, report_data);
HID_int_ParseReport(Dev, report_data, report_len, &gHID_RootCallbacks);
--- /dev/null
+#
+# Acess2 USB MSC Driver
+#
+
+OBJ = main.o scsi.o
+CPPFLAGS = -I../Core/include
+NAME = MSC
+
+-include ../Makefile.tpl
+
--- /dev/null
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * common.h
+ * - Common header
+ */
+#ifndef _MSC__COMMON_H_
+#define _MSC__COMMON_H_
+
+#include <usb_core.h>
+#include <Storage/LVM/include/lvm.h>
+
+typedef struct sMSCInfo tMSCInfo;
+
+struct sMSCInfo
+{
+ Uint64 BlockCount;
+ size_t BlockSize;
+};
+
+extern void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
+extern void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
+
+extern tLVM_VolType gMSC_SCSI_VolType;
+extern Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize);
+#endif
+
--- /dev/null
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Driver Core
+ */
+#define DEBUG 1
+#define VERSION VER2(0,1)
+#include <acess.h>
+#include <modules.h>
+#include "common.h"
+#include "msc_proto.h"
+
+// === PROTOTYPES ===
+ int MSC_Initialise(char **Arguments);
+ int MSC_Cleanup(void);
+void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen);
+void MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data);
+// --- Internal Helpers
+ int MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen);
+void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data);
+void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data);
+
+// === GLOBALS ===
+MODULE_DEFINE(0, VERSION, USB_MSC, MSC_Initialise, MSC_Cleanup, "USB_Core", NULL);
+tUSBDriver gMSC_Driver_BulkOnly = {
+ .Name = "MSC_BulkOnly",
+ .Match = {.Class = {0x080050, 0xFF00FF}},
+ .Connected = MSC_DeviceConnected,
+ .MaxEndpoints = 2,
+ .Endpoints = {
+ {0x82, MSC_DataIn},
+ {0x02, NULL},
+ }
+ };
+int giMSC_NextTag;
+
+// === CODE ===
+int MSC_Initialise(char **Arguments)
+{
+ USB_RegisterDriver( &gMSC_Driver_BulkOnly );
+ return 0;
+}
+
+int MSC_Cleanup(void)
+{
+ return 0;
+}
+
+void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen)
+{
+ tMSCInfo *info;
+ tLVM_VolType *vt;
+
+ info = malloc( sizeof(*info) );
+ USB_SetDeviceDataPtr(Dev, info);
+
+ // Get the class code (and hence what command set is in use)
+ Uint8 sc = (USB_GetInterfaceClass(Dev) & 0x00FF00) >> 8;
+ switch( sc )
+ {
+ // SCSI Transparent Command Set
+ case 0x06:
+ info->BlockCount = MSC_SCSI_GetSize(Dev, &info->BlockSize);
+ vt = &gMSC_SCSI_VolType;
+ break;
+ // Unknown, prepare to chuck sad
+ default:
+ Log_Error("USB MSC", "Unknown sub-class 0x%02x", sc);
+ USB_SetDeviceDataPtr(Dev, NULL);
+ free(info);
+ return ;
+ }
+
+ // Create device name from Vendor ID, Device ID and Serial Number
+ Uint16 vendor, devid;
+ char *serial_number;
+ USB_GetDeviceVendor(Dev, &vendor, &devid);
+ serial_number = USB_GetSerialNumber(Dev);
+ if( !serial_number ) {
+ // No serial number - this breaks spec, but it's easy to handle
+ Log_Warning("USB MSC", "Device does not have a serial number, using a random one");
+ serial_number = malloc(4+8+1);
+ sprintf(serial_number, "rand%08x", rand());
+ }
+ char name[4 + 4 + 1 + 4 + 1 + strlen(serial_number) + 1];
+ sprintf(name, "usb-%04x:%04x-%s", vendor, devid, serial_number);
+ free(serial_number);
+
+ // Pass the buck to LVM
+ LOG("Device '%s' has 0x%llx blocks of 0x%x bytes", name, info->BlockCount, info->BlockSize);
+ LVM_AddVolume(vt, name, Dev, info->BlockSize, info->BlockCount);
+}
+
+void MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data)
+{
+ // Will this ever be needed?
+}
+
+/**
+ * \brief Create a CBW structure
+ */
+int MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen)
+{
+ if( CmdLen == 0 ) {
+ Log_Error("MSC", "Zero length commands are invalid");
+ return -1;
+ }
+
+ if( CmdLen > 16 ) {
+ Log_Error("MSC", "Command data >16 bytes (%i)", CmdLen);
+ return -1;
+ }
+
+ Cbw->dCBWSignature = LittleEndian32(0x43425355);
+ Cbw->dCBWTag = giMSC_NextTag ++;
+ Cbw->dCBWDataTransferLength = LittleEndian32(DataLen);
+ Cbw->bmCBWFlags = (bInput ? 0x80 : 0x00);
+ Cbw->bCBWLUN = 0; // TODO: Logical Unit Number (param from proto)
+ Cbw->bCBWLength = CmdLen;
+ memcpy(Cbw->CBWCB, CmdData, CmdLen);
+
+ return 0;
+}
+
+void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data)
+{
+ tMSC_CBW cbw;
+ tMSC_CSW csw;
+ const int endpoint_out = 2;
+ const int endpoint_in = 1;
+
+ if( MSC_int_CreateCBW(&cbw, 0, CmdLen, CmdData, DataLen) )
+ return ;
+
+ // Send CBW
+ USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
+
+ // Send Data
+ USB_SendData(Dev, endpoint_out, DataLen, Data);
+
+ // Read CSW
+ USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
+ // TODO: Validate CSW
+}
+
+void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data)
+{
+ tMSC_CBW cbw;
+ tMSC_CSW csw;
+ const int endpoint_out = 2;
+ const int endpoint_in = 1;
+
+ if( MSC_int_CreateCBW(&cbw, 1, CmdLen, CmdData, DataLen) )
+ return ;
+
+ // Send CBW
+ USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw);
+
+ // Read Data
+ // TODO: use async version and wait for the transaction to complete
+ USB_RecvData(Dev, endpoint_in, DataLen, Data);
+
+ // Read CSW
+ USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw);
+ // TODO: Validate CSW
+}
+
--- /dev/null
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Driver Core
+ */
+#ifndef _MSC__MSC_PROTO_H_
+#define _MSC__MSC_PROTO_H_
+
+typedef struct sMSC_CBW tMSC_CBW;
+typedef struct sMSC_CSW tMSC_CSW;
+
+struct sMSC_CBW
+{
+ Uint32 dCBWSignature; // = 0x43425355
+ Uint32 dCBWTag;
+ Uint32 dCBWDataTransferLength;
+ Uint8 bmCBWFlags;
+ Uint8 bCBWLUN;
+ Uint8 bCBWLength;
+ Uint8 CBWCB[16];
+} PACKED;
+
+struct sMSC_CSW
+{
+ Uint32 dCSWSignature; // = 0x53425355
+ Uint32 dCSWTag;
+ Uint32 dCSWDataResidue;
+ Uint8 dCSWStatus;
+} PACKED;
+
+#endif
--- /dev/null
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * scsi.c
+ * - "SCSI Transparent Command Set" handling code
+ */
+#define DEBUG 0
+#include "common.h"
+#include "scsi.h"
+
+// === PROTOTYPES ===
+Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize);
+int MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest);
+int MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Dest);
+
+// === GLOBALS ===
+tLVM_VolType gMSC_SCSI_VolType = {
+ .Name = "USB-MSC-SCSI",
+ .Read = MSC_SCSI_ReadData,
+ .Write = MSC_SCSI_WriteData
+ };
+
+// === CODE ===
+Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize)
+{
+ struct sSCSI_Cmd_ReadCapacity16 cmd;
+ struct sSCSI_Ret_ReadCapacity16 ret;
+
+ cmd.Op = 0x9E;
+ cmd.Svc = 0x10;
+ cmd.LBA = BigEndian64( 0 );
+ cmd.AllocationLength = BigEndian32(sizeof(ret));
+ cmd.Flags = 0;
+ cmd.Control = 0;
+
+ ret.BlockSize = 0;
+ ret.BlockCount = 0;
+ MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret);
+
+ *BlockSize = BigEndian32(ret.BlockSize);
+ return BigEndian64(ret.BlockCount);
+}
+
+int MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest)
+{
+ tUSBInterface *Dev = Ptr;
+ tMSCInfo *info = USB_GetDeviceDataPtr(Dev);
+ struct sSCSI_Cmd_Read16 cmd;
+
+ // TODO: Bounds checking?
+
+ cmd.Op = 0x88;
+ cmd.Flags = 0;
+ cmd.LBA = BigEndian64(Block);
+ cmd.Length = BigEndian32(Count);
+ cmd.GroupNumber = 0;
+ cmd.Control = 0;
+
+ MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest);
+ // TODO: Error check
+
+ return Count;
+}
+
+int MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Data)
+{
+ Log_Warning("MSC_SCSI", "TODO: Impliment MSC_SCSI_WriteData");
+ return 0;
+}
+
--- /dev/null
+/*
+ * Acess2 USB Stack Mass Storage Driver
+ * - By John Hodge (thePowersGang)
+ *
+ * scsi.h
+ * - "SCSI Transparent Command Set" handling code
+ */
+#ifndef _MSC__SCSI_H_
+#define _MSC__SCSI_H_
+
+// NOTE: All commands are big-endian
+
+struct sSCSI_Cmd_ReadCapacity16
+{
+ Uint8 Op; // 0x9E
+ Uint8 Svc; // 0x10
+ Uint64 LBA; //
+ Uint32 AllocationLength;
+ Uint8 Flags;
+ Uint8 Control;
+} PACKED;
+
+struct sSCSI_Ret_ReadCapacity16
+{
+ Uint64 BlockCount;
+ Uint32 BlockSize;
+ Uint8 Flags;
+ Uint8 _resvd[32-13];
+} PACKED;
+
+struct sSCSI_Cmd_Read16
+{
+ Uint8 Op; // 0x88
+ Uint8 Flags;
+ Uint64 LBA;
+ Uint32 Length;
+ Uint8 GroupNumber;
+ Uint8 Control;
+} PACKED;
+
+#endif
+
void UHCI_int_AppendTD(tUHCI_Controller *Cont, tUHCI_QH *QH, tUHCI_TD *TD);
tUHCI_TD *UHCI_int_CreateTD(tUHCI_Controller *Cont, int Addr, Uint8 Type, int bTgl, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
// --- API
-void *UHCI_InterruptIN(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void UHCI_StopInterrupt(void *Ptr, void *Handle);
-void *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length);
-void *UHCI_ControlOUT(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length);
-void *UHCI_ControlIN(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length);
-void *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
-void *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length);
+void *UHCI_InitInterrupt(void *Ptr, int Endpt, int bOutbound, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len);
+void *UHCI_InitIsoch(void *Ptr, int Endpt, size_t MaxPacketSize);
+void *UHCI_InitControl(void *Ptr, int Endpt, size_t MaxPacketSize);
+void *UHCI_InitBulk(void *Ptr, int Endpt, size_t MaxPacketSize);
+void UHCI_RemoveEndpoint(void *Ptr, void *EndptHandle);
+void *UHCI_SendIsoch(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length, int When);
+void *UHCI_SendControl(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData,
+ int isOutbound,
+ const void *SetupData, size_t SetupLength,
+ const void *OutData, size_t OutLength,
+ void *InData, size_t InLength
+ );
+void *UHCI_SendBulk(void *Ptr, void *Dest, tUSBHostCb Cb, void *CbData, int Dir, void *Data, size_t Length);
void UHCI_CheckPortUpdate(void *Ptr);
void UHCI_int_InterruptThread(void *Unused);
tUHCI_TD *gaUHCI_TDPool;
tUHCI_Controller gUHCI_Controllers[MAX_CONTROLLERS];
tUSBHostDef gUHCI_HostDef = {
- .InterruptIN = UHCI_InterruptIN,
- .InterruptOUT = UHCI_InterruptOUT,
- .StopInterrupt = UHCI_StopInterrupt,
+ .InitInterrupt = UHCI_InitInterrupt,
+// .InitIsoch = UHCI_InitIsoch,
+ .InitControl = UHCI_InitControl,
+ .InitBulk = UHCI_InitBulk,
+ .RemEndpoint = UHCI_RemoveEndpoint,
- .ControlSETUP = UHCI_ControlSETUP,
- .ControlIN = UHCI_ControlIN,
- .ControlOUT = UHCI_ControlOUT,
-
- .BulkOUT = UHCI_BulkOUT,
- .BulkIN = UHCI_BulkIN,
+// .SendIsoch = UHCI_SendIsoch,
+ .SendControl = UHCI_SendControl,
+ .SendBulk = UHCI_SendBulk,
+ .FreeOp = NULL,
- .CheckPorts = UHCI_CheckPortUpdate
+ .CheckPorts = UHCI_CheckPortUpdate,
+// .ClearPortFeature = NULL,
+// .GetBusState = NULL,
+// .GetPortStatus = NULL,
+// .SetPortFeature = NULL
};
tSemaphore gUHCI_InterruptSempahore;
1,17,9,25,5,21,13,29,3,19,11,27,7,23,15,31
};
for( int i = 0; i < 1024; i ++ ) {
- Uint32 addr = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->ControlQH );
+ Uint32 addr = MM_GetPhysAddr( &Host->TDQHPage->ControlQH );
Host->FrameList[i] = addr | 2;
}
for( int i = 0; i < 64; i ++ ) {
dest += _count; destphys += _count * sizeof(tUHCI_QH);
}
// Skip padding, and move to control QH
- dest->Next = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->BulkQH ) | 2;
+ dest->Next = MM_GetPhysAddr( &Host->TDQHPage->BulkQH ) | 2;
dest->Child = 1;
}
// Set up control and bulk queues
- Host->TDQHPage->ControlQH.Next = MM_GetPhysAddr( (tVAddr)&Host->TDQHPage->BulkQH ) | 2;
+ Host->TDQHPage->ControlQH.Next = MM_GetPhysAddr( &Host->TDQHPage->BulkQH ) | 2;
Host->TDQHPage->ControlQH.Child = 1;
Host->TDQHPage->BulkQH.Next = 1;
Host->TDQHPage->BulkQH.Child = 1;
// Add
TD->Link = 1;
if( QH->Child & 1 ) {
- QH->Child = MM_GetPhysAddr( (tVAddr)TD );
+ QH->Child = MM_GetPhysAddr( TD );
}
else {
// Depth first
- QH->_LastItem->Link = MM_GetPhysAddr( (tVAddr)TD ) | 4;
+ QH->_LastItem->Link = MM_GetPhysAddr( TD ) | 4;
}
QH->_LastItem = TD;
if(
((tVAddr)Data & (PAGE_SIZE-1)) + Length > PAGE_SIZE
#if PHYS_BITS > 32
- || MM_GetPhysAddr( (tVAddr)Data ) >> 32
+ || MM_GetPhysAddr( Data ) >> 32
#endif
)
{
LOG("Relocated IN");
info = calloc( sizeof(tUHCI_ExtraTDInfo), 1 );
info->Offset = ((tVAddr)Data & (PAGE_SIZE-1));
- info->FirstPage = MM_GetPhysAddr( (tVAddr)Data );
- info->SecondPage = MM_GetPhysAddr( (tVAddr)Data + Length - 1 );
+ info->FirstPage = MM_GetPhysAddr( Data );
+ info->SecondPage = MM_GetPhysAddr( (const char *)Data + Length - 1 );
}
else
{
LOG("Relocated OUT/SETUP");
- tVAddr ptr = MM_MapTemp(td->BufferPointer);
- memcpy( (void*)ptr, Data, Length );
+ void *ptr = MM_MapTemp(td->BufferPointer);
+ memcpy( ptr, Data, Length );
MM_FreeTemp(ptr);
td->Control |= TD_CTL_IOC;
}
}
else
{
- td->BufferPointer = MM_GetPhysAddr( (tVAddr)Data );
+ td->BufferPointer = MM_GetPhysAddr( Data );
td->_info.bFreePointer = 0;
}
UHCI_int_AppendTD(Cont, qh, TD);
}
-void *UHCI_InterruptIN(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+// --------------------------------------------------------------------
+// API
+// --------------------------------------------------------------------
+void *UHCI_InitInterrupt(void *Ptr, int Endpt, int bOutbound,
+ int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Len)
{
tUHCI_TD *td;
-
- if( Period < 0 ) return NULL;
-
- ENTER("pPtr xDest iPeriod pCb pCbData pBuf iLength",
- Ptr, Dest, Period, Cb, CbData, Buf, Length);
+ if( Period <= 0 ) return NULL;
+
+ ENTER("pPtr xEndpt bbOutbound iPeriod pCb pCbData pBuf iLen",
+ Ptr, Endpt, bOutbound, Period, Cb, CbData, Buf, Len);
// TODO: Data toggle?
- td = UHCI_int_CreateTD(Ptr, Dest, PID_IN, 0, Cb, CbData, Buf, Length);
+ td = UHCI_int_CreateTD(Ptr, Endpt, (bOutbound ? PID_OUT : PID_IN), 0, Cb, CbData, Buf, Len);
if( !td ) return NULL;
UHCI_int_SetInterruptPoll(Ptr, td, Period);
-
- LEAVE('p', td);
+
+ LEAVE('p', td);
return td;
}
-// TODO: Does interrupt OUT make sense?
-void *UHCI_InterruptOUT(void *Ptr, int Dest, int Period, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+
+void *UHCI_int_InitEndpt(tUHCI_Controller *Cont, int Type, int Endpt, size_t MaxPacketSize)
{
- tUHCI_TD *td;
+ if( Endpt >= 256*16 )
+ return NULL;
- if( Period < 0 ) return NULL;
+ if( MaxPacketSize > MAX_PACKET_SIZE) {
+ Log_Warning("UHCI", "MaxPacketSize for %x greater than controller max (%i > %i)",
+ Endpt, MaxPacketSize, MAX_PACKET_SIZE);
+ return NULL;
+ }
- ENTER("pPtr xDest iPeriod pCb pCbData pBuf, iLength",
- Ptr, Dest, Period, Cb, CbData, Buf, Length);
+ if( Cont->DevInfo[Endpt / 16] == NULL ) {
+ Cont->DevInfo[Endpt / 16] = calloc( 1, sizeof(*Cont->DevInfo[0]) );
+ }
+ tUHCI_EndpointInfo *epi = &Cont->DevInfo[Endpt/16]->EndpointInfo[Endpt%16];
+ if( epi->Type ) {
+ // oops, in use
+ Log_Warning("UHCI", "Endpoint %x reused?", Endpt);
+ return NULL;
+ }
- // TODO: Data toggle?
- td = UHCI_int_CreateTD(Ptr, Dest, PID_OUT, 0, Cb, CbData, Buf, Length);
- if( !td ) return NULL;
-
- UHCI_int_SetInterruptPoll(Ptr, td, Period);
+ epi->MaxPacketSize = MaxPacketSize;
+ epi->Type = Type;
+ epi->Tgl = 0;
+
+ return (void*)(tVAddr)(Endpt+1);
- LEAVE('p', td);
- return td;
}
-void UHCI_StopInterrupt(void *Ptr, void *Handle)
+void *UHCI_InitControl(void *Ptr, int Endpt, size_t MaxPacketSize)
{
- // TODO: Stop interrupt transaction
- Log_Error("UHCI", "TODO: Implement UHCI_StopInterrupt");
+ return UHCI_int_InitEndpt(Ptr, 1, Endpt, MaxPacketSize);
}
-void *UHCI_ControlSETUP(void *Ptr, int Dest, int Tgl, void *Data, size_t Length)
+void *UHCI_InitBulk(void *Ptr, int Endpt, size_t MaxPacketSize)
{
- tUHCI_Controller *Cont = Ptr;
- tUHCI_QH *qh = &Cont->TDQHPage->ControlQH;
- tUHCI_TD *td;
+ return UHCI_int_InitEndpt(Ptr, 2, Endpt, MaxPacketSize);
+}
- ENTER("pPtr xDest iTgl pData iLength", Ptr, Dest, Tgl, Data, Length);
+void UHCI_RemoveEndpoint(void *Ptr, void *Handle)
+{
+ tUHCI_Controller *Cont = Ptr;
+ if( Handle == NULL )
+ return ;
- td = UHCI_int_CreateTD(Cont, Dest, PID_SETUP, Tgl, NULL, NULL, Data, Length);
- UHCI_int_AppendTD(Cont, qh, td);
-
- LEAVE('p', td);
-
- return td;
+ if( (tVAddr)Handle <= 256*16 ) {
+ int addr = (tVAddr)Handle;
+ Cont->DevInfo[addr/16]->EndpointInfo[addr%16].Type = 0;
+ }
+ else {
+ // TODO: Stop interrupt transaction
+ Log_Error("UHCI", "TODO: Implement stopping interrupt polling");
+ }
}
-void *UHCI_ControlOUT(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
+
+void *UHCI_SendControl(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData,
+ int bOutbound, // (1) SETUP, OUT, IN vs (0) SETUP, IN, OUT
+ const void *SetupData, size_t SetupLength,
+ const void *OutData, size_t OutLength,
+ void *InData, size_t InLength
+ )
{
+ ENTER("pPtr pEndpt ibOutbound", Ptr, Endpt, bOutbound);
+
tUHCI_Controller *Cont = Ptr;
tUHCI_QH *qh = &Cont->TDQHPage->ControlQH;
tUHCI_TD *td;
+ tUHCI_EndpointInfo *epi;
+ int dest, tgl;
+ size_t mps;
- ENTER("pPtr xDest iTgl pCb pCbData pData iLength", Ptr, Dest, Tgl, Cb, CbData, Data, Length);
+ if( Endpt == NULL ) {
+ Log_Error("UHCI", "Passed a NULL Endpoint handle");
+ LEAVE('n');
+ return NULL;
+ }
- td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, Tgl, Cb, CbData, Data, Length);
- UHCI_int_AppendTD(Cont, qh, td);
+ // Sanity check Endpt
+ if( (tVAddr)Endpt > 0x800 ) {
+ LEAVE('n');
+ return NULL;
+ }
+ dest = (tVAddr)Endpt - 1;
+ if( Cont->DevInfo[dest/16] == NULL ) LEAVE_RET('n', NULL);
+ epi = &Cont->DevInfo[dest/16]->EndpointInfo[dest%16];
+ if( epi->Type != 1 ) LEAVE_RET('n', NULL);
+ mps = epi->MaxPacketSize;
+ tgl = epi->Tgl;
+
+ // TODO: Build up list and then append to QH in one operation
+
+ char *data_ptr, *status_ptr;
+ size_t data_len, status_len;
+ Uint8 data_pid, status_pid;
+
+ if( bOutbound ) {
+ data_pid = PID_OUT; data_ptr = (void*)OutData; data_len = OutLength;
+ status_pid = PID_IN; status_ptr = InData; status_len = InLength;
+ }
+ else {
+ data_pid = PID_IN; data_ptr = InData; data_len = InLength;
+ status_pid = PID_OUT; status_ptr = (void*)OutData; status_len = OutLength;
+ }
- LEAVE('p', td);
- return td;
-}
-void *UHCI_ControlIN(void *Ptr, int Dest, int Tgl, tUSBHostCb Cb, void *CbData, void *Data, size_t Length)
-{
- tUHCI_Controller *Cont = Ptr;
- tUHCI_QH *qh = &Cont->TDQHPage->ControlQH;
- tUHCI_TD *td;
+ // Sanity check data lengths
+ if( SetupLength > mps ) LEAVE_RET('n', NULL);
+ if( status_len > mps ) LEAVE_RET('n', NULL);
- ENTER("pPtr xDest iTgl pCb pCbData pData iLength", Ptr, Dest, Tgl, Cb, CbData, Data, Length);
-
- td = UHCI_int_CreateTD(Cont, Dest, PID_IN, !!Tgl, Cb, CbData, Data, Length);
+ // Create and append SETUP packet
+ td = UHCI_int_CreateTD(Cont, dest, PID_SETUP, tgl, NULL, NULL, (void*)SetupData, SetupLength);
UHCI_int_AppendTD(Cont, qh, td);
+ tgl = !tgl;
- LEAVE('p', td);
+ // Send data packets
+ while( data_len > 0 )
+ {
+ size_t len = MIN(data_len, mps);
+ td = UHCI_int_CreateTD(Cont, dest, data_pid, tgl, NULL, NULL, data_ptr, len);
+ UHCI_int_AppendTD(Cont, qh, td);
+ tgl = !tgl;
+
+ data_ptr += len;
+ data_len -= len;
+ }
+
+ // Send status
+ td = UHCI_int_CreateTD(Cont, dest, status_pid, tgl, Cb, CbData, status_ptr, status_len);
+ UHCI_int_AppendTD(Cont, qh, td);
+ tgl = !tgl;
+
+ // Update toggle value
+ epi->Tgl = tgl;
+
+ LEAVE('p', td);
return td;
}
-void *UHCI_BulkOUT(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
+void *UHCI_SendBulk(void *Ptr, void *Endpt, tUSBHostCb Cb, void *CbData, int bOutbound, void *Data, size_t Length)
{
tUHCI_Controller *Cont = Ptr;
tUHCI_QH *qh = &Cont->TDQHPage->BulkQH;
- tUHCI_TD *td;
- char *src = Buf;
+ tUHCI_TD *td = NULL;
+ tUHCI_EndpointInfo *epi;
+ int dest, tgl;
+ size_t mps;
- ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length);
+ ENTER("pPtr pEndpt pCb pCbData bOutbound pData iLength", Ptr, Dest, Cb, CbData, bOutbound, Data, Length);
- while( Length > MAX_PACKET_SIZE )
- {
- LOG("MaxPacket (rem = %i)", Length);
- td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, NULL, NULL, src, MAX_PACKET_SIZE);
- UHCI_int_AppendTD(Cont, qh, td);
-
- bToggle = !bToggle;
- Length -= MAX_PACKET_SIZE;
- src += MAX_PACKET_SIZE;
+ if( Endpt == NULL ) {
+ Log_Error("UHCI", "_SendBulk passed a NULL endpoint handle");
+ LEAVE('n');
+ return NULL;
}
- LOG("Final");
- td = UHCI_int_CreateTD(Cont, Dest, PID_OUT, bToggle, NULL, NULL, src, Length);
- UHCI_int_AppendTD(Cont, qh, td);
+ // Sanity check Endpt
+ if( (tVAddr)Endpt > 256*16 ) {
+ Log_Error("UHCI", "_SendBulk passed an interrupt endpoint handle");
+ LEAVE('n');
+ return NULL;
+ }
+ dest = (tVAddr)Endpt - 1;
+ if( Cont->DevInfo[dest/16] == NULL ) {
+ Log_Error("UHCI", "_SendBulk passed an uninitialised handle");
+ LEAVE('n');
+ return NULL;
+ }
+ epi = &Cont->DevInfo[dest/16]->EndpointInfo[dest%16];
+ if( epi->Type != 2 ) {
+ Log_Error("UHCI", "_SendBulk passed an invalid endpoint type (%i!=2)", epi->Type);
+ LEAVE('n');
+ return NULL;
+ }
+ tgl = epi->Tgl;
+ mps = epi->MaxPacketSize;
- LEAVE('p', td);
- return td;
-}
-void *UHCI_BulkIN(void *Ptr, int Dest, int bToggle, tUSBHostCb Cb, void *CbData, void *Buf, size_t Length)
-{
- tUHCI_Controller *Cont = Ptr;
- tUHCI_QH *qh = &Cont->TDQHPage->BulkQH;
- tUHCI_TD *td;
- char *dst = Buf;
+ Uint8 pid = (bOutbound ? PID_OUT : PID_IN);
- ENTER("pPtr xDest ibToggle pCb pCbData pData iLength", Ptr, Dest, bToggle, Cb, CbData, Buf, Length);
- while( Length > MAX_PACKET_SIZE )
+ char *pos = Data;
+ while( Length > 0 )
{
- LOG("MaxPacket (rem = %i)", Length);
- td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, NULL, NULL, dst, MAX_PACKET_SIZE);
+ size_t len = MIN(mps, Length);
+
+ td = UHCI_int_CreateTD(Cont, dest, pid, tgl, Cb, (len == Length ? CbData : NULL), pos, len);
UHCI_int_AppendTD(Cont, qh, td);
- bToggle = !bToggle;
- Length -= MAX_PACKET_SIZE;
- dst += MAX_PACKET_SIZE;
+ pos += len;
+ Length -= len;
+ tgl = !tgl;
}
-
- LOG("Final");
- td = UHCI_int_CreateTD(Cont, Dest, PID_IN, bToggle, NULL, NULL, dst, Length);
- UHCI_int_AppendTD(Cont, qh, td);
+
+ epi->Tgl = tgl;
LEAVE('p', td);
return td;
}
+// ==========================
// === INTERNAL FUNCTIONS ===
+// ==========================
void UHCI_CheckPortUpdate(void *Ptr)
{
tUHCI_Controller *Host = Ptr;
}
- tPAddr global_pool = MM_GetPhysAddr( (tVAddr)gaUHCI_TDPool );
+ tPAddr global_pool = MM_GetPhysAddr( gaUHCI_TDPool );
if( PAddr < global_pool || PAddr >= global_pool + PAGE_SIZE ) return NULL;
{
char *src, *dest;
int src_ofs = TD->BufferPointer & (PAGE_SIZE-1);
- src = (void *) MM_MapTemp(TD->BufferPointer);
- dest = (void *) MM_MapTemp(info->FirstPage);
+ src = MM_MapTemp(TD->BufferPointer);
+ dest = MM_MapTemp(info->FirstPage);
// Check for a single page transfer
if( byte_count + info->Offset <= PAGE_SIZE )
{
TD->BufferPointer, info->FirstPage, info->SecondPage, TD);
int part_len = PAGE_SIZE - info->Offset;
memcpy(dest + info->Offset, src + src_ofs, part_len);
- MM_FreeTemp( (tVAddr)dest );
- dest = (void *) MM_MapTemp(info->SecondPage);
+ MM_FreeTemp( dest );
+ dest = MM_MapTemp(info->SecondPage);
memcpy(dest, src + src_ofs + part_len, byte_count - part_len);
}
- MM_FreeTemp( (tVAddr)src );
- MM_FreeTemp( (tVAddr)dest );
+ MM_FreeTemp( src );
+ MM_FreeTemp( dest );
}
// Callback
if( info->Callback != NULL )
{
LOG("Calling cb %p (%i bytes)", info->Callback, byte_count);
- void *ptr = (void *) MM_MapTemp( TD->BufferPointer );
+ void *ptr = MM_MapTemp( TD->BufferPointer );
info->Callback( info->CallbackPtr, ptr, byte_count );
- MM_FreeTemp( (tVAddr)ptr );
+ MM_FreeTemp( ptr );
}
// Clean up info
Uint16 status = _InWord(Host, USBSTS);
LOG("%p: status = 0x%04x", Ptr, status);
+
// Interrupt-on-completion
if( status & 1 )
{
Semaphore_Signal(&gUHCI_InterruptSempahore, 1);
}
+ // USB Error Interrupt
+ if( status & 2 )
+ {
+
+ }
+
+ // Resume Detect
+ // - Fired if in suspend state and a USB device sends the RESUME signal
+ if( status & 4 )
+ {
+
+ }
+
+ // Host System Error
+ if( status & 8 )
+ {
+
+ }
+
+ // Host Controller Process Error
+ if( status & 0x10 )
+ {
+ Log_Error("UHCI", "Host controller process error on controller %p", Ptr);
+ }
+
_OutWord(Host, USBSTS, status);
}
// === TYPES ===
typedef struct sUHCI_Controller tUHCI_Controller;
+typedef struct sUHCI_EndpointInfo tUHCI_EndpointInfo;
typedef struct sUHCI_ExtraTDInfo tUHCI_ExtraTDInfo;
typedef struct sUHCI_TD tUHCI_TD;
void *CallbackPtr;
};
-#define TD_CTL_IOC (1 << 24)
+struct sUHCI_EndpointInfo
+{
+ unsigned MaxPacketSize : 12;
+ unsigned Type : 3;
+ unsigned Tgl : 1;
+};
+#define TD_CTL_IOC (1 << 24)
#define TD_CTL_ACTIVE (1 << 23)
#define TD_CTL_STALLED (1 << 22)
#define TD_CTL_DATABUFERR (1 << 21)
*/
Uint32 Next;
-
/**
* \brief Next Entry in list
*
tUHCI_TD LocalTDPool[ (4096-(128+2)*sizeof(tUHCI_QH)) / sizeof(tUHCI_TD) ];
} *TDQHPage;
+
+ struct {
+ tUHCI_EndpointInfo EndpointInfo[16];
+ } *DevInfo[256];
};
// === ENUMERATIONS ===
ch.BGCol = (Colour & 0x0F0000) >> (16-8);
ch.BGCol |= (Colour & 0x000F00) >> (8-4);
ch.BGCol |= (Colour & 0x00000F);
+ ch.FGCol = 0;
word = VGA_int_GetWord(&ch);
Log("Fill (%i,%i) %ix%i with 0x%x", X, Y, W, H, word);
SUBMAKE = $(MAKE) --no-print-directory
USRLIBS := crt0.o acess.ld ld-acess.so libgcc.so libc.so
-USRLIBS += libreadline.so libnet.so liburi.so
+USRLIBS += libreadline.so libnet.so liburi.so libpsocket.so
USRLIBS += libimage_sif.so
USRAPPS := init login CLIShell cat ls mount
-USRAPPS += bomb dhcpclient
-USRAPPS += ip ping telnet irc
+USRAPPS += bomb lspci
+USRAPPS += ip dhcpclient ping telnet irc wget telnetd
USRAPPS += axwin3
ALL_DYNMODS = $(addprefix all-,$(DYNMODS))
+@$(SUBMAKE) clean -C Usermode/Applications/$*_src
# Install
+ifeq ($(ARCH),host)
+install-%:
+
+else
$(INSTALL_DYNMODS): install-%:
@$(_build_dynmod)$* install
$(INSTALL_MODULES): install-%:
@$(SUBMAKE) install -C Usermode/Libraries/$*_src
$(INSTALL_USRAPPS): install-%:
@$(SUBMAKE) install -C Usermode/Applications/$*_src
+endif
DRIVERS :=
MODULES :=
+MODULES += Filesystems/RAMDisk
MODULES += Filesystems/Ext2
MODULES += Filesystems/FAT
MODULES += Filesystems/NTFS
--- /dev/null
+=== Simple Image Format ===
+
+U16 Magic 0x51F0 - This determines the endianness of the file
+U16 Flags
+ > 0-2: Compression (0: Uncompressed, 1: RLE, 2: zlib, 3: RLE-Channel)
+ > 3-5: Format (0: ARGB, 1: RGB
+U16 Width
+U16 Height
+<DATA>
+
+
+=== Compression Formats ===
+0 - Uncompressed
+ The file data is a linear sequence of Width * Height 32-bit ARGB
+ words (in file endianness, determined by the magic)
+
+1 - RLE-4
+ 7-bit length followed by a 32-bit value that is repeated `n` times
+ (if bit 7 of the length byte is set, the next `n` 32-bit words are
+ verbatim)
+
+2 - zlib
+ The image data is a zlib stream of 32-bit xRGB words
+
+3 - RLE-Channel
+ The data is the alpha values, followed by red, then green, then blue
+ encoded as RLE with a 7-bit length and a verbatim flag (same as mode
+ 1, except with 8-bit values instead of 32-bit)
--- /dev/null
+Rationale:
+- Provides a method for ARM SoCs to use existing device drivers (e.g. USB ECHI) with minimal modifcation.
+
+Method possibilities
+# Hook in Kernel/drv/pci.c that enumerates the virtual bus using a fixed format.
QEMU=qemu-system-x86_64
USE_GDB=
+BOOTOPT="-fda DiskImage.img -boot a"
-QEMU_PARAMS="-fda DiskImage.img -boot a"
+QEMU_PARAMS=""
QEMU_PARAMS=$QEMU_PARAMS" -hda AcessHDD.img"
QEMU_PARAMS=$QEMU_PARAMS" -vga std"
QEMU_PARAMS=$QEMU_PARAMS" -smp 2"
-gdb)
QEMU_PARAMS=$QEMU_PARAMS" -s -S"
;;
+ -dbin)
+ shift
+ if [ "x$2" = "xdefault" ] || [ "x$2" = "x" ]; then
+ _kfile="KernelLand/Acess2.$1.bin"
+ else
+ _kfile="KernelLand/Acess2.$1-$2.bin"
+ fi
+ BOOTOPT="-kernel $_kfile"
+ BOOTOPT=$BOOTOPT" -initrd KernelLand/Modules/Filesystems/FS_InitRD.kmd.$1 -append $3"
+ shift
+ shift
+ ;;
-dbgbin)
QEMU=/home/tpg/apps/bin/qemu-system-x86_64
;;
+ -bin)
+ shift
+ QEMU=$1
+ ;;
+ -dbgscript)
+ QEMU="echo $QEMU"
+ ;;
-extramem)
QEMU_PARAMS=$QEMU_PARAMS" -m 768"
;;
-notee)
_NOTEE="yes"
;;
+ -nographic)
+ _NOGRAPHIC="yes"
+ ;;
esac
shift
done
if [ "x$_NOUSB" != "xyes" ] ; then
QEMU_PARAMS=$QEMU_PARAMS" -usb"
+ QEMU_PARAMS=$QEMU_PARAMS" -device usb-ehci"
QEMU_PARAMS=$QEMU_PARAMS" -drive id=test_usb_image,file=USB_Test_Image.img,if=none"
QEMU_PARAMS=$QEMU_PARAMS" -device usb-storage,drive=test_usb_image"
QEMU_PARAMS=$QEMU_PARAMS" -usbdevice mouse"
# /home/tpg/apps/bin/qemu-system-x86_64 $QEMU_PARAMS -serial stdio -serial file:QemuLog.txt
# qemu-system-x86_64 $QEMU_PARAMS -serial stdio | tee QemuLog.txt
-if [ "x$_NOTEE" != "xyes" ] ; then
- $QEMU $QEMU_PARAMS -serial stdio | tee QemuLog.txt
-else
- $QEMU $QEMU_PARAMS -serial stdio
+#echo $QEMU $BOOTOPT $QEMU_PARAMS
+if [ "x$_NOGRAPHIC" = "xyes" ] ; then
+ $QEMU $BOOTOPT $QEMU_PARAMS -nographic
+ exit
fi
+
+if [ "x$_NOTEE" = "xyes" ] ; then
+ $QEMU $BOOTOPT $QEMU_PARAMS -serial stdio
+ exit
+fi
+
+$QEMU $BOOTOPT $QEMU_PARAMS -serial stdio | tee QemuLog.txt
while [ $# -ne 0 ]; do
case $1 in
+ -raspberrypi)
+ _SYSTEM="versatilepb"
+ QEMU_PARAMS=$QEMU_PARAMS" -cpu arm1176 -m 192 -localtime"
+ _KERNEL=Acess2.armv6-raspberrypi.bin
+ ;;
-gdb)
QEMU_PARAMS=$QEMU_PARAMS" -s -S"
;;
esac
shift
done
-QEMU_PARAMS="-M $_SYSTEM -kernel $_KERNEL -net nic -net $_NETTYPE"$QEMU_PARAMS
+QEMU_PARAMS="-M $_SYSTEM -kernel KernelLand/$_KERNEL -net nic -net $_NETTYPE"$QEMU_PARAMS
# /home/tpg/apps/bin/qemu-system-x86_64 $QEMU_PARAMS -serial stdio -serial file:QemuLog.txt
# qemu-system-x86_64 $QEMU_PARAMS -serial stdio | tee QemuLog.txt
--- /dev/null
+TODO:
+
+=== Hardware ===
+- E1000 Driver (stubbed)
+ > Find specs
+ http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf
+ > Use bochs/qemu only as a backup
+
+- Cirrus 64-bit VisualMedia Accelerator
+ PCI 1013:00B8 (Cirrus CLGD5446)
+ > Specs avail?
+ Qemu Suggests http://home.worldonline.dk/~finth/
+ > Bochs/Qemu
+
+- UniChrome Driver
+
+- Sound Stack
+ > Intel 82801AA AC97 Audio (qemu)
+
+
+=== General Features ===
+- Init Scripts
+ > With an argument to init passed from the kernel?
+
+- #!
+ > Pass as argument? or pass pointer like ld-acess?
+ > argc/argv - Definitely
+
+- Network Debugging + IPv6 Autoconf
+ > Should IPv6 RAs be done in kernel mode, or usermode?
+ > Wait until something like linux's net.conf.ipv6.accept_ra is set?
+ > Have a custom suffix for stateless IPs?
+
+- Signals
+ > Add return value to mutexs and semaphores, and add warn_unused_ret
+
+
+=== Kernel Core ===
+- Virtual PCI bus for system configuration
+ > Hook in drv_pci.c, with an arch-defined array of devices
+ > Allow hooks on PCI config accesses (to emulate power management etc)
+
+- VFS Path caching
+ > Is it needed?
+ > Use a trie of path elements
+ - Trie on path content (with '/' included)
+ - Prefixed to reduce load
+ - Able to split
+ > Maintain backwards cache of elements
+ > Support symlink caching too
+
+- USB Stack
+ > Check validity
+ > (DONE) Rework HC API to support structure used by OHCI/ECHI
+
+- LVM Usablity
+ > /Devices/LVM/by-id/ and /Devices/LVM/by-label
+
+=== Userland ===
+- AxWin3
+ > Text editor (with a GP formatted text field?)
+ > Maybe a basic web browser using the surface support?
+ > Configuration (via lib/server)
+
+- Omnispeak
+ > Debug speed issues (tracing agian)
+ > Port to AxWin3
+ > (DONE) Trace memory corruption
+
+- Port dropbear!
--- /dev/null
+
+TARGET := $(shell gcc -v 2>&1 | grep Targ | awk '{print $$2}')
+
+include ../../../Makefile.Version.cfg
+-include Makefile.BuildNum
+ifeq ($(BUILD_NUM),)
+BUILD_NUM = 1
+endif
+
+
+KERNEL_SRC = ../../../KernelLand/Kernel/
+MODULE_SRC = ../../../KernelLand/Modules/
+
+BIN = ../DiskTool
+# Kernel Sources (compiled with -ffreestanding)
+K_OBJ := lib.o
+K_OBJ += vfs/main.o vfs/open.o vfs/acls.o vfs/io.o vfs/dir.o
+K_OBJ += vfs/nodecache.o vfs/mount.o vfs/memfile.o # vfs/select.o
+K_OBJ += vfs/fs/root.o vfs/fs/devfs.o
+K_OBJ += drvutil_disk.o drv/proc.o
+# Modules
+MODULES := Storage/LVM Filesystems/FAT Filesystems/Ext2 Filesystems/NTFS
+# Local kernel soruces (same as above, but located in same directory as Makefile)
+L_OBJ = vfs_handles.o threads.o nativefs.o time.o actions.o
+# Native Sources (compiled as usual)
+N_OBJ = main.o script.o logging.o helpers.o
+
+# Compilation Options
+CFLAGS := -Wall -std=gnu99 -g -Werror
+CPPFLAGS := -I include/
+K_CPPFLAGS := -I $(KERNEL_SRC)include -I $(MODULE_SRC)
+LDFLAGS += -Wl,--defsym,__buildnum=$(BUILD_NUM) -g
+
+BUILDINFO_OBJ := obj/$(TARGET)/buildinfo.o
+BUILDINFO_SRC := $(BUILDINFO_OBJ:%.o=%.c)
+
+# ====================
+# == Start of Magic ==
+# ====================
+# -- Load modules ---
+$(foreach module,$(MODULES), $(eval include $(MODULE_SRC)$(module)/Makefile) $(eval M_OBJ += $(addprefix $(module)/,$(OBJ))) )
+
+# -- Apply Prefixes to object paths
+OBJ_PREFIX = obj/$(TARGET)/
+K_OBJ_PREFIX = $(OBJ_PREFIX)_Kernel/
+M_OBJ_PREFIX = $(OBJ_PREFIX)_Module/
+K_OBJ := $(addprefix $(K_OBJ_PREFIX),$(K_OBJ))
+M_OBJ := $(addprefix $(M_OBJ_PREFIX),$(M_OBJ))
+L_OBJ := $(addprefix $(OBJ_PREFIX),$(L_OBJ))
+N_OBJ := $(addprefix $(OBJ_PREFIX),$(N_OBJ))
+
+OBJ := $(N_OBJ) $(L_OBJ) $(K_OBJ) $(M_OBJ) $(BUILDINFO_OBJ)
+
+DEPFILES = $(filter %.o,$(OBJ))
+DEPFILES := $(DEPFILES:%=%.dep)
+
+
+.PHONY: all clean
+
+all: $(BIN)
+
+clean:
+ $(RM) -f $(OBJ) $(DEPFILES) $(BIN)
+
+$(BIN): $(OBJ)
+ @echo [CC Link] -o $(BIN)
+ @$(CC) -o $(BIN) $(OBJ) $(LDFLAGS)
+ @echo BUILD_NUM = $$(( $(BUILD_NUM) + 1 )) > Makefile.BuildNum
+
+$(M_OBJ): $(M_OBJ_PREFIX)%.o: $(MODULE_SRC)%.c
+ @mkdir -p $(dir $@)
+ @echo [CC Module] -o $@
+ @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF
[email protected]
+
+$(K_OBJ): $(K_OBJ_PREFIX)%.o: $(KERNEL_SRC)%.c
+ @mkdir -p $(dir $@)
+ @echo [CC Kernel] -o $@
+ @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF
[email protected]
+
+$(L_OBJ): $(OBJ_PREFIX)%.o: %.c
+ @mkdir -p $(dir $@)
+ @echo [CC Local] -o $@
+ @$(CC) -c $< -o $@ -ffreestanding $(CFLAGS) $(CPPFLAGS) $(K_CPPFLAGS) -MMD -MP -MF
[email protected]
+
+$(N_OBJ): $(OBJ_PREFIX)%.o: %.c
+ @mkdir -p $(dir $@)
+ @echo [CC Native] -o $@
+
+# Hacky buildinfo.c file
+$(BUILDINFO_SRC): $(filter-out $(BUILDINFO_OBJ), $(OBJ)) Makefile
+ @echo "" > $@
+ @echo "const char gsKernelVersion[] = \"$(ACESS_VERSION)\";" >> $@
+ @echo "const char gsGitHash[] = \""`git log -n 1 | head -n 1 | awk '{print $$2}'`"\";" >> $@
+ @echo "const int giBuildNumber = $(BUILD_NUM);" >> $@
+ @echo "const char gsBuildInfo[] = \"Acess2 DiskTool v$(ACESS_VERSION)\";" >> $@
+$(BUILDINFO_OBJ): $(BUILDINFO_SRC)
+ @echo [CC] -o $@
+ @$(CC) -o $@ -c $< $(CFLAGS) $(CPPFLAGS)
+
+$(OBJ): Makefile
+
+-include $(DEPFILES)
--- /dev/null
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * actions.c
+ * - High level actions that call the VFS
+ * # Kernel-space compiled
+ */
+#include <acess.h>
+#include <disktool_common.h>
+#include <Storage/LVM/include/lvm.h>
+
+// === IMPORTS ===
+extern int NativeFS_Install(char **Arguments);
+extern int LVM_Cleanup(void);
+
+// === PROTOTYPES ===
+void DiskTool_Initialise(void) __attribute__((constructor(101)));
+void DiskTool_Cleanup(void);
+ int DiskTool_int_TranslateOpen(const char *File, int Mode);
+ int DiskTool_LVM_Read(void *Handle, Uint64 Block, size_t BlockCount, void *Dest);
+ int DiskTool_LVM_Write(void *Handle, Uint64 Block, size_t BlockCount, const void *Dest);
+void DiskTool_LVM_Cleanup(void *Handle);
+
+// === GLOBALS ===
+tLVM_VolType gDiskTool_VolumeType = {
+ .Name = "DiskTool",
+ .Read = DiskTool_LVM_Read,
+ .Write = DiskTool_LVM_Write,
+ .Cleanup = DiskTool_LVM_Cleanup
+};
+
+// === CODE ===
+void DiskTool_Initialise(void)
+{
+ VFS_Init();
+ NativeFS_Install(NULL);
+ VFS_MkDir("/Native");
+ VFS_Mount("/", "/Native", "nativefs", "");
+}
+
+void DiskTool_Cleanup(void)
+{
+ int vfs_rv, lvm_rv;
+ int nNochangeLoop = 0;
+ // Unmount all
+ do {
+ lvm_rv = LVM_Cleanup();
+ vfs_rv = VFS_UnmountAll();
+ Log_Debug("DiskTool", "Unmounted %i volumes", vfs_rv);
+ if( vfs_rv == 0 && lvm_rv == 0 ) {
+ nNochangeLoop ++;
+ if(nNochangeLoop == 2) {
+ Log_Error("DiskTool", "Possible handle leak");
+ break;
+ }
+ }
+ else {
+ nNochangeLoop = 0;
+ }
+ }
+ while( vfs_rv >= 0 || lvm_rv != 0 );
+}
+
+int DiskTool_RegisterLVM(const char *Identifier, const char *Path)
+{
+ int fd = DiskTool_int_TranslateOpen(Path, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE);
+ if(fd == -1) {
+ Log_Notice("DiskTool", "Can't open '%s' for LVM %s", Path, Identifier);
+ return -1;
+ }
+ VFS_Seek(fd, 0, SEEK_END);
+ LVM_AddVolume( &gDiskTool_VolumeType, Identifier, (void*)(tVAddr)fd, 512, VFS_Tell(fd)/512);
+ Log_Debug("DiskTool", "Registered '%s' for LVM %s", Path, Identifier);
+ return 0;
+}
+
+int DiskTool_MountImage(const char *Identifier, const char *Path)
+{
+ // Validate Identifier and make mountpoint string
+ char mountpoint[sizeof("/Mount/") + strlen(Identifier) + 1];
+ strcpy(mountpoint, "/Mount/");
+ strcat(mountpoint, Identifier);
+
+ // Translate path
+ size_t tpath_len = DiskTool_int_TranslatePath(NULL, Path);
+ char tpath[tpath_len-1];
+ DiskTool_int_TranslatePath(tpath, Path);
+
+ // Call mount
+ VFS_MkDir(mountpoint);
+ // TODO: Detect filesystem?
+ return VFS_Mount(tpath, mountpoint, "", "");
+}
+
+int DiskTool_MkDir(const char *Directory)
+{
+ return -1;
+}
+
+int DiskTool_Copy(const char *Source, const char *Destination)
+{
+ int src = DiskTool_int_TranslateOpen(Source, VFS_OPENFLAG_READ);
+ if( src == -1 ) {
+ Log_Error("DiskTool", "Unable to open %s for reading", Source);
+ return -1;
+ }
+ int dst = DiskTool_int_TranslateOpen(Destination, VFS_OPENFLAG_WRITE|VFS_OPENFLAG_CREATE);
+ if( dst == -1 ) {
+ Log_Error("DiskTool", "Unable to open %s for writing", Destination);
+ VFS_Close(src);
+ return -1;
+ }
+
+ char buf[1024];
+ size_t len, total = 0;
+ while( (len = VFS_Read(src, sizeof(buf), buf)) == sizeof(buf) ) {
+ VFS_Write(dst, len, buf);
+ total += len;
+ }
+ VFS_Write(dst, len, buf), total += len;
+
+ Log_Notice("DiskTool", "Copied %i from %s to %s", total, Source, Destination);
+
+ VFS_Close(dst);
+ VFS_Close(src);
+
+ return 0;
+}
+
+int DiskTool_ListDirectory(const char *Directory)
+{
+ int fd = DiskTool_int_TranslateOpen(Directory, VFS_OPENFLAG_READ|VFS_OPENFLAG_DIRECTORY);
+ if(fd == -1) {
+// fprintf(stderr, "Can't open '%s'\n", Directory);
+ return -1;
+ }
+
+ Log("Directory listing of '%s'", Directory);
+
+ char name[256];
+ while( VFS_ReadDir(fd, name) )
+ {
+ tFInfo fi;
+ int child = VFS_OpenChild(fd, name, 0);
+ if( child != -1 )
+ {
+ VFS_FInfo(child, &fi, 0);
+ VFS_Close(child);
+ }
+ Log("- %02x %6lli %s", fi.flags, fi.size, name);
+ }
+
+ VFS_Close(fd);
+
+ return 0;
+}
+
+int DiskTool_Cat(const char *File)
+{
+ int src = DiskTool_int_TranslateOpen(File, VFS_OPENFLAG_READ);
+ if( src == -1 ) {
+ Log_Error("DiskTool", "Unable to open %s for reading", File);
+ return -1;
+ }
+
+ char buf[1024];
+ size_t len, total = 0;
+ while( (len = VFS_Read(src, sizeof(buf), buf)) == sizeof(buf) ) {
+ _fwrite_stdout(len, buf);
+ total += len;
+ }
+ _fwrite_stdout(len, buf);
+ total += len;
+
+ Log_Notice("DiskTool", "%i bytes from %s", total, File);
+
+ VFS_Close(src);
+ return 0;
+}
+
+int DiskTool_LVM_Read(void *Handle, Uint64 Block, size_t BlockCount, void *Dest)
+{
+ return VFS_ReadAt( (int)(tVAddr)Handle, Block*512, BlockCount*512, Dest) / 512;
+}
+int DiskTool_LVM_Write(void *Handle, Uint64 Block, size_t BlockCount, const void *Dest)
+{
+ return VFS_WriteAt( (int)(tVAddr)Handle, Block*512, BlockCount*512, Dest) / 512;
+}
+void DiskTool_LVM_Cleanup(void *Handle)
+{
+ VFS_Close( (int)(tVAddr)Handle );
+}
+
+// --- Internal helpers ---
+int DiskTool_int_TranslateOpen(const char *File, int Flags)
+{
+ size_t tpath_len = DiskTool_int_TranslatePath(NULL, File);
+ if(tpath_len == 0)
+ return -1;
+ char tpath[tpath_len-1];
+ DiskTool_int_TranslatePath(tpath, File);
+
+ return VFS_Open(tpath, Flags);
+}
+
--- /dev/null
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * helpers.c
+ */
+#include <stdlib.h>
+#include <acess_logging.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+
+// === GLOBALS ===
+char gsWorkingDirectory[1024];
+
+
+// === CODE ===
+size_t DiskTool_int_TranslatePath(char *Buffer, const char *Path)
+{
+ int len;
+ const char *colon = strchr(Path, ':');
+
+ if( Path[0] == '#' )
+ {
+ len = strlen(Path+1);
+ if(Buffer) {
+ strcpy(Buffer, Path+1);
+ }
+ }
+ else if( Path[0] == ':' )
+ {
+ len = strlen("/Devices/LVM/");
+ len += strlen(Path+1);
+ if(Buffer) {
+ strcpy(Buffer, "/Devices/LVM/");
+ strcat(Buffer, Path+1);
+ }
+ }
+ else if( colon )
+ {
+ const char *pos;
+ for(pos = Path; pos < colon; pos ++)
+ {
+ if( !isalpha(*pos) )
+ goto native_path;
+ }
+
+ len = strlen("/Mount/");
+ len += strlen(Path);
+ if( Buffer ) {
+ strcpy(Buffer, "/Mount/");
+ strncat(Buffer+strlen("/Mount/"), Path, colon - Path);
+ strcat(Buffer, colon + 1);
+ }
+ }
+ else
+ {
+ native_path:
+ if( !gsWorkingDirectory[0] ) {
+ getcwd(gsWorkingDirectory, 1024);
+ }
+
+ len = strlen("/Native");
+ len += strlen( gsWorkingDirectory ) + 1;
+ len += strlen(Path);
+ if( Buffer ) {
+ strcpy(Buffer, "/Native");
+ strcat(Buffer, gsWorkingDirectory);
+ strcat(Buffer, "/");
+ strcat(Buffer, Path);
+ }
+ }
+ return len;
+}
--- /dev/null
+/*
+ * Acess2 DiskTool utility
+ * - By John Hodge (thePowersGang)
+ *
+ * include/acess.h
+ * - Mock kernel core header
+ */
+#ifndef _DISKTOOL__ACESS_H_
+#define _DISKTOOL__ACESS_H_
+
+#define CONCAT(x,y) x ## y
+#define EXPAND_CONCAT(x,y) CONCAT(x,y)
+#define STR(x) #x
+#define EXPAND_STR(x) STR(x)
+
+#define ASSERT(x) do{}while(0)
+
+extern char __buildnum[];
+#define BUILD_NUM ((int)(Uint)&__buildnum)
+extern const char gsGitHash[];
+extern const char gsBuildInfo[];
+
+#define BITS 32
+#define NULL ((void*)0)
+#include <stdint.h>
+
+typedef uintptr_t Uint;
+//typedef unsigned int size_t;
+#include <stddef.h>
+typedef uint64_t off_t;
+typedef char BOOL;
+
+
+typedef uint8_t Uint8;
+typedef uint16_t Uint16;
+typedef uint32_t Uint32;
+typedef uint64_t Uint64;
+
+typedef int8_t Sint8;
+typedef int16_t Sint16;
+typedef int32_t Sint32;
+typedef int64_t Sint64;
+
+typedef uintptr_t tVAddr;
+typedef uint32_t tPAddr;
+
+typedef uint32_t tUID;
+typedef uint32_t tGID;
+typedef uint32_t tTID;
+
+// NOTE: Since this is single-threaded (for now) mutexes can be implimented as simple locks
+typedef char tShortSpinlock;
+
+typedef int64_t tTime;
+extern tTime now(void);
+extern int64_t timestamp(int sec, int min, int hr, int day, int month, int year);
+extern void format_date(tTime TS, int *year, int *month, int *day, int *hrs, int *mins, int *sec, int *ms);
+
+#define PACKED __attribute__((packed))
+#define DEPRECATED
+#define EXPORT(s)
+#define EXPORTV(s)
+
+#include <vfs_ext.h>
+
+// These are actually library functions, but they can't be included, so they're defined manually
+extern void *malloc(size_t bytes);
+extern void *calloc(size_t nmemb, size_t size);
+extern void *realloc(void *oldptr, size_t bytes);
+extern void free(void *buffer);
+
+#include <errno.h>
+#include <acess_logging.h>
+
+// Threads
+extern int *Threads_GetErrno(void);
+//extern tPGID Threads_GetPGID(void);
+//extern tPID Threads_GetPID(void);
+extern tTID Threads_GetTID(void);
+extern tUID Threads_GetUID(void);
+extern tGID Threads_GetGID(void);
+
+// Kinda hacky way of not colliding with native errno
+#define errno (*(Threads_GetErrno()))
+
+/**
+ * \name Endianness Swapping
+ * \{
+ */
+#ifdef __BIG_ENDIAN__
+#define LittleEndian16(_val) SwapEndian16(_val)
+#define LittleEndian32(_val) SwapEndian32(_val)
+#define LittleEndian64(_val) SwapEndian32(_val)
+#define BigEndian16(_val) (_val)
+#define BigEndian32(_val) (_val)
+#define BigEndian64(_val) (_val)
+#else
+#define LittleEndian16(_val) (_val)
+#define LittleEndian32(_val) (_val)
+#define LittleEndian64(_val) (_val)
+#define BigEndian16(_val) SwapEndian16(_val)
+#define BigEndian32(_val) SwapEndian32(_val)
+#define BigEndian64(_val) SwapEndian64(_val)
+#endif
+extern Uint16 SwapEndian16(Uint16 Val);
+extern Uint32 SwapEndian32(Uint32 Val);
+extern Uint64 SwapEndian64(Uint64 Val);
+/**
+ * \}
+ */
+
+
+#include <string.h>
+extern int strucmp(const char *s1, const char *s2);
+extern int strpos(const char *Str, char Ch);
+extern void itoa(char *buf, uint64_t num, int base, int minLength, char pad);
+extern int snprintf(char *buf, size_t len, const char *fmt, ...);
+extern int sprintf(char *buf, const char *fmt, ...);
+extern int ReadUTF8(const Uint8 *str, Uint32 *Val);
+extern int WriteUTF8(Uint8 *str, Uint32 Val);
+#define CheckString(str) (1)
+#define CheckMem(mem,sz) (1)
+#include <ctype.h>
+
+// TODO: Move out?
+extern int DivUp(int value, int divisor);
+extern uint64_t DivMod64U(uint64_t Num, uint64_t Den, uint64_t *Rem);
+
+static inline void SHORTLOCK(tShortSpinlock *Lock) {
+ if(*Lock) Log_KernelPanic("---", "Double short lock");
+ *Lock = 1;
+}
+static inline void SHORTREL(tShortSpinlock *m) { *m = 0; }
+
+static inline intptr_t MM_GetPhysAddr(void *Ptr) { return 1; }
+
+#endif
+
--- /dev/null
+
+#ifndef _DISKTOOL__ACESS_LOGGING_H_
+#define _DISKTOOL__ACESS_LOGGING_H_
+
+#if DEBUG
+# define ENTER(str, v...) Debug_TraceEnter(__func__, str, ##v)
+# define LOG(fmt, v...) Debug_TraceLog(__func__, fmt, ##v)
+# define LEAVE(t, v...) Debug_TraceLeave(__func__, t, ##v)
+# define LEAVE_RET(t,v) do{LEAVE('-');return v;}while(0)
+#else
+# define ENTER(...) do{}while(0)
+# define LOG(...) do{}while(0)
+# define LEAVE(...) do{}while(0)
+# define LEAVE_RET(t,v) return v;
+#endif
+
+extern void Log_KernelPanic(const char *Ident, const char *Message, ...) __attribute__((noreturn));
+extern void Log_Panic(const char *Ident, const char *Message, ...);
+extern void Log_Error(const char *Ident, const char *Message, ...);
+extern void Log_Warning(const char *Ident, const char *Message, ...);
+extern void Log_Notice(const char *Ident, const char *Message, ...);
+extern void Log_Log(const char *Ident, const char *Message, ...);
+extern void Log_Debug(const char *Ident, const char *Message, ...);
+
+extern void Warning(const char *Message, ...);
+extern void Log(const char *Message, ...);
+extern void Debug_HexDump(const char *Prefix, const void *Data, size_t Length);
+
+extern void Debug_TraceEnter(const char *Function, const char *Format, ...);
+extern void Debug_TraceLog(const char *Function, const char *Format, ...);
+extern void Debug_TraceLeave(const char *Function, char Type, ...);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * include/disktool_common.h
+ * - DiskTool internal API between native and kernel code
+ */
+#ifndef _INCLUDE__DISKTOOL_COMMON_H_
+#define _INCLUDE__DISKTOOL_COMMON_H_
+
+extern void DiskTool_Cleanup(void);
+
+extern int DiskTool_RegisterLVM(const char *Identifier, const char *Path);
+extern int DiskTool_MountImage(const char *Identifier, const char *Path);
+extern int DiskTool_Copy(const char *Source, const char *Destination);
+extern int DiskTool_ListDirectory(const char *Directory);
+extern int DiskTool_Cat(const char *File);
+
+extern size_t DiskTool_int_TranslatePath(char *Buffer, const char *Path);
+
+extern size_t _fwrite_stdout(size_t bytes, const void *data);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * include/modules.h
+ * - Reimplimentation of kernel module interface for POSIX userland
+ */
+#ifndef _INCLUDE__MODULES_H_
+#define _INCLUDE__MODULES_H_
+
+enum
+{
+ MODULE_ERR_OK,
+};
+
+#define MODULE_DEFINE(flags, version, name, init, deinit, deps...) \
+void __init_##init(void) __attribute__((constructor(200))); void __init_##init(void){init(NULL);}
+
+#endif
+
--- /dev/null
+
+#ifndef _MUTEX_H_
+#define _MUTEX_H_
+
+typedef struct {
+ void *LockerReturnAddr;
+} tMutex;
+
+static inline int Mutex_Acquire(tMutex *m) {
+ if(m->LockerReturnAddr)
+ Log_KernelPanic("---", "Double mutex lock of %p by %p (was locked by %p)",
+ m, __builtin_return_address(0), m->LockerReturnAddr);
+ m->LockerReturnAddr = __builtin_return_address(0);;
+ return 0;
+}
+static inline void Mutex_Release(tMutex *m) { m->LockerReturnAddr = 0; }
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 Disk Tool
+ */
+#ifndef _RWLOCK_H
+#define _RWLOCK_H
+
+typedef char tRWLock;
+
+static inline int RWLock_AcquireRead(tRWLock *m) {
+ if(*m) Log_KernelPanic("---", "Double mutex lock");
+ *m = 1;
+ return 0;
+}
+static inline int RWLock_AcquireWrite(tRWLock *m) {
+ if(*m) Log_KernelPanic("---", "Double mutex lock");
+ *m = 1;
+ return 0;
+}
+static inline void RWLock_Release(tRWLock *m) { *m = 0; }
+
+#endif
+
--- /dev/null
+/*
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <acess_logging.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#define LOGHDR(col,type) fprintf(stderr, "\e["col"m[%-8.8s]"type" ", Ident)
+#define LOGTAIL() fprintf(stderr, "\e[0m\n")
+
+#define PUTERR(col,type) {\
+ LOGHDR(col,type);\
+ va_list args; va_start(args, Message);\
+ vfprintf(stderr, Message, args);\
+ va_end(args);\
+ LOGTAIL();\
+}
+
+// === CODE ===
+void Log_KernelPanic(const char *Ident, const char *Message, ...) {
+ PUTERR("35", "k")
+ abort();
+}
+void Log_Panic(const char *Ident, const char *Message, ...)
+ PUTERR("34", "p")
+void Log_Error(const char *Ident, const char *Message, ...)
+ PUTERR("31", "e")
+void Log_Warning(const char *Ident, const char *Message, ...)
+ PUTERR("33", "w")
+void Log_Notice(const char *Ident, const char *Message, ...)
+ PUTERR("32", "n")
+void Log_Log(const char *Ident, const char *Message, ...)
+ PUTERR("37", "l")
+void Log_Debug(const char *Ident, const char *Message, ...)
+ PUTERR("37", "d")
+
+void Warning(const char *Message, ...) {
+ const char *Ident = "";
+ PUTERR("33", "W")
+}
+void Log(const char *Message, ...) {
+ const char *Ident = "";
+ PUTERR("37", "L")
+}
+
+void Debug_HexDump(const char *Prefix, const void *Data, size_t Length)
+{
+ const uint8_t *data = Data;
+ size_t ofs;
+ fprintf(stderr, "[HexDump ]d %s: %i bytes\n", Prefix, (int)Length);
+ for( ofs = 0; ofs + 16 <= Length; ofs += 16 )
+ {
+ fprintf(stderr, "[HexDump ]d %s:", Prefix);
+ fprintf(stderr, " %02x %02x %02x %02x %02x %02x %02x %02x",
+ data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+ data += 8;
+ fprintf(stderr, " %02x %02x %02x %02x %02x %02x %02x %02x",
+ data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+ data += 8;
+ fprintf(stderr, "\n");
+ }
+
+ fprintf(stderr, "[HexDump ]d %s:", Prefix);
+ for( ; ofs < Length; ofs ++ )
+ {
+ if( ofs % 8 == 0 ) fprintf(stderr, " ");
+ fprintf(stderr, " %02x", data[ofs%16]);
+ }
+ fprintf(stderr, "\n");
+}
+
+ int giDebug_TraceLevel = 0;
+
+void Debug_TraceEnter(const char *Function, const char *Format, ...)
+{
+ const char *Ident = "Trace";
+ LOGHDR("37","T");
+ for( int i = 0; i < giDebug_TraceLevel; i ++ )
+ fprintf(stderr, " ");
+ fprintf(stderr, "%s: (", Function);
+
+ va_list args;
+ va_start(args, Format);
+
+ int hasBeenPrev = 0;
+ while(*Format)
+ {
+ while( *Format && isblank(*Format) )
+ Format ++;
+ if( !*Format ) break;
+
+ char type = *Format++;
+ const char *start = Format;
+ while( *Format && !isblank(*Format) )
+ Format ++;
+
+ if(hasBeenPrev)
+ fprintf(stderr, ",");
+ hasBeenPrev = 1;
+
+ fprintf(stderr, "%.*s=", (int)(Format-start), start);
+ switch(type)
+ {
+ case 'p':
+ fprintf(stderr, "%p", va_arg(args,const void *));
+ break;
+ case 's':
+ fprintf(stderr, "\"%s\"", va_arg(args,const char *));
+ break;
+ case 'i':
+ fprintf(stderr, "%i", va_arg(args,int));
+ break;
+ case 'x':
+ fprintf(stderr, "0x%x", va_arg(args,unsigned int));
+ break;
+ case 'X':
+ fprintf(stderr, "0x%"PRIx64, va_arg(args,uint64_t));
+ break;
+ default:
+ va_arg(args,uintptr_t);
+ fprintf(stderr, "?");
+ break;
+ }
+ }
+
+ va_end(args);
+
+ fprintf(stderr, ")");
+ LOGTAIL();
+ giDebug_TraceLevel ++;
+}
+
+void Debug_TraceLog(const char *Function, const char *Format, ...)
+{
+ const char *Ident = "Trace";
+ LOGHDR("37","T");
+
+ for( int i = 0; i < giDebug_TraceLevel; i ++ )
+ fprintf(stderr, " ");
+ fprintf(stderr, "%s: ", Function);
+
+ va_list args;
+ va_start(args, Format);
+
+ vfprintf(stderr, Format, args);
+
+ va_end(args);
+ LOGTAIL();
+}
+
+void Debug_TraceLeave(const char *Function, char Type, ...)
+{
+ if( giDebug_TraceLevel == 0 ) {
+ Log_Error("Debug", "Function %s called LEAVE without ENTER", Function);
+ }
+
+ const char *Ident = "Trace";
+ LOGHDR("37","T");
+
+ va_list args;
+ va_start(args, Type);
+
+ if( giDebug_TraceLevel > 0 )
+ {
+ giDebug_TraceLevel --;
+ for( int i = 0; i < giDebug_TraceLevel; i ++ )
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, "%s: RETURN", Function);
+ switch(Type)
+ {
+ case '-':
+ break;
+ case 'i':
+ fprintf(stderr, " %i", va_arg(args, int));
+ break;
+ case 'x':
+ fprintf(stderr, " 0x%x", va_arg(args, unsigned int));
+ break;
+ case 'X':
+ fprintf(stderr, " 0x%"PRIx64, va_arg(args,uint64_t));
+ break;
+ case 's':
+ fprintf(stderr, " \"%s\"", va_arg(args, const char *));
+ break;
+ case 'p':
+ fprintf(stderr, " %p", va_arg(args, const void *));
+ break;
+ case 'n':
+ fprintf(stderr, " NULL");
+ break;
+ default:
+ fprintf(stderr, " ?");
+ break;
+ }
+
+ va_end(args);
+ LOGTAIL();
+}
+
--- /dev/null
+/*
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <disktool_common.h>
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+ // Parse arguments
+ for( int i = 1; i < argc; i ++ )
+ {
+ if( strcmp("mount", argv[i]) == 0 || strcmp("-i", argv[i]) == 0 ) {
+ // Mount an image
+ if( argc - i < 3 ) {
+ fprintf(stderr, "mount takes 2 arguments (image and mountpoint)\n");
+ exit(-1);
+ }
+
+ if( DiskTool_MountImage(argv[i+2], argv[i+1]) ) {
+ fprintf(stderr, "Unable to mount '%s' as '%s'\n", argv[i+1], argv[i+2]);
+ break;
+ }
+
+ i += 2;
+ continue ;
+ }
+
+ if( strcmp("mountlvm", argv[i]) == 0 || strcmp("lvm", argv[i]) == 0 ) {
+
+ if( argc - i < 3 ) {
+ fprintf(stderr, "lvm takes 2 arguments (iamge and ident)\n");
+ exit(-1);
+ }
+
+ if( DiskTool_RegisterLVM(argv[i+2], argv[i+1]) ) {
+ fprintf(stderr, "Unable to register '%s' as LVM '%s'\n", argv[i+1], argv[i+2]);
+ break;
+ }
+
+ i += 2;
+ continue ;
+ }
+
+ if( strcmp("ls", argv[i]) == 0 ) {
+ if( argc - i < 2 ) {
+ fprintf(stderr, "ls takes 1 argument (path)\n");
+ break;
+ }
+
+ DiskTool_ListDirectory(argv[i+1]);
+ i += 1;
+ continue ;
+ }
+
+ if( strcmp("cp", argv[i]) == 0 ) {
+
+ if( argc - i < 3 ) {
+ fprintf(stderr, "cp takes 2 arguments (source and destination)\n");
+ break;
+ }
+
+ DiskTool_Copy(argv[i+1], argv[i+2]);
+
+ i += 2;
+ continue ;
+ }
+
+ if( strcmp("cat", argv[i]) == 0 ) {
+
+ if( argc - 1 < 2 ) {
+ fprintf(stderr, "cat takes 1 argument (path)\n");
+ break;
+ }
+
+ DiskTool_Cat(argv[i+1]);
+
+ i += 1;
+ continue;
+ }
+
+ fprintf(stderr, "Unknown command '%s'\n", argv[i]);
+ }
+
+ DiskTool_Cleanup();
+
+ return 0;
+}
+
+// NOTE: This is in a native compiled file because it needs access to the real errno macro
+int *Threads_GetErrno(void)
+{
+ return &errno;
+}
+
+// TODO: Move into a helper lib?
+void itoa(char *buf, uint64_t num, int base, int minLength, char pad)
+{
+ char fmt[] = "%0ll*x";
+ switch(base)
+ {
+ case 8: fmt[5] = 'o'; break;
+ case 10: fmt[5] = 'd'; break;
+ case 16: fmt[5] = 'x'; break;
+ }
+ if(pad != '0') {
+ fmt[1] = '%';
+ sprintf(buf, fmt+1, minLength, num);
+ }
+ else {
+ sprintf(buf, fmt, minLength, num);
+ }
+}
+
+int strpos(const char *Str, char Ch)
+{
+ const char *r = strchr(Str, Ch);
+ if(!r) return -1;
+ return r - Str;
+}
+
+int strucmp(const char *s1, const char *s2)
+{
+ return strcasecmp(s1, s2);
+}
+
+uint64_t DivMod64U(uint64_t value, uint64_t divisor, uint64_t *remainder)
+{
+ if(remainder)
+ *remainder = value % divisor;
+ return value / divisor;
+}
+
+size_t _fwrite_stdout(size_t bytes, const void *data)
+{
+ return fwrite(data, bytes, 1, stdout);
+}
--- /dev/null
+../../../AcessNative/acesskernel_src/nativefs.c
\ No newline at end of file
--- /dev/null
+/*
+ *
+ */
+#include <acess.h>
+#include <threads.h>
+
+// === CODE ===
+tThread *Proc_GetCurThread(void)
+{
+ return NULL;
+}
+
+void Threads_PostEvent(tThread *Thread, Uint32 Events)
+{
+
+}
+
+Uint32 Threads_WaitEvents(Uint32 Events)
+{
+ Log_KernelPanic("Threads", "Can't use _WaitEvents in DiskTool");
+ return 0;
+}
+
+void Threads_ClearEvent(Uint32 Mask)
+{
+
+}
+
+tUID Threads_GetUID(void) { return 0; }
+tGID Threads_GetGID(void) { return 0; }
+
+int *Threads_GetMaxFD(void) { static int max_fd=32; return &max_fd; }
+char **Threads_GetCWD(void) { static char *cwd; return &cwd; }
+char **Threads_GetChroot(void) { static char *chroot; return &chroot; }
+
--- /dev/null
+/*
+ * Acess2 DiskTool
+ * - By John Hodge (thePowersGang)
+ *
+ * time.c
+ * - Timing functions (emulated)
+ */
+#include <acess.h>
+#include <timers.h>
+
+// === CODE ===
+tTimer *Time_AllocateTimer(tTimerCallback *Callback, void *Argument)
+{
+ return NULL;
+}
+
+void Time_ScheduleTimer(tTimer *Timer, int Delta)
+{
+
+}
+
+void Time_FreeTimer(tTimer *Timer)
+{
+
+}
+
+Sint64 now(void)
+{
+ // TODO: Translate UNIX time into Acess time
+ return 0;
+}
+
--- /dev/null
+/*
+ *
+ */
+#include <acess.h>
+#include <vfs.h>
+#include <vfs_int.h>
+
+#define MAX_KERNEL_FILES 32
+
+// === GLOBALS ===
+tVFS_Handle gaKernelHandles[MAX_KERNEL_FILES];
+
+// === CODE ===
+int VFS_AllocHandle(int bIsUser, tVFS_Node *Node, int Mode)
+{
+ for( int i = 0; i < MAX_KERNEL_FILES; i ++ )
+ {
+ if(gaKernelHandles[i].Node) continue;
+ gaKernelHandles[i].Node = Node;
+ gaKernelHandles[i].Position = 0;
+ gaKernelHandles[i].Mode = Mode;
+ return i;
+ }
+
+ return -1;
+}
+
+tVFS_Handle *VFS_GetHandle(int ID)
+{
+ if( ID < 0 || ID >= MAX_KERNEL_FILES )
+ return NULL;
+ return &gaKernelHandles[ID];
+}
--- /dev/null
+#!/bin/bash
+
+# Get invocation path (which could be a symlink in $PATH)
+fullpath=`which "$0"`
+if [[ !$? ]]; then
+ fullpath="$0"
+fi
+
+# Resolve symlink
+fullpath=`readlink -f "$fullpath"`
+
+# Get base directory
+BASEDIR=`dirname "$fullpath"`
+
+cfgfile=`mktemp`
+make --no-print-directory -f $BASEDIR/getconfig.mk ARCH=x86 > $cfgfile
+#echo $cfgfile
+#cat $cfgfile
+. $cfgfile
+rm $cfgfile
+
+_miscargs=""
+_compile=0
+
+while [[ $# -gt 0 ]]; do
+ case "$1" in
+ -E)
+ _preproc=1
+ ;;
+ -c)
+ _compile=1
+ ;;
+ -o)
+ shift
+ _outfile="-o $1"
+ ;;
+ -I)
+ shift
+ _cflags=$_cflags" -I$1"
+ ;;
+ -I*|-D*|-O*)
+ _cflags=$_cflags" $1"
+ ;;
+ -Wl,*)
+ arg=$1
+ arg=${arg#-Wl}
+ arg=${arg/,/ }
+ _ldflags=$_ldflags" ${arg}"
+ ;;
+ -l)
+ shift
+ _libs=$_libs" -l$1"
+ ;;
+ -l*|-L*)
+ _libs=$_libs" $1"
+ ;;
+ *)
+ _miscargs=$_miscargs" $1"
+ ;;
+ esac
+ shift
+done
+
+run() {
+# echo $*
+ $*
+}
+
+if [[ $_preproc -eq 1 ]]; then
+ run $_CC -E $CFLAGS $_cflags $_miscargs $_outfile
+ exit $?
+fi
+if [[ $_compile -eq 1 ]]; then
+ run $_CC $CFLAGS $_cflags $_miscargs -c $_outfile
+ exit $?
+fi
+
+if echo " $_miscargs" | grep '\.c' >/dev/null; then
+ tmpout=`mktemp acess_gccproxy.XXXXXXXXXX.o --tmpdir`
+ run $_CC $CFLAGS $_miscargs -c -o $tmpout
+ run $_LD $LDFLAGS $_ldflags $_libs $tmpout $_outfile
+ rm $tmpout
+else
+ run $_LD $LDFLAGS $_ldflags $_miscargs $_outfile $LIBGCC_PATH
+fi
+
--- /dev/null
+include $(dir $(lastword $(MAKEFILE_LIST)))../../Usermode/Applications/Makefile.cfg
+
+.PHONY: shellvars
+
+shellvars:
+ @echo '_CC="$(CC)"'
+ @echo '_LD="$(LD)"'
+ @echo 'LDFLAGS="$(LDFLAGS)"'
+ @echo 'CFLAGS="$(CFLAGS)"'
+ @echo 'LIBGCC_PATH="$(LIBGCC_PATH)"'
\r
fileName = (char*)(tmpPath+dirLen);\r
// Read Directory Content\r
- while( (fp = readdir(dp, fileName)) )\r
+ while( (fp = SysReadDir(dp, fileName)) )\r
{\r
if(fp < 0)\r
{\r
include $(dir $(lastword $(MAKEFILE_LIST)))../Makefile.cfg
ASFLAGS = -felf
-CPPFLAGS = -I$(ACESSUSERDIR)/include/ -DARCHDIR_is_$(ARCHDIR)
+CPPFLAGS = -ffreestanding -I$(ACESSUSERDIR)/include/ -DARCHDIR_is_$(ARCHDIR)
+CPPFLAGS += $(addprefix -I,$(wildcard $(ACESSUSERDIR)Libraries/*/include_exp/))
CFLAGS = -fno-stack-protector $(CPPFLAGS)
LDFLAGS = -T $(OUTPUTDIR)Libs/acess.ld -rpath-link $(OUTPUTDIR)Libs -L $(OUTPUTDIR)Libs -I /Acess/Libs/ld-acess.so -lld-acess -lc $(OUTPUTDIR)Libs/crtbegin.o $(OUTPUTDIR)Libs/crtend.o
+LIBGCC_PATH = $(shell $(CC) -print-libgcc-file-name)
# Extra-verbose errors!
#CFLAGS += -Wall -Wextra -Wwrite-strings -Wshadow -Wswitch-default -Wswitch-enum -Wstrict-overflow=5 -Wfloat-equal -Wundef -Wmissing-declarations -Wlogical-op
@mkdir -p $(dir $(_BIN))
@echo [LD] -o $@
ifneq ($(_DBGMAKEFILE),)
- $(LD) -g $(LDFLAGS) -o $@ $(OBJ) -Map $(_OBJPREFIX)Map.txt
+ $(LD) -g $(LDFLAGS) -o $@ $(OBJ) -Map $(_OBJPREFIX)Map.txt $(LIBGCC_PATH)
else
- @$(LD) -g $(LDFLAGS) -o $@ $(OBJ) -Map $(_OBJPREFIX)Map.txt
+ @$(LD) -g $(LDFLAGS) -o $@ $(OBJ) -Map $(_OBJPREFIX)Map.txt $(LIBGCC_PATH)
endif
@$(DISASM) $(_BIN) > $(_OBJPREFIX)$(BIN).dsm
+++ /dev/null
-
-NAME = AxWin2
-DIRS = WM Shell_src
-
-SUBMAKE = $(MAKE) --no-print-directory
-
-all:
- @$(foreach DIR,$(DIRS), echo --- $(NAME)/$(DIR) && $(SUBMAKE) -C $(DIR) $@ &&) true
-install:
- @$(foreach DIR,$(DIRS), echo --- $(NAME)/$(DIR) && $(SUBMAKE) -C $(DIR) $@ &&) true
-
-clean:
- @$(foreach DIR,$(DIRS), $(SUBMAKE) -C $(DIR) $@ &&) true
+++ /dev/null
-=== Simple Image Format ===
-
-U16 Magic 0x51F0 - This determines the endianness of the file
-U16 Flags
- > 0-2: Compression (0: Uncompressed, 1: RLE, 2: zlib, 3: RLE-Channel)
- > 3-5: Format (0: ARGB, 1: RGB
-U16 Width
-U16 Height
-<DATA>
-
-
-=== Compression Formats ===
-0 - Uncompressed
- The file data is a linear sequence of Width * Height 32-bit ARGB
- words (in file endianness, determined by the magic)
-
-1 - RLE-4
- 7-bit length followed by a 32-bit value that is repeated `n` times
- (if bit 7 of the length byte is set, the next `n` 32-bit words are
- verbatim)
-
-2 - zlib
- The image data is a zlib stream of 32-bit xRGB words
-
-3 - RLE-Channel
- The data is the alpha values, followed by red, then green, then blue
- encoded as RLE with a 7-bit length and a verbatim flag (same as mode
- 1, except with 8-bit values instead of 32-bit)
+++ /dev/null
-# Project: Acess GUI Default Shell
-
--include ../../Makefile.cfg
-
-CPPFLAGS +=
-LDFLAGS += -laxwin2
-
-DIR = Apps/AxWin/1.0
-BIN = Shell
-OBJ = main.o
-
--include ../../Makefile.tpl
+++ /dev/null
-/*
- * Acess2 GUI Test App
- * - By John Hodge (thePowersGang)
- */
-#include <axwin2/axwin.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-// === CONSTANTS ===
-enum eTerminal_Events
-{
- EVENT_NULL,
- EVENT_NEW_TAB,
- EVENT_CLOSE_TAB,
- EVENT_EXIT
-};
-
-// === PROTOTYPES ===
- int main(int argc, char *argv[]);
- int Global_HandleMessage(tAxWin_Message *Message);
- int Shell_HandleMessage(tAxWin_Message *Message);
-
-// === GLOBALS ===
-tAxWin_Element *geConsole;
-
-// === CODE ===
-int main(int argc, char *argv[])
-{
- tAxWin_Element *menu, *tab;
-
- if(argc != 1)
- {
- fprintf(stderr, "Usage: %s\n", argv[0]);
- fprintf(stderr, "\tThis application takes no arguments\n");
- return 0;
- }
-
- AxWin_Register("Terminal", Global_HandleMessage);
-
- menu = AxWin_AddMenuItem(NULL, "File", 0);
- AxWin_AddMenuItem(menu, "&New Tab\tCtrl-Shift-N", EVENT_NEW_TAB);
- AxWin_AddMenuItem(menu, NULL, 0);
- AxWin_AddMenuItem(menu, "&Close Tab\tCtrl-Shift-W", EVENT_CLOSE_TAB);
- AxWin_AddMenuItem(menu, "E&xit\tAlt-F4", EVENT_EXIT);
-
- tab = AxWin_CreateWindow("root@acess: ~");
- //geConsole = AxWin_CreateElement();
-
- AxWin_MessageLoop();
-
- return 0;
-}
-
-/**
- */
-int Global_HandleMessage(tAxWin_Message *Message)
-{
- switch(Message->ID)
- {
- default:
- return 0;
- }
-}
-
-int Shell_HandleMessage(tAxWin_Message *Message)
-{
- switch(Message->ID)
- {
- default:
- return 0;
- }
-}
+++ /dev/null
-# Project: Acess GUI Window Manager
-
--include ../../Makefile.cfg
-
-CPPFLAGS +=
-
-DIR := Apps/AxWin/1.0
-BIN := AxWinWM
-OBJ := main.o helpers.o commandline.o video.o input.o video_text.o
-OBJ += messages.o interface.o wm.o decorator.o render.o
-OBJ += image.o
-
-LDFLAGS += -limage_sif -luri -lnet
-
--include ../../Makefile.tpl
-
-all: resources/LogoSmall.sif.res.h
-
-%.res.h: % Makefile
- echo "#define RESOURCE_$(notdir $<) \\"| sed -e 's/\./_/g' > $@
- base64 $< | sed -e 's/.*/"&"\\/' >> $@
- echo "" >> $@
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <string.h>
-
-// === PROTOTYPES ===
-void ShowUsage(char *ProgName);
-void ShowHelp(char *ProgName);
-
-// === CODE ===
-void ParseCommandline(int argc, char *argv[])
-{
- int i;
- char *arg;
-
- for( i = 1; i < argc; i++ )
- {
- arg = argv[i];
- if(arg[0] == '-')
- {
- if( arg[1] == '-' )
- {
- if( strcmp(&arg[2], "help") == 0 ) {
- ShowHelp(argv[0]);
- exit(EXIT_SUCCESS);
- }
- else {
- ShowUsage(argv[0]);
- exit(EXIT_FAILURE);
- }
- }
- else
- {
- while( *++arg )
- {
- switch(*arg)
- {
- case 'h':
- case '?':
- ShowHelp(argv[0]);
- exit(EXIT_SUCCESS);
- break;
- default:
- break;
- }
- }
- }
- }
- }
-}
-
-void ShowUsage(char *ProgName)
-{
- fprintf(stderr, "Usage: %s [-h|--help]\n", ProgName);
-}
-
-void ShowHelp(char *ProgName)
-{
- ShowUsage(ProgName);
- fprintf(stderr, "\n");
- fprintf(stderr, "\t--help\tShow this message\n");
-}
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <acess/sys.h> // _SysDebug
-
-// === TYPES ===
-typedef struct sIPC_Type tIPC_Type;
-typedef struct sFont tFont;
-
-struct sIPC_Type
-{
- int (*GetIdentSize)(void *Ident);
- int (*CompareIdent)(void *Ident1, void *Ident2);
- void (*SendMessage)(void *Ident, size_t, void *Data);
-};
-
-#include "wm.h"
-#include "image.h"
-//#include "font.h"
-
-// === MACROS ===
-static inline uint32_t Video_AlphaBlend(uint32_t _orig, uint32_t _new, uint8_t _alpha)
-{
- uint16_t ao,ro,go,bo;
- uint16_t an,rn,gn,bn;
- if( _alpha == 0 ) return _orig;
- if( _alpha == 255 ) return _new;
-
- ao = (_orig >> 24) & 0xFF;
- ro = (_orig >> 16) & 0xFF;
- go = (_orig >> 8) & 0xFF;
- bo = (_orig >> 0) & 0xFF;
-
- an = (_new >> 24) & 0xFF;
- rn = (_new >> 16) & 0xFF;
- gn = (_new >> 8) & 0xFF;
- bn = (_new >> 0) & 0xFF;
-
- if( _alpha == 0x80 ) {
- ao = (ao + an) / 2;
- ro = (ro + rn) / 2;
- go = (go + gn) / 2;
- bo = (bo + bn) / 2;
- }
- else {
- ao = ao*(255-_alpha) + an*_alpha;
- ro = ro*(255-_alpha) + rn*_alpha;
- go = go*(255-_alpha) + gn*_alpha;
- bo = bo*(255-_alpha) + bn*_alpha;
- ao /= 255*2;
- ro /= 255*2;
- go /= 255*2;
- bo /= 255*2;
- }
-
- return (ao << 24) | (ro << 16) | (go << 8) | bo;
-}
-
-// === GLOBALS ===
-extern const char *gsTerminalDevice;
-extern const char *gsMouseDevice;
-
-extern int giScreenWidth;
-extern int giScreenHeight;
-extern uint32_t *gpScreenBuffer;
-
-extern int giTerminalFD;
-extern int giMouseFD;
-
-// === Functions ===
-extern void memset32(void *ptr, uint32_t val, size_t count);
-// --- Initialisation ---
-extern void ParseCommandline(int argc, char *argv[]);
-// --- Messages / IPC ---
-extern void IPC_Init(void);
-extern void IPC_FillSelect(int *nfds, fd_set *set);
-extern void IPC_HandleSelect(fd_set *set);
-// --- Input ---
-extern void Input_FillSelect(int *nfds, fd_set *set);
-extern void Input_HandleSelect(fd_set *set);
-// --- Local WM ---
-extern tApplication *AxWin_RegisterClient(tIPC_Type *Method, void *Ident, const char *Name);
-extern void AxWin_DeregisterClient(tApplication *App);
-extern tApplication *AxWin_GetClient(tIPC_Type *Method, void *Ident);
-extern tElement *AxWin_CreateAppWindow(tApplication *App, const char *Name);
-// --- Video ---
-extern void Video_Setup(void);
-extern void Video_SetCursorPos(short X, short Y);
-extern void Video_Update(void);
-extern void Video_FillRect(short X, short Y, short W, short H, uint32_t Color);
-extern void Video_DrawRect(short X, short Y, short W, short H, uint32_t Color);
-extern int Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text);
-extern void Video_DrawImage(short X, short Y, short W, short H, tImage *Image);
-// --- Interface ---
-extern void Interface_Init(void);
-extern void Interface_Update(void);
-extern void Interface_Render(void);
-// --- Decorator ---
-extern void Decorator_RenderWidget(tElement *Element);
-
-#endif
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- *
- * Widget Decorator
- */
-#include "common.h"
-#include "wm.h"
-
-#define BORDER_EVERYTHING 1
-
-#define BOX_BGCOLOUR 0xC0C0C0
-#define BOX_BORDER 0xA0A0A0
-#define BUTTON_BGCOLOUR 0xD0D0D0
-#define BUTTON_BORDER 0xF0F0F0
-#define TEXT_COLOUR 0x000000
-
-// === CODE ===
-void Decorator_RenderWidget(tElement *Element)
-{
- _SysDebug("Decorator_RenderWidget: (Element={Type:%i,(%i,%i) %ix%i})",
- Element->Type,
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH
- );
-
- #if BORDER_EVERYTHING
- Video_DrawRect(Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- 0
- );
- #endif
-
- switch(Element->Type)
- {
- case ELETYPE_NONE:
- case ELETYPE_BOX: break; // Box is a meta-element
-
- case ELETYPE_TABBAR: // Tab Bar
- Video_DrawRect(
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- BOX_BORDER
- );
- Video_FillRect(
- Element->CachedX+1, Element->CachedY+1,
- Element->CachedW-2, Element->CachedH-2,
- BOX_BGCOLOUR
- );
- // Enumerate Items.
- break;
- case ELETYPE_TOOLBAR: // Tool Bar
- Video_DrawRect(
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- BOX_BORDER
- );
- Video_FillRect(
- Element->CachedX+1, Element->CachedY+1,
- Element->CachedW-2, Element->CachedH-2,
- BOX_BGCOLOUR
- );
- break;
-
- case ELETYPE_SPACER: // Spacer (subtle line)
- Video_FillRect(
- Element->CachedX+3, Element->CachedY+3,
- Element->CachedW-6, Element->CachedH-6,
- BOX_BORDER
- );
- break;
-
- case ELETYPE_BUTTON: // Button
- Video_FillRect(
- Element->CachedX+1, Element->CachedY+1,
- Element->CachedW-2, Element->CachedH-2,
- BUTTON_BGCOLOUR
- );
- Video_DrawRect(
- Element->CachedX, Element->CachedY,
- Element->CachedW-1, Element->CachedH-1,
- BUTTON_BORDER
- );
- break;
-
- case ELETYPE_TEXT:
- Video_DrawText(
- Element->CachedX+1, Element->CachedY+1,
- Element->CachedW-2, Element->CachedH-2,
- NULL,
- TEXT_COLOUR,
- Element->Text
- );
- break;
-
- case ELETYPE_IMAGE:
- Video_DrawImage(
- Element->CachedX, Element->CachedY,
- Element->CachedW, Element->CachedH,
- Element->Data
- );
- break;
-
- default:
- _SysDebug(" ERROR: Unknown type %i", Element->Type);
- break;
- }
-}
+++ /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
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-
-// === CODE ===
-void memset32(void *ptr, uint32_t val, size_t count)
-{
- uint32_t *dst = ptr;
- while(count --) *dst++ = val;
-}
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- *
- * Window Manager and Widget Control
- */
-#include "common.h"
-#include <stdlib.h>
-#include <string.h>
-#include <uri.h>
-
-// === IMPORTS ===
-extern tImage *Image_SIF_Parse(void *Buffer, size_t Size);
-
-// === PROTOTYPES ===
- int UnBase64(uint8_t *Dest, char *Src, int BufSize);
-
-// === CODE ===
-/**
- * \brief Open an image from a URI
- */
-tImage *Image_Load(const char *URI)
-{
- tURI *uri;
- int filesize;
- void *buf;
- tImage *img;
-
- uri = URI_Parse(URI);
- if( !uri ) {
- _SysDebug("Image_Load: Unable parse as URI '%s'\n", URI);
- return NULL;
- }
-
- if( strcmp(uri->Proto, "file") == 0 )
- {
- FILE *fp;
- fp = fopen(uri->Path, "rb");
- if(!fp) {
- _SysDebug("Image_Load: Unable to open '%s'\n", uri->Path);
- free(uri);
- return NULL;
- }
-
- fseek(fp, 0, SEEK_END);
- filesize = ftell(fp);
- buf = malloc( filesize );
- if(!buf) {
- _SysDebug("Image_Load: malloc() failed!\n");
- fclose(fp);
- free(uri);
- return NULL;
- }
-
- fread(buf, filesize, 1, buf);
- fclose(fp);
- }
- else if( strcmp(uri->Proto, "base64") == 0 )
- {
- // 4 bytes of base64 = 3 bytes of binary (base 256)
- filesize = strlen( uri->Path ) * 3 / 4;
- buf = malloc(filesize);
- if(!buf) {
- _SysDebug("Image_Load: malloc() failed!\n");
- free(uri);
- return NULL;
- }
-
- filesize = UnBase64(buf, uri->Path, filesize);
- }
- else
- {
- _SysDebug("Image_Load: Unknow protocol '%s'\n", uri->Proto);
- free(uri);
- return NULL;
- }
-
- img = Image_SIF_Parse(buf, filesize);
- free(buf);
- free(uri);
- if( !img ) {
- _SysDebug("Image_Load: Unable to parse SIF from '%s'\n", URI);
- return NULL;
- }
-
- return img;
-}
-
-/**
- * \brief Decode a Base64 value
- */
-int UnBase64(uint8_t *Dest, char *Src, int BufSize)
-{
- uint32_t val;
- int i, j;
- char *start_src = Src;
-
- for( i = 0; i+2 < BufSize; i += 3 )
- {
- val = 0;
- for( j = 0; j < 4; j++, Src ++ ) {
- if('A' <= *Src && *Src <= 'Z')
- val |= (*Src - 'A') << ((3-j)*6);
- else if('a' <= *Src && *Src <= 'z')
- val |= (*Src - 'a' + 26) << ((3-j)*6);
- else if('0' <= *Src && *Src <= '9')
- val |= (*Src - '0' + 52) << ((3-j)*6);
- else if(*Src == '+')
- val |= 62 << ((3-j)*6);
- else if(*Src == '/')
- val |= 63 << ((3-j)*6);
- else if(!*Src)
- break;
- else if(*Src != '=')
- j --; // Ignore invalid characters
- }
- Dest[i ] = (val >> 16) & 0xFF;
- Dest[i+1] = (val >> 8) & 0xFF;
- Dest[i+2] = val & 0xFF;
- if(j != 4) break;
- }
-
- // Finish things off
- if(i < BufSize)
- Dest[i] = (val >> 16) & 0xFF;
- if(i+1 < BufSize)
- Dest[i+1] = (val >> 8) & 0xFF;
-
- return Src - start_src;
-}
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#ifndef _IMAGE_H_
-#define _IMAGE_H_
-
-typedef struct sImage tImage;
-
-struct sImage
-{
- short Width;
- short Height;
- int Format;
- uint8_t Data[];
-};
-
-enum eImageFormats
-{
- IMGFMT_BGRA,
- IMGFMT_RGB,
- NUM_IMGFMTS
-};
-
-// === PROTOTYPES ===
-extern tImage *Image_Load(const char *URI);
-
-#endif
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <acess/sys.h>
-
-#define JOY_IOCTL_GETSETAXISLIMIT 6
-#define JOY_IOCTL_GETSETAXISPOSITION 7
-
-// === CODE ===
-int Input_Init(void)
-{
- struct {
- int Num, Value;
- } num_value;
-
- // Open mouse for RW
- giMouseFD = open(gsMouseDevice, 3);
-
- // Set mouse limits
- num_value.Num = 0;
- num_value.Value = giScreenWidth;
- ioctl(giMouseFD, JOY_IOCTL_GETSETAXISLIMIT, &num_value);
- num_value.Value = giScreenWidth/2;
- ioctl(giMouseFD, JOY_IOCTL_GETSETAXISPOSITION, &num_value);
-
- num_value.Num = 1;
- num_value.Value = giScreenHeight;
- ioctl(giMouseFD, JOY_IOCTL_GETSETAXISLIMIT, &num_value);
- num_value.Value = giScreenHeight/2;
- ioctl(giMouseFD, JOY_IOCTL_GETSETAXISPOSITION, &num_value);
-
- return 0;
-}
-
-void Input_FillSelect(int *nfds, fd_set *set)
-{
- if(*nfds < giTerminalFD) *nfds = giTerminalFD;
- if(*nfds < giMouseFD) *nfds = giMouseFD;
- FD_SET(giTerminalFD, set);
- FD_SET(giMouseFD, set);
-}
-
-void Input_HandleSelect(fd_set *set)
-{
- if(FD_ISSET(giTerminalFD, set))
- {
- uint32_t codepoint;
- if( read(giTerminalFD, &codepoint, sizeof(codepoint)) != sizeof(codepoint) )
- {
- // oops, error
- }
- // TODO: pass on to message handler
- _SysDebug("Keypress 0x%x", codepoint);
- }
-
- if(FD_ISSET(giMouseFD, set))
- {
- struct sMouseInfo {
- uint16_t NAxies;
- uint16_t NButtons;
- struct sMouseAxis {
- int16_t MinValue;
- int16_t MaxValue;
- int16_t CurValue;
- uint16_t CursorPos;
- } Axies[2];
- uint8_t Buttons[3];
- } mouseinfo;
-
- seek(giMouseFD, 0, SEEK_SET);
- if( read(giMouseFD, &mouseinfo, sizeof(mouseinfo)) != sizeof(mouseinfo) )
- {
- // Not a 3 button mouse, oops
- return ;
- }
-
-// _SysDebug("sizeof(uint16_t) = %i, sizeof(int16_t) = %i",
-// sizeof(uint16_t), sizeof(int16_t));
-// _SysDebug("NAxies=%i,NButtons=%i", mouseinfo.NAxies, mouseinfo.NButtons);
-// _SysDebug("offsetof(Axies[0].MinValue) = %i", offsetof(struct sMouseInfo, Axies[0].MinValue));
-// _SysDebug("[0] = {MinValue=%i,MaxValue=%i,CurValue=%i}",
-// mouseinfo.Axies[0].MinValue, mouseinfo.Axies[0].MaxValue,
-// mouseinfo.Axies[0].CurValue
-// );
- // Handle movement
- Video_SetCursorPos( mouseinfo.Axies[0].CursorPos, mouseinfo.Axies[1].CursorPos );
-// _SysDebug("Cursor to %i,%i", mouseinfo.Axies[0].CursorPos, mouseinfo.Axies[1].CursorPos);
- }
-}
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- *
- * interface.c
- * > Main Overarching UI
- */
-#include "common.h"
-#include "resources/LogoSmall.sif.res.h"
-
-// === GLOBALS ==
- int giInterface_Width = 0;
- int giInterface_HeaderBarSize = 20;
- int giInterface_TabBarSize = 20;
-tElement *gpInterface_Sidebar;
-tElement *gpInterface_ProgramList;
-tElement *gpInterface_MainArea;
-tElement *gpInterface_HeaderBar;
-tElement *gpInterface_TabBar;
-tElement *gpInterface_TabContent;
-const char csLogoSmall[] = "base64:///"RESOURCE_LogoSmall_sif;
-tApplication *gpInterface_CurrentApp;
-
-typedef struct sApplicationLink tApplicationLink;
-
-struct sApplicationLink {
- tApplication *App;
- tElement *Button;
- char Name[];
-};
-
-// === CODE ===
-/**
- * \brief Initialise the UI
- */
-void Interface_Init(void)
-{
- tElement *btn, *text;
- tElement *ele;
-
- // Calculate sizes
- giInterface_Width = giScreenWidth/16;
-
- // Set root window to no-border
- AxWin_SetFlags(NULL, 0);
-
- // -- Create Sidebar (Menu and Window List) --
- gpInterface_Sidebar = AxWin_CreateElement(NULL, ELETYPE_TOOLBAR, ELEFLAG_VERTICAL, "Sidebar");
- AxWin_SetSize( gpInterface_Sidebar, giInterface_Width );
-
- // > System Menu Button
- btn = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_BUTTON, ELEFLAG_NOSTRETCH, "SystemMenu");
- AxWin_SetSize(btn, giInterface_Width-4);
- //text = AxWin_CreateElement(btn, ELETYPE_IMAGE, ELEFLAG_SCALE, "MenuLogo");
- text = AxWin_CreateElement(btn, ELETYPE_IMAGE, 0, "MenuLogo");
- //AxWin_SetText(text, "file:///LogoSmall.sif");
- AxWin_SetText(text, csLogoSmall);
-
- // > Plain <hr/> style spacer
- ele = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_SPACER, ELEFLAG_NOSTRETCH, "SideBar Spacer Top");
- AxWin_SetSize(ele, 4);
-
- // > Application List (Window list on most OSs)
- gpInterface_ProgramList = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_BOX, ELEFLAG_VERTICAL, "ProgramList");
-
- // > Plain <hr/> style spacer
- ele = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_SPACER, ELEFLAG_NOSTRETCH, "SideBar Spacer Bottom");
- AxWin_SetSize(ele, 4);
-
- // > Version/Time
- text = AxWin_CreateElement(gpInterface_Sidebar, ELETYPE_TEXT, ELEFLAG_NOSTRETCH, "Version String");
- AxWin_SetSize(text, 20);
- AxWin_SetText(text, "2.0");
-
- // --
- // -- Create Main Area and regions within --
- // --
- // > Righthand Area
- gpInterface_MainArea = AxWin_CreateElement(NULL, ELETYPE_BOX, ELEFLAG_VERTICAL, "MainArea");
- // > Header Bar (Title)
- gpInterface_HeaderBar = AxWin_CreateElement(gpInterface_MainArea, ELETYPE_BOX, 0, "HeaderBar");
- AxWin_SetSize(gpInterface_HeaderBar, giInterface_HeaderBarSize);
- text = AxWin_CreateElement(gpInterface_HeaderBar, ELETYPE_TEXT, 0, NULL);
- AxWin_SetText(text, "Acess2 GUI - By thePowersGang (John Hodge)");
- // > Tab Bar (Current windows)
- gpInterface_TabBar = AxWin_CreateElement(gpInterface_MainArea, ELETYPE_TABBAR, 0, "TabBar");
- AxWin_SetSize(gpInterface_TabBar, giInterface_TabBarSize);
- // > Application Space
- gpInterface_TabContent = AxWin_CreateElement(gpInterface_MainArea, ELETYPE_BOX, 0, "TabContent");
-}
-
-void Interface_Update(void)
-{
-// tApplication *app;
-// tApplicationLink *lnk;
- giInterface_Width = giScreenWidth/16;
- AxWin_SetSize( gpInterface_Sidebar, giInterface_Width );
-
- // Scan application list for changes
- // - HACK for now, just directly access it
-// for( app = gWM_Applications; app; app = app->Next )
-// {
-// AxWin_CreateElement();
-// }
-
- // Update current tab list
-}
-
-void Interface_Render(void)
-{
- Video_FillRect(
- 0, 0,
- giInterface_Width, giScreenHeight,
- 0xDDDDDD);
-
- Video_Update();
-}
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <acess/sys.h>
-
-// === IMPORTS ===
-extern void WM_Update(void);
-extern int Input_Init(void);
-
-// === GLOBALS ===
-const char *gsTerminalDevice = NULL;
-const char *gsMouseDevice = NULL;
-
- int giScreenWidth = 640;
- int giScreenHeight = 480;
-uint32_t *gpScreenBuffer = NULL;
-
- int giTerminalFD = -1;
- int giMouseFD = -1;
-
-
-// === CODE ===
-/**
- * \brief Program Entrypoint
- */
-int main(int argc, char *argv[])
-{
- ParseCommandline(argc, argv);
-
- if( gsTerminalDevice == NULL ) {
- gsTerminalDevice = "/Devices/VTerm/6";
- }
- if( gsMouseDevice == NULL ) {
- gsMouseDevice = "/Devices/PS2Mouse";
- }
-
- Video_Setup();
- Interface_Init();
- IPC_Init();
- Input_Init();
-
- WM_Update();
-
- // Main Loop
- for(;;)
- {
- fd_set fds;
- int nfds = 0;
- FD_ZERO(&fds);
-
- Input_FillSelect(&nfds, &fds);
- IPC_FillSelect(&nfds, &fds);
-
- nfds ++;
- select(nfds, &fds, NULL, NULL, NULL);
-
- Input_HandleSelect(&fds);
- IPC_HandleSelect(&fds);
- }
- return 0;
-}
-
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <acess/sys.h>
-#include <net.h>
-#include <axwin2/messages.h>
-#include <string.h>
-
-#define AXWIN_PORT 4101
-
-#define STATICBUF_SIZE 64
-
-// === TYPES ===
-
-// === PROTOTYPES ===
-void IPC_Init(void);
-void IPC_FillSelect(int *nfds, fd_set *set);
-void IPC_HandleSelect(fd_set *set);
-void IPC_Handle(tIPC_Type *IPCType, void *Ident, size_t MsgLen, tAxWin_Message *Msg);
-void IPC_ReturnValue(tIPC_Type *IPCType, void *Ident, int MessageID, uint32_t Value);
- int IPC_Type_Datagram_GetSize(void *Ident);
- int IPC_Type_Datagram_Compare(void *Ident1, void *Ident2);
-void IPC_Type_Datagram_Send(void *Ident, size_t Length, void *Data);
- int IPC_Type_Sys_GetSize(void *Ident);
- int IPC_Type_Sys_Compare(void *Ident1, void *Ident2);
-void IPC_Type_Sys_Send(void *Ident, size_t Length, void *Data);
-
-// === GLOBALS ===
- int giNetworkFileHandle = -1;
- int giMessagesFileHandle = -1;
-tIPC_Type gIPC_Type_Datagram = {
- IPC_Type_Datagram_GetSize,
- IPC_Type_Datagram_Compare,
- IPC_Type_Datagram_Send
-};
-tIPC_Type gIPC_Type_SysMessage = {
- IPC_Type_Sys_GetSize,
- IPC_Type_Sys_Compare,
- IPC_Type_Sys_Send
-};
-
-// === CODE ===
-void IPC_Init(void)
-{
- int tmp;
- // TODO: Check this
- giNetworkFileHandle = open("/Devices/ip/loop/udp", OPENFLAG_READ);
- tmp = AXWIN_PORT; ioctl(giNetworkFileHandle, 4, &tmp); // TODO: Don't hard-code IOCtl number
-}
-
-void IPC_FillSelect(int *nfds, fd_set *set)
-{
- if( giNetworkFileHandle > *nfds ) *nfds = giNetworkFileHandle;
- FD_SET(giNetworkFileHandle, set);
-}
-
-void IPC_HandleSelect(fd_set *set)
-{
- if( FD_ISSET(giNetworkFileHandle, set) )
- {
- char staticBuf[STATICBUF_SIZE];
- int readlen, identlen;
- char *msg;
-
- readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf));
-
- identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] );
- msg = staticBuf + identlen;
-
- IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg);
- _SysDebug("IPC_HandleSelect: UDP handled");
- }
-
- while(SysGetMessage(NULL, NULL))
- {
- pid_t tid;
- int len = SysGetMessage(&tid, NULL);
- char data[len];
- SysGetMessage(NULL, data);
-
- IPC_Handle(&gIPC_Type_SysMessage, &tid, len, (void*)data);
- _SysDebug("IPC_HandleSelect: Message handled");
- }
-}
-
-void IPC_Handle(tIPC_Type *IPCType, void *Ident, size_t MsgLen, tAxWin_Message *Msg)
-{
- tApplication *app;
- tElement *ele;
-
- _SysDebug("IPC_Handle: (IPCType=%p, Ident=%p, MsgLen=%i, Msg=%p)",
- IPCType, Ident, MsgLen, Msg);
-
- if( MsgLen < sizeof(tAxWin_Message) )
- return ;
- if( MsgLen < sizeof(tAxWin_Message) + Msg->Size )
- return ;
-
- app = AxWin_GetClient(IPCType, Ident);
-
- switch((enum eAxWin_Messages) Msg->ID)
- {
- // --- Ping message (reset timeout and get server version)
- case MSG_SREQ_PING:
- _SysDebug(" IPC_Handle: MSG_SREQ_PING");
- if( MsgLen < sizeof(tAxWin_Message) + 4 ) return;
- Msg->ID = MSG_SRSP_VERSION;
- Msg->Size = 4;
- Msg->Data[0] = 0;
- Msg->Data[1] = 1;
- *(uint16_t*)&Msg->Data[2] = -1;
- IPCType->SendMessage(Ident, sizeof(Msg->ID), Msg);
- break;
-
-
- // --- Register an application
- case MSG_SREQ_REGISTER:
- _SysDebug(" IPC_Handle: MSG_SREQ_REGISTER");
- if( Msg->Data[Msg->Size-1] != '\0' ) {
- // Invalid message
- _SysDebug("IPC_Handle: RETURN - Not NULL terminated");
- return ;
- }
-
- if( app != NULL ) {
- _SysDebug("Notice: Duplicate registration (%s)\n", Msg->Data);
- return ;
- }
-
- // TODO: Should this function be implemented here?
- AxWin_RegisterClient(IPCType, Ident, Msg->Data);
- break;
-
- // --- Create a window
- case MSG_SREQ_ADDWIN:
- _SysDebug(" IPC_Handle: MSG_SREQ_ADDWIN");
- if( Msg->Data[Msg->Size-1] != '\0' ) {
- // Invalid message
- return ;
- }
-
- ele = AxWin_CreateAppWindow(app, Msg->Data);
- IPC_ReturnValue(IPCType, Ident, MSG_SREQ_ADDWIN, ele->ApplicationID);
- break;
-
- // --- Set a window's icon
- case MSG_SREQ_SETICON:
- _SysDebug(" IPC_Handle: MSG_SREQ_SETICON");
- // TODO: Find a good way of implementing this
- break;
-
- // --- Create an element
- case MSG_SREQ_INSERT: {
- _SysDebug(" IPC_Handle: MSG_SREQ_INSERT");
- struct sAxWin_SReq_NewElement *info = (void *)Msg->Data;
-
- if( Msg->Size != sizeof(*info) ) return;
-
- if( !app || info->Parent > app->MaxElementIndex ) return ;
-
- ele = AxWin_CreateElement( app->EleIndex[info->Parent], info->Type, info->Flags, NULL );
- IPC_ReturnValue(IPCType, Ident, MSG_SREQ_ADDWIN, ele->ApplicationID);
- break; }
-
- // --- Unknown message
- default:
- fprintf(stderr, "WARNING: Unknown message %i (%p)\n", Msg->ID, IPCType);
- _SysDebug("WARNING: Unknown message %i (%p)\n", Msg->ID, IPCType);
- break;
- }
-}
-
-void IPC_ReturnValue(tIPC_Type *IPCType, void *Ident, int MessageID, uint32_t Value)
-{
- char data[sizeof(tAxWin_Message) + sizeof(tAxWin_RetMsg)];
- tAxWin_Message *msg = (void *)data;
- tAxWin_RetMsg *ret_msg = (void *)msg->Data;
-
- msg->Source = 0; // 0 = Server
- msg->ID = MSG_SRSP_RETURN;
- msg->Size = sizeof(tAxWin_RetMsg);
- ret_msg->ReqID = MessageID;
- ret_msg->Rsvd = 0;
- ret_msg->Value = Value;
-
- IPCType->SendMessage(Ident, sizeof(data), data);
-}
-
-int IPC_Type_Datagram_GetSize(void *Ident)
-{
- return 4 + Net_GetAddressSize( ((uint16_t*)Ident)[1] );
-}
-
-int IPC_Type_Datagram_Compare(void *Ident1, void *Ident2)
-{
- // Pass the buck :)
- // - No need to worry about mis-matching sizes, as the size is computed
- // from the 3rd/4th bytes, hence it will differ before the size is hit.
- return memcmp(Ident1, Ident2, IPC_Type_Datagram_GetSize(Ident1));
-}
-
-void IPC_Type_Datagram_Send(void *Ident, size_t Length, void *Data)
-{
- int identlen = IPC_Type_Datagram_GetSize(Ident);
- char tmpbuf[ identlen + Length ];
- memcpy(tmpbuf, Ident, identlen); // Header
- memcpy(tmpbuf + identlen, Data, Length); // Data
- // TODO: Handle fragmented packets
- write(giNetworkFileHandle, tmpbuf, sizeof(tmpbuf));
-}
-
-int IPC_Type_Sys_GetSize(void *Ident)
-{
- return sizeof(pid_t);
-}
-
-int IPC_Type_Sys_Compare(void *Ident1, void *Ident2)
-{
- return *(int*)Ident1 - *(int*)Ident2;
-}
-
-void IPC_Type_Sys_Send(void *Ident, size_t Length, void *Data)
-{
- SysSendMessage( *(tid_t*)Ident, Length, Data );
-}
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- *
- * Rendering code
- */
-#include "common.h"
-#include <stdlib.h>
-#include <string.h>
-#include "wm.h"
-#include <acess/sys.h> // _SysDebug
-
-// === IMPORTS ===
-extern void Decorator_RenderWidget(tElement *Element);
-extern tElement gWM_RootElement;
-extern tApplication *gWM_Applications;
-extern int giWM_MaxAreaX;
-extern int giWM_MaxAreaY;
-extern int giWM_MaxAreaW;
-extern int giWM_MaxAreaH;
-
-// === PROTOTYPES ===
-void WM_UpdateMinDims(tElement *Element);
-void WM_UpdateDimensions(tElement *Element, int Pass);
-void WM_UpdatePosition(tElement *Element);
-void WM_RenderWidget(tElement *Element);
-void WM_Update(void);
-
-// === CODE ===
-/**
- * \brief Updates the dimensions of an element
- * \todo What is the \a Pass parameter for
- *
- * The dimensions of an element are calculated from the parent's
- * cross dimension (the side at right angles to the alignment) sans some
- * padding.
- */
-void WM_UpdateDimensions(tElement *Element, int Pass)
-{
- tElement *child;
- int nChildren = 0;
- int nFixed = 0;
- int maxCross = 0;
- int fixedSize = 0;
- int fullCross, dynWith;
-
- _SysDebug("WM_UpdateDimensions %p'%s'", Element, Element->DebugName);
- _SysDebug(" -> Flags = 0x%x", Element->Flags);
- _SysDebug(" ->CachedH = %i, ->PaddingT = %i, ->PaddingB = %i",
- Element->CachedH, Element->PaddingT, Element->PaddingB
- );
- _SysDebug(" ->CachedW = %i, ->PaddingL = %i, ->PaddingR = %i",
- Element->CachedW, Element->PaddingL, Element->PaddingR
- );
-
- // Pass 1
- for( child = Element->FirstChild; child; child = child->NextSibling )
- {
- if( child->Flags & ELEFLAG_ABSOLUTEPOS )
- continue ;
-
- _SysDebug(" > %p'%s' ->FixedWith = %i", child, child->DebugName, child->FixedWith);
- if( child->FixedWith )
- {
- nFixed ++;
- fixedSize += child->FixedWith;
- }
-
- if( child->FixedCross && maxCross < child->FixedCross )
- maxCross = child->FixedCross;
- if( child->MinCross && maxCross < child->MinCross )
- maxCross = child->MinCross;
- nChildren ++;
- }
-
- _SysDebug(" - nChildren = %i, nFixed = %i", Element, nChildren, nFixed);
- if( nChildren > nFixed ) {
- if( Element->Flags & ELEFLAG_VERTICAL )
- dynWith = Element->CachedH - Element->PaddingT
- - Element->PaddingB;
- else
- dynWith = Element->CachedW - Element->PaddingL
- - Element->PaddingR;
- dynWith -= fixedSize;
- if( dynWith < 0 ) return ;
- dynWith /= nChildren - nFixed;
- _SysDebug(" - dynWith = %i", dynWith);
- }
-
- if( Element->Flags & ELEFLAG_VERTICAL )
- fullCross = Element->CachedW - Element->PaddingL - Element->PaddingR;
- else
- fullCross = Element->CachedH - Element->PaddingT - Element->PaddingB;
-
- _SysDebug(" - fullCross = %i", Element, fullCross);
-
- // Pass 2 - Set sizes and recurse
- for( child = Element->FirstChild; child; child = child->NextSibling )
- {
- int cross, with;
-
- _SysDebug(" > %p'%s' ->MinCross = %i", child, child->DebugName, child->MinCross);
-
-
- // --- Cross Size ---
- if( child->FixedCross )
- cross = child->FixedCross;
- // Expand to fill?
- // TODO: Extra flag so options are (Expand, Equal, Wrap)
- else if( child->Flags & ELEFLAG_NOEXPAND )
- cross = child->MinCross;
- else
- cross = fullCross;
- _SysDebug(" > %p'%s' - cross = %i", child, child->DebugName, cross);
- if( Element->Flags & ELEFLAG_VERTICAL )
- child->CachedW = cross;
- else
- child->CachedH = cross;
-
- // --- With Size ---
- if( child->FixedWith)
- with = child->FixedWith;
- else if( child->Flags & ELEFLAG_NOSTRETCH )
- with = child->MinWith;
- else
- with = dynWith;
- _SysDebug(" > %p'%s' - with = %i", child, child->DebugName, with);
- if( Element->Flags & ELEFLAG_VERTICAL )
- child->CachedH = with;
- else
- child->CachedW = with;
-
- WM_UpdateDimensions(child, Pass);
- }
-
- _SysDebug("%p'%s' Done", Element, Element->DebugName);
-}
-
-/**
- * \brief Updates the position of an element
- *
- * The parent element sets the positions of its children
- */
-void WM_UpdatePosition(tElement *Element)
-{
- tElement *child;
- int x, y;
- static int depth = 0;
- char indent[depth+1];
-
- if( Element->Flags & ELEFLAG_NORENDER ) return ;
-
- memset(indent, ' ', depth);
- indent[depth] = '\0';
- depth ++;
-
- _SysDebug("%sWM_UpdatePosition %p'%s'{PaddingL:%i, PaddingT:%i}",
- indent, Element, Element->DebugName, Element->PaddingL, Element->PaddingT);
-
- // Initialise
- x = Element->CachedX + Element->PaddingL;
- y = Element->CachedY + Element->PaddingT;
-
- _SysDebug("%s- Alignment = %s", indent,
- (Element->Flags & ELEFLAG_VERTICAL) ? "vertical" : "horizontal");
-
- // Update each child
- for(child = Element->FirstChild; child; child = child->NextSibling)
- {
- _SysDebug("%s- x = %i, y = %i", indent, x, y);
- child->CachedX = x;
- child->CachedY = y;
-
- // Set Alignment
- if( Element->Flags & ELEFLAG_ALIGN_CENTER ) {
- _SysDebug("%sChild being aligned to center", indent);
- if(Element->Flags & ELEFLAG_VERTICAL)
- child->CachedX += Element->CachedW/2 - child->CachedW/2;
- else
- child->CachedY += Element->CachedH/2 - child->CachedH/2;
- }
- else if( Element->Flags & ELEFLAG_ALIGN_END) {
- _SysDebug("%sChild being aligned to end", indent);
- if(Element->Flags & ELEFLAG_VERTICAL )
- child->CachedX += Element->CachedW
- - Element->PaddingL - Element->PaddingR
- - child->CachedW;
- else
- child->CachedY += Element->CachedH
- - Element->PaddingT
- - Element->PaddingB
- - child->CachedH;
- }
-
- _SysDebug("%s> %p'%s' at (%i,%i)", indent, child, child->DebugName,
- child->CachedX, child->CachedY);
-
- // Update child's children positions
- WM_UpdatePosition(child);
-
- // Increment
- if(Element->Flags & ELEFLAG_VERTICAL ) {
- y += child->CachedH + Element->GapSize;
- }
- else {
- x += child->CachedW + Element->GapSize;
- }
- }
-
- _SysDebug("%sElement %p'%s' (%i,%i)",
- indent, Element, Element->DebugName, Element->CachedX, Element->CachedY
- );
- depth --;
-}
-
-/**
- * \brief Update the minimum dimensions of the element
- * \note Called after a child's minimum dimensions have changed
- */
-void WM_UpdateMinDims(tElement *Element)
-{
- tElement *child;
-
- if(!Element) return;
-
- Element->MinCross = 0;
- Element->MinWith = 0;
-
- for(child = Element->FirstChild; child; child = child->NextSibling)
- {
- if( Element->Parent &&
- (Element->Flags & ELEFLAG_VERTICAL) == (Element->Parent->Flags & ELEFLAG_VERTICAL)
- )
- {
- if(child->FixedCross)
- Element->MinCross += child->FixedCross;
- else
- Element->MinCross += child->MinCross;
- if(child->FixedWith)
- Element->MinWith += child->FixedWith;
- else
- Element->MinWith += child->MinWith;
- }
- else
- {
- if(child->FixedCross)
- Element->MinWith += child->FixedCross;
- else
- Element->MinWith += child->MinCross;
- if(child->FixedWith)
- Element->MinCross += child->FixedWith;
- else
- Element->MinCross += child->MinWith;
- }
- }
-
- // Recurse upwards
- WM_UpdateMinDims(Element->Parent);
-}
-
-// --- Render ---
-void WM_RenderWidget(tElement *Element)
-{
- tElement *child;
-
- if( Element->Flags & ELEFLAG_NORENDER ) return ;
- if( Element->Flags & ELEFLAG_INVISIBLE ) return ;
-
- Decorator_RenderWidget(Element);
-
- for(child = Element->FirstChild; child; child = child->NextSibling)
- {
- WM_RenderWidget(child);
- }
-}
-
-void WM_UpdateWindow(tElement *Ele)
-{
- WM_UpdateDimensions( Ele, 0 );
- WM_UpdatePosition( Ele );
- WM_RenderWidget( Ele );
-}
-
-void WM_Update(void)
-{
- tApplication *app;
- tElement *ele;
-
- for( app = gWM_Applications; app; app = app->Next )
- {
- for( ele = app->MetaElement.FirstChild; ele; ele = ele->NextSibling ) {
- if( ele->Flags & ELEFLAG_WINDOW_MAXIMISED ) {
- ele->CachedX = giWM_MaxAreaX;
- ele->CachedY = giWM_MaxAreaY;
- ele->CachedW = giWM_MaxAreaW;
- ele->CachedH = giWM_MaxAreaH;
- }
- ele->Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
- WM_UpdateWindow(ele);
- }
- }
-
- gWM_RootElement.CachedX = 0;
- gWM_RootElement.CachedY = 0;
- gWM_RootElement.CachedW = giScreenWidth;
- gWM_RootElement.CachedH = giScreenHeight;
- gWM_RootElement.Flags |= ELEFLAG_NOEXPAND|ELEFLAG_ABSOLUTEPOS|ELEFLAG_FIXEDSIZE;
-
- WM_UpdateWindow( &gWM_RootElement );
-
- Video_Update();
-}
+++ /dev/null
-/*
- */
-#ifndef _RESORUCE_CURSOR_H
-#define _RESORUCE_CURSOR_H
-
-#include <stdint.h>
-
-static struct {
- uint16_t W, H, OfsX, OfsY;
- uint32_t Data[];
-} cCursorBitmap = {
- 8, 16, 0, 0,
- {
- 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, 0xFF000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000, 0x00000000,
- 0xFF000000, 0x00000000, 0x00000000, 0xFF000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF000000, 0x00000000,
- 0x00000000, 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
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include "common.h"
-#include <acess/sys.h>
-#include <acess/devices/terminal.h>
-#include <image.h>
-#include "resources/cursor.h"
-
-// === PROTOTYPES ===
-void Video_Setup(void);
-void Video_SetCursorPos(short X, short Y);
-void Video_Update(void);
-void Video_FillRect(short X, short Y, short W, short H, uint32_t Color);
-void Video_DrawRect(short X, short Y, short W, short H, uint32_t Color);
-
-// === GLOBALS ===
- int giVideo_CursorX;
- int giVideo_CursorY;
-
-// === CODE ===
-void Video_Setup(void)
-{
- int tmpInt;
-
- // Open terminal
- giTerminalFD = open(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE);
- if( giTerminalFD == -1 )
- {
- fprintf(stderr, "ERROR: Unable to open '%s' (%i)\n", gsTerminalDevice, _errno);
- exit(-1);
- }
-
- // Set width
- tmpInt = giScreenWidth;
- tmpInt = ioctl( giTerminalFD, TERM_IOCTL_WIDTH, &tmpInt );
- if(tmpInt != giScreenWidth)
- {
- fprintf(stderr, "Warning: Selected width (%i) is invalid, clipped to %i\n",
- giScreenWidth, tmpInt);
- giScreenWidth = tmpInt;
- }
-
- // Set height
- tmpInt = giScreenHeight;
- tmpInt = ioctl( giTerminalFD, TERM_IOCTL_HEIGHT, &tmpInt );
- if(tmpInt != giScreenHeight)
- {
- fprintf(stderr, "Warning: Selected height (%i) is invalid, clipped to %i\n",
- giScreenHeight, tmpInt);
- giScreenHeight = tmpInt;
- }
-
- // Set mode to video
- tmpInt = TERM_MODE_FB;
- ioctl( giTerminalFD, TERM_IOCTL_MODETYPE, &tmpInt );
-
- // Force VT to be shown
- ioctl( giTerminalFD, TERM_IOCTL_FORCESHOW, NULL );
-
- // Create local framebuffer (back buffer)
- gpScreenBuffer = malloc( giScreenWidth*giScreenHeight*4 );
- memset32( gpScreenBuffer, 0x8888FF, giScreenWidth*giScreenHeight );
-
- // Set cursor position and bitmap
- ioctl(giTerminalFD, TERM_IOCTL_SETCURSORBITMAP, &cCursorBitmap);
- Video_SetCursorPos( giScreenWidth/2, giScreenHeight/2 );
-
- Video_Update();
-}
-
-void Video_Update(void)
-{
- //seek(giTerminalFD, 0, SEEK_SET);
- seek(giTerminalFD, 0, 1);
- write(giTerminalFD, gpScreenBuffer, giScreenWidth*giScreenHeight*4);
-}
-
-void Video_SetCursorPos(short X, short Y)
-{
- struct {
- uint16_t x;
- uint16_t y;
- } pos;
- pos.x = giVideo_CursorX = X;
- pos.y = giVideo_CursorY = Y;
- ioctl(giTerminalFD, TERM_IOCTL_GETSETCURSOR, &pos);
-}
-
-void Video_FillRect(short X, short Y, short W, short H, uint32_t Color)
-{
- uint32_t *buf = gpScreenBuffer + Y*giScreenWidth + X;
-
- _SysDebug("Video_FillRect: (X=%i, Y=%i, W=%i, H=%i, Color=%08x)",
- X, Y, W, H, Color);
-
- if(W < 0 || X < 0 || X >= giScreenWidth) return ;
- if(X + W > giScreenWidth) W = giScreenWidth - X;
-
- if(H < 0 || Y < 0 || Y >= giScreenHeight) return ;
- if(Y + H > giScreenHeight) H = giScreenHeight - Y;
-
- while( H -- )
- {
- memset32( buf, Color, W );
- buf += giScreenWidth;
- }
-}
-
-void Video_DrawRect(short X, short Y, short W, short H, uint32_t Color)
-{
- Video_FillRect(X, Y, W, 1, Color);
- Video_FillRect(X, Y+H-1, W, 1, Color);
- Video_FillRect(X, Y, 1, H, Color);
- Video_FillRect(X+W-1, Y, 1, H, Color);
-}
-
-/**
- * \brief Draw an image to the screen
- * \todo Maybe have support for an offset in the image
- */
-void Video_DrawImage(short X, short Y, short W, short H, tImage *Image)
-{
- int x, y;
- uint8_t *buf = (uint8_t *)(gpScreenBuffer + Y*giScreenWidth + X);
- uint8_t *data;
-
- // Sanity please
- if( !Image )
- return ;
-
- // Bounds Check
- if( X >= giScreenWidth ) return ;
- if( Y >= giScreenHeight ) return ;
-
- // Wrap to image size
- if( W > Image->Width ) W = Image->Width;
- if( H > Image->Height ) H = Image->Height;
-
- // Wrap to screen size
- if( X + W > giScreenWidth ) W = giScreenWidth - X;
- if( Y + H > giScreenHeight ) H = giScreenHeight - Y;
-
- // Do the render
- data = Image->Data;
- switch( Image->Format )
- {
- case IMGFMT_BGRA:
- for( y = 0; y < H; y ++ )
- {
- int r, g, b, a; // New
- int or, og, ob; // Original
- for( x = 0; x < W; x ++ )
- {
- b = data[x*4+0]; g = data[x*4+1]; r = data[x*4+2]; a = data[x*4+3];
- if( a == 0 ) continue; // 100% transparent
- ob = buf[x*4+0]; og = buf[x*4+1]; or = buf[x*4+2];
- // Handle Alpha
- switch(a)
- {
- // Transparent: Handled above
- // Solid
- case 0xFF: break;
- // Half
- case 0x80:
- r = (or + r) / 2;
- g = (og + g) / 2;
- b = (ob + b) / 2;
- break;
- // General
- default:
- r = (or * (255-a) + r * a) / 255;
- g = (og * (255-a) + g * a) / 255;
- b = (ob * (255-a) + b * a) / 255;
- break;
- }
- buf[x*4+0] = b; buf[x*4+1] = g; buf[x*4+2] = r;
- }
- data += Image->Width * 4;
- buf += giScreenWidth * 4;
- }
- break;
-
- // RGB
- case IMGFMT_RGB:
- for( y = 0; y < H; y ++ )
- {
- for( x = 0; x < W; x ++ )
- {
- buf[x*4+0] = data[x*3+2]; // Blue
- buf[x*4+1] = data[x*3+1]; // Green
- buf[x*4+2] = data[x*3+0]; // Red
- }
- data += W * 3;
- buf += giScreenWidth * 4;
- }
- break;
- default:
- _SysDebug("ERROR: Unknown image format %i\n", Image->Format);
- break;
- }
-}
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- */
-#include <acess/sys.h>
-#include "common.h"
-
-typedef struct sGlyph {
- struct sGlyph *Next;
- struct sGlyph *Prev;
-
- uint32_t Codepoint;
-
- // Effective dimensions (distance to move 'cursor')
- short Width;
- short Height;
-
- // Distance from the current cursor position to render at
- short OffsetX;
- short OffsetY;
-
- // True dimensions (size of the bitmap
- short TrueWidth;
- short TrueHeight;
-
- // Bitmap Data
- uint8_t Bitmap[]; // 8-bit alpha
-
-} tGlyph;
-
-struct sFont {
- struct sFont *Next;
- int ReferenceCount;
-
- tGlyph *AsciiGlyphs[128]; // Glyphs 0-127
-
- tGlyph *FirstGlyph;
- tGlyph *LastGlyph;
-
- tGlyph *(*CacheGlyph)(struct sFont *this, uint32_t Codepoint);
-
-};
-
-
-// === PROTOTYPES ===
- int Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text);
-void Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H);
-tGlyph *_GetGlyph(tFont *Font, uint32_t Codepoint);
-void _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color);
-tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint);
- int ReadUTF8(const char *Input, uint32_t *Output);
-
-// === GLOBALS ===
-tFont gSystemFont = {
- .CacheGlyph = _SystemFont_CacheGlyph
-};
-
-// === CODE ===
-/**
- * \brief Draw text to the screen
- */
-int Video_DrawText(short X, short Y, short W, short H, tFont *Font, uint32_t Color, char *Text)
-{
- int xOfs = 0;
- tGlyph *glyph;
- uint32_t ch = 0;
-
- _SysDebug("Video_DrawText: (X=%i,Y=%i,W=%i,H=%i,Font=%p,", X, Y, W, H, Font);
- _SysDebug(" Color=%08x,Text='%s')", Color, Text);
-
- // Check the bounds
- if(W < 0 || X < 0 || X >= giScreenWidth) return 0;
- if(X + W > giScreenWidth) W = giScreenWidth - X;
-
- if(H < 0 || Y < 0 || Y >= giScreenHeight) return 0;
- if(Y + H > giScreenHeight) H = giScreenHeight - Y;
-
- // Handle NULL font (system default monospace)
- if( !Font ) Font = &gSystemFont;
-
- while( *Text )
- {
- // Read character
- Text += ReadUTF8(Text, &ch);
-
- // Find (or load) the glyph
- glyph = _GetGlyph(Font, ch);
- if( !glyph ) continue ; // If not found, just don't render it
-
- // End render if it will overflow the perscribed range
- if( xOfs + glyph->TrueWidth > W )
- break;
-
- xOfs += glyph->Width;
- _RenderGlyph(X + xOfs, Y, glyph, Color);
- }
-
- return xOfs;
-}
-
-void Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H)
-{
- int w=0, h=0;
- uint32_t ch;
- tGlyph *glyph;
- if( !Font ) Font = &gSystemFont;
-
- while( *Text )
- {
- Text += ReadUTF8(Text, &ch);
- glyph = _GetGlyph(Font, ch);
- if( !glyph ) continue;
-
- w += glyph->Width;
- if( h < glyph->Height ) h = glyph->Height;
- }
-
- if(W) *W = w;
- if(H) *H = h;
-}
-
-tGlyph *_GetGlyph(tFont *Font, uint32_t Codepoint)
-{
- tGlyph *next = NULL, *prev = NULL;
- tGlyph *new;
-
- // Check for ASCII
- if( Codepoint < 128 )
- {
- if( Font->AsciiGlyphs[Codepoint] == NULL ) {
- Font->AsciiGlyphs[Codepoint] = Font->CacheGlyph(Font, Codepoint);
- }
-
- return Font->AsciiGlyphs[Codepoint];
- }
-
- // If within the range
- if( Font->FirstGlyph && Font->FirstGlyph->Codepoint < Codepoint && Codepoint < Font->LastGlyph->Codepoint )
- {
- // Find what end is "closest"
- if( Codepoint - Font->FirstGlyph->Codepoint < Font->LastGlyph->Codepoint - Codepoint )
- {
- // Start from the bottom
- for( next = Font->FirstGlyph;
- next && next->Codepoint < Codepoint;
- prev = next, next = next->Next
- );
-
- if( next->Codepoint == Codepoint )
- return next;
-
- }
- else
- {
- // Start at the top
- // NOTE: The roles of next and prev are reversed here to allow
- // the insert to be able to assume that `prev` is the
- // previous entry, and `next` is the next.
- for( prev = Font->LastGlyph;
- prev && prev->Codepoint > Codepoint;
- next = prev, prev = prev->Prev
- );
- if( prev->Codepoint == Codepoint )
- return prev;
- }
- }
- else
- {
- // If below first
- if( !Font->FirstGlyph || Font->FirstGlyph->Codepoint > Codepoint ) {
- prev = NULL;
- next = Font->FirstGlyph;
- }
- // Above last
- else {
- prev = Font->LastGlyph;
- next = NULL;
- }
- }
-
- // Load new
- new = Font->CacheGlyph(Font, Codepoint);
- if( !new ) return NULL;
-
- // Add to list
- // - Forward link
- if( prev ) {
- new->Next = prev->Next;
- prev->Next = new;
- }
- else {
- new->Next = Font->FirstGlyph;
- Font->FirstGlyph = new;
- }
-
- // - Backlink
- if( next ) {
- new->Prev = next->Prev;
- next->Prev = new;
- }
- else {
- new->Prev = Font->LastGlyph;
- Font->LastGlyph = new;
- }
-
- // Return
- return new;
-}
-
-/**
- */
-void _RenderGlyph(short X, short Y, tGlyph *Glyph, uint32_t Color)
-{
- int xStart = 0, yStart = 0;
- int x, y;
- uint32_t *outBuf;
- uint8_t *inBuf;
- // TODO: Implement
-
- X += Glyph->OffsetX;
- if( X < 0 ) { // If -ve, skip the first -X collums
- xStart = -X;
- X = 0;
- }
-
- Y += Glyph->OffsetY;
- if( Y < 0 ) { // If -ve, skip the first -Y lines
- yStart = -Y;
- Y = 0;
- }
-
- outBuf = gpScreenBuffer + Y*giScreenWidth + X;
- inBuf = Glyph->Bitmap + yStart*Glyph->TrueWidth;
-
- for( y = yStart; y < Glyph->TrueHeight; y ++ )
- {
- for( x = xStart; x < Glyph->TrueWidth; x ++ )
- {
- outBuf[x] = Video_AlphaBlend( outBuf[x], Color, inBuf[x] );
- }
- outBuf += giScreenWidth;
- inBuf += Glyph->TrueWidth;
-
- }
-}
-
-// Load system font (8x16 monospace)
-#include "font_8x16.h"
-
-/*
- */
-tGlyph *_SystemFont_CacheGlyph(tFont *Font, uint32_t Codepoint)
-{
- int i;
- uint8_t index = 0;
- tGlyph *ret;
- uint8_t *data;
-
- _SysDebug("_SystemFont_CacheGlyph: (Font=%p, Codepoint=0x%06x)", Font, Codepoint);
-
- if( Codepoint < 128 ) {
- index = Codepoint;
- }
- else {
- index = '?'; // Unknowns come out as a question mark
- }
-
- _SysDebug(" index = %i", index);
-
- ret = malloc( sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT );
- if( !ret ) {
- _SysDebug("ERROR: malloc(%i) failed", sizeof(tGlyph) + FONT_WIDTH*FONT_HEIGHT);
- return NULL;
- }
-
- ret->Codepoint = Codepoint;
-
- ret->Width = FONT_WIDTH;
- ret->Height = FONT_HEIGHT;
-
- ret->TrueWidth = FONT_WIDTH;
- ret->TrueHeight = FONT_HEIGHT;
-
- ret->OffsetX = 0;
- ret->OffsetY = 0;
-
- data = &VTermFont[index * FONT_HEIGHT];
-
- for( i = 0; i < FONT_HEIGHT; i ++ )
- {
- ret->Bitmap[ i * 8 + 0 ] = data[i] & (1 << 7) ? 255 : 0;
- ret->Bitmap[ i * 8 + 1 ] = data[i] & (1 << 6) ? 255 : 0;
- ret->Bitmap[ i * 8 + 2 ] = data[i] & (1 << 5) ? 255 : 0;
- ret->Bitmap[ i * 8 + 3 ] = data[i] & (1 << 4) ? 255 : 0;
- ret->Bitmap[ i * 8 + 4 ] = data[i] & (1 << 3) ? 255 : 0;
- ret->Bitmap[ i * 8 + 5 ] = data[i] & (1 << 2) ? 255 : 0;
- ret->Bitmap[ i * 8 + 6 ] = data[i] & (1 << 1) ? 255 : 0;
- ret->Bitmap[ i * 8 + 7 ] = data[i] & (1 << 0) ? 255 : 0;
- }
-
- return ret;
-}
-
-
-/**
- * \fn int ReadUTF8(char *Input, uint32_t *Val)
- * \brief Read a UTF-8 character from a string
- */
-int ReadUTF8(const char *Input, uint32_t *Val)
-{
- const uint8_t *str = (const uint8_t *)Input;
- *Val = 0xFFFD; // Assume invalid character
-
- // ASCII
- if( !(*str & 0x80) ) {
- *Val = *str;
- return 1;
- }
-
- // Middle of a sequence
- if( (*str & 0xC0) == 0x80 ) {
- return 1;
- }
-
- // Two Byte
- if( (*str & 0xE0) == 0xC0 ) {
- *Val = (*str & 0x1F) << 6; // Upper 6 Bits
- str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F); // Lower 6 Bits
- return 2;
- }
-
- // Three Byte
- if( (*str & 0xF0) == 0xE0 ) {
- *Val = (*str & 0x0F) << 12; // Upper 4 Bits
- str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F) << 6; // Middle 6 Bits
- str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F); // Lower 6 Bits
- return 3;
- }
-
- // Four Byte
- if( (*str & 0xF1) == 0xF0 ) {
- *Val = (*str & 0x07) << 18; // Upper 3 Bits
- str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F) << 12; // Middle-upper 6 Bits
- str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F) << 6; // Middle-lower 6 Bits
- str ++;
- if( (*str & 0xC0) != 0x80) return -1; // Validity check
- *Val |= (*str & 0x3F); // Lower 6 Bits
- return 4;
- }
-
- // UTF-8 Doesn't support more than four bytes
- return 4;
-}
-
-
-
-
+++ /dev/null
-/*
- * Acess GUI (AxWin) Version 2
- * By John Hodge (thePowersGang)
- *
- * Window Manager and Widget Control
- */
-#include "common.h"
-#include <stdlib.h>
-#include <string.h>
-#include "wm.h"
-#include <acess/sys.h> // _SysDebug
-
-// === IMPORTS ===
-extern void Video_GetTextDims(tFont *Font, const char *Text, int *W, int *H);
-
-// === PROTOTYPES ===
-tApplication *AxWin_RegisterClient(tIPC_Type *IPCType, void *Ident, const char *Name);
-void AxWin_DeregisterClient(tApplication *App);
-tApplication *AxWin_GetClient(tIPC_Type *Method, void *Ident);
-tElement *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName);
-void AxWin_DeleteElement(tElement *Element);
-void AxWin_SetFlags(tElement *Element, int Flags);
-void AxWin_SetSize(tElement *Element, int Size);
-void AxWin_SetText(tElement *Element, const char *Text);
-
-// === GLOBALS ===
-// - TODO: Handle windows by having multiple root elements
-tElement gWM_RootElement = {
- .DebugName = "ROOT"
-};
-tWindow *gWM_WindowFirst;
-tWindow *gWM_WindowLast;
-tApplication *gWM_Applications;
- int giWM_MaxAreaX = 0;
- int giWM_MaxAreaY = 0;
- int giWM_MaxAreaW = -1;
- int giWM_MaxAreaH = -1;
-
-// --- Element type flags
-struct {
- void (*Init)(tElement *This);
- void (*Delete)(tElement *This);
- void (*UpdateFlags)(tElement *This);
- void (*UpdateSize)(tElement *This);
- void (*UpdateText)(tElement *This);
-} gaWM_WidgetTypes[MAX_ELETYPES] = {
- {NULL, NULL, NULL, NULL, NULL}, // NULL
- {NULL, NULL, NULL, NULL, NULL}, // Window
- {NULL, NULL, NULL, NULL, NULL} // Box
-};
-const int ciWM_NumWidgetTypes = sizeof(gaWM_WidgetTypes)/sizeof(gaWM_WidgetTypes[0]);
-
-// === CODE ===
-tApplication *AxWin_RegisterClient(tIPC_Type *Method, void *Ident, const char *Name)
-{
- int identlen = Method->GetIdentSize(Ident);
- // Structure, empty string, Name, Ident
- tApplication *ret = calloc( 1, sizeof(tApplication) + 1 + strlen(Name) + 1 + identlen );
-
- // DebugName is empty
-
- // Name/Title
- ret->Name = &ret->MetaElement.DebugName[1];
- strcpy(ret->Name, Name);
- // Ident
- ret->Ident = ret->Name + strlen(Name) + 1;
- memcpy(ret->Ident, Ident, identlen);
- // IPC Type
- ret->IPCType = Method;
-
- // Element index
- ret->MaxElementIndex = DEFAULT_ELEMENTS_PER_APP;
- ret->EleIndex = calloc( 1, ret->MaxElementIndex * sizeof(*ret->EleIndex) );
-
- // Add to global list
- ret->Next = gWM_Applications;
- gWM_Applications = ret;
-
- // TODO: Inform listeners of the new application
-
- return ret;
-}
-
-void AxWin_DeregisterClient(tApplication *App)
-{
- // TODO: Complete implementing DeregisterClient
- tElement *win, *next;
-
- for( win = App->MetaElement.FirstChild; win; win = next )
- {
- next = win->NextSibling;
- AxWin_DeleteElement(win);
- }
-
- // TODO: Inform listeners of deleted application
-
- // Remove from list
- {
- tApplication *app, *prev = NULL;
- for( app = gWM_Applications; app; app = app->Next )
- {
- if( app == App ) break;
- prev = app;
- }
-
- if( app )
- {
- if(prev)
- prev->Next = App->Next;
- else
- gWM_Applications = App->Next;
- }
- }
-
- free(App);
-}
-
-/**
- * \brief Get an application handle from a client identifier
- */
-tApplication *AxWin_GetClient(tIPC_Type *Method, void *Ident)
-{
- // TODO: Faster and smarter technique
- tApplication *app;
- for( app = gWM_Applications; app; app = app->Next )
- {
- if( app->IPCType != Method ) continue;
- if( Method->CompareIdent( app->Ident, Ident ) != 0 ) continue;
- return app;
- }
- return NULL;
-}
-
-tElement *AxWin_CreateAppWindow(tApplication *App, const char *Name)
-{
- tElement *ret;
- tWindow *win;
-
- win = calloc(1, sizeof(tWindow) + 1);
- if(!win) return NULL;
-
- ret = &win->RootElement;
- ret->Type = ELETYPE_WINDOW;
- ret->Data = win;
- ret->Parent = &App->MetaElement;
-
- // Add to parent list
- if(ret->Parent->LastChild)
- ret->Parent->LastChild->NextSibling = ret;
- ret->Parent->LastChild = ret;
- if(!ret->Parent->FirstChild)
- ret->Parent->FirstChild = ret;
-
- ret->Text = strdup(Name);
-
- return ret;
-}
-
-// --- Widget Creation and Control ---
-tAxWin_Element *AxWin_CreateElement(tElement *Parent, int Type, int Flags, const char *DebugName)
-{
- tElement *ret;
- const char *dbgName = DebugName ? DebugName : "";
-
- ret = calloc(sizeof(tElement)+strlen(dbgName)+1, 1);
- if(!ret) return NULL;
-
- // Prepare
- ret->Type = Type;
- strcpy(ret->DebugName, dbgName);
- if(Parent == NULL) Parent = &gWM_RootElement;
- ret->Parent = Parent;
- ret->Flags = Flags;
-
- // Append to parent's list
- if(Parent->LastChild)
- Parent->LastChild->NextSibling = ret;
- Parent->LastChild = ret;
- if(!Parent->FirstChild) Parent->FirstChild = ret;
-
- ret->PaddingL = 2;
- ret->PaddingR = 2;
- ret->PaddingT = 2;
- ret->PaddingB = 2;
-
- if( Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Type].Init )
- gaWM_WidgetTypes[Type].Init(ret);
-
- WM_UpdateMinDims(ret->Parent);
-
- return ret;
-}
-
-/**
- * \brief Delete an element
- */
-void AxWin_DeleteElement(tElement *Element)
-{
- tElement *child, *next;
-
- for(child = Element->FirstChild; child; child = next)
- {
- next = child->NextSibling;
- AxWin_DeleteElement(child);
- }
-
- // TODO: Implement AxWin_DeleteElement
- // TODO: Clean up related data.
- if( Element->Type < ciWM_NumWidgetTypes && gaWM_WidgetTypes[Element->Type].Delete )
- gaWM_WidgetTypes[Element->Type].Delete(Element);
-
- if(Element->Owner)
- Element->Owner->EleIndex[ Element->ApplicationID ] = NULL;
-
- Element->Type = 0;
- Element->Owner = 0;
- Element->Flags = 0;
-
- free(Element);
-}
-
-/**
- * \brief Alter an element's flags
- */
-void AxWin_SetFlags(tElement *Element, int Flags)
-{
- // Permissions are handled in the message handler
- if(!Element) {
- gWM_RootElement.Flags = Flags;
- return ;
- }
-
- Element->Flags = Flags;
- return ;
-}
-
-/**
- * \brief Set the fixed lenghthways size of an element
- */
-void AxWin_SetSize(tElement *Element, int Size)
-{
- if(!Element) return ;
- Element->FixedWith = Size;
- return ;
-}
-
-/**
- * \brief Set the text field of an element
- * \note Used for the image path on ELETYPE_IMAGE
- */
-void AxWin_SetText(tElement *Element, const char *Text)
-{
- if(!Element) return ;
- if(Element->Text) free(Element->Text);
- Element->Text = strdup(Text);
-
- switch(Element->Type)
- {
- case ELETYPE_IMAGE:
- if(Element->Data) free(Element->Data);
- Element->Data = Image_Load( Element->Text );
- if(!Element->Data) {
- Element->Flags &= ~ELEFLAG_FIXEDSIZE;
- return ;
- }
-
- //Element->Flags |= ELEFLAG_FIXEDSIZE;
- Element->CachedW = ((tImage*)Element->Data)->Width;
- Element->CachedH = ((tImage*)Element->Data)->Height;
-
- if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
- Element->MinCross = ((tImage*)Element->Data)->Width;
- Element->MinWith = ((tImage*)Element->Data)->Height;
- }
- else {
- Element->MinWith = ((tImage*)Element->Data)->Width;
- Element->MinCross = ((tImage*)Element->Data)->Height;
- }
- break;
-
- case ELETYPE_TEXT:
- {
- int w=0, h=0;
- Video_GetTextDims(NULL, Element->Text, &w, &h);
- if(Element->Parent && Element->Parent->Flags & ELEFLAG_VERTICAL) {
- Element->MinCross = w;
- Element->MinWith = h;
- }
- else {
- Element->MinWith = w;
- Element->MinCross = h;
- }
- }
- break;
- default: // Any other, no special case
- break ;
- }
-
- return ;
-}
+++ /dev/null
-/*
- * Acess2 Window Manager (AxWin2)
- */
-#ifndef _WM_H_
-#define _WM_H_
-
-#include <axwin2/axwin.h>
-#include "common.h"
-
-/**
- * \brief Number of elements that can be owned by each application
- */
-// TODO: Fine tune these values
-#define MAX_ELEMENTS_PER_APP 1024
-#define DEFAULT_ELEMENTS_PER_APP 128
-
-typedef struct sAxWin_Element tElement;
-typedef struct sMenuItem tMenuItem;
-typedef struct sWindow tWindow;
-typedef struct sApplication tApplication;
-
-struct sAxWin_Element
-{
- enum eElementTypes Type;
-
- // Element Tree
- tElement *Parent;
- tElement *FirstChild;
- tElement *LastChild;
- tElement *NextSibling;
-
- // Application
- tApplication *Owner; //!< Owning application
- uint16_t ApplicationID; //!< Index into sApplication::EleIndex
-
- // User modifiable attributes
- short PaddingL, PaddingR;
- short PaddingT, PaddingB;
- short GapSize;
-
- uint32_t Flags;
-
- short FixedWith; //!< Fixed lengthways Size attribute (height)
- short FixedCross; //!< Fixed Cross Size attribute (width)
-
- char *Text;
-
- // -- Attributes maitained by the element code
- // Not touched by the user
- short MinWith; //!< Minimum long size
- short MinCross; //!< Minimum cross size
- void *Data; //!< Per-type data
-
- // -- Render Cache
- short CachedX, CachedY;
- short CachedW, CachedH;
-
- char DebugName[];
-};
-
-struct sMenuItem
-{
- tMenuItem *Next;
- int Flags;
- int ID; //!< ID number sent to application
- const char *Label;
- const char *Right;
- tMenuItem *FirstChild;
-};
-
-struct sWindow
-{
- int X, Y, W, H;
- void *Icon;
-
- tApplication *App;
-
- tWindow *OrderNext; // Render order
-
- tMenuItem *Menus;
-
- tElement RootElement;
-};
-
-struct sApplication
-{
- tApplication *Next;
-
- tIPC_Type *IPCType;
- void *Ident; //!< Client Identifier
-
- char *Name; //!< Application name
-
- int MaxElementIndex; //!< Number of entries in \a EleIndex
- tElement **EleIndex; //!< Array of pointers to elements owned by this application
-
- tElement MetaElement; //!< Tabs child off this
-};
-
-// === FUNCTIONS ===
-
-// --- Render
-extern void WM_UpdateMinDims(tElement *Element);
-extern void WM_UpdateDimensions(tElement *Element, int Pass);
-extern void WM_UpdatePosition(tElement *Element);
-extern void WM_RenderWidget(tElement *Element);
-extern void WM_Update(void);
-
-#endif
+++ /dev/null
-Applications can have 0-* windows
-Windows can have 1-* tabs
-Each window has a menu based on a template from the application
void create_sidebar(void);
void create_mainmenu(void);
void create_run_dialog(void);
+void mainmenu_run_dialog(void *unused);
// === GLOBALS ===
tHWND gSidebar;
create_mainmenu();
create_run_dialog();
+ AxWin3_RegisterAction(gSidebar, "Interface>Run", (tAxWin3_HotkeyCallback)mainmenu_run_dialog);
+// AxWin3_RegisterAction(gSidebar, "Interface>Terminal", mainmenu_app_terminal);
+// AxWin3_RegisterAction(gSidebar, "Interface>TextEdit", mainmenu_app_textedit);
+
// Idle loop
AxWin3_MainLoop();
void mainmenu_run_dialog(void *unused)
{
AxWin3_ShowWindow(gRunDialog, 1);
+ AxWin3_FocusWindow(gRunDialog);
}
void create_mainmenu(void)
// --------------------------------------------------------------------
int run_dorun(tAxWin3_Widget *unused)
{
+ _SysDebug("DoRun pressed");
char *cmd = AxWin3_Widget_GetText(gRunInput);
_SysDebug("Command string '%s'", cmd);
AxWin3_ShowWindow(gRunDialog, 0);
install:
@$(xMKDIR) $(DISTROOT)/Apps ; true
@$(xMKDIR) $(DISTROOT)/Apps/AxWin ; true
- @$(xMKDIR) $(DISTROOT)/Apps/3.0 ; true
+ @$(xMKDIR) $(DISTROOT)/Apps/AxWin/3.0 ; true
@$(foreach DIR,$(DIRS), echo --- $(NAME)/$(DIR) && $(SUBMAKE) -C $(DIR) $@ &&) true
@$(foreach FILE,$(FILES), $(xCP) $(FILE:-%=%) $(DISTROOT)/Apps/AxWin/3.0/$(FILE:-%=%) &&) true
-include ../../Makefile.cfg
CPPFLAGS += -I include/ -I ../include/
+CFLAGS += -std=gnu99
DIR := Apps/AxWin/3.0
BIN := AxWinWM
OBJ := main.o input.o video.o ipc.o image.o utf-8.o
-OBJ += wm.o wm_input.o wm_render.o wm_render_text.o
+OBJ += wm.o wm_input.o wm_render.o wm_render_text.o wm_hotkeys.o
OBJ += decorator.o
OBJ += renderers/passthru.o
OBJ += renderers/background.o
}
// Draw title bar
+ // - Body
WM_Render_FillRect(Window,
0, -ciTitlebarHeight, Window->W, ciTitlebarHeight,
(bActive ? cColourActive_Titlebar : cColourInactive_Titlebar)
);
+ // - Top Border
WM_Render_FillRect(Window,
0, -ciTitlebarHeight, Window->W, 1,
cColour_TitleTopBorder
);
+ // - Sides
WM_Render_FillRect(Window,
0, -ciTitlebarHeight, 1, ciTitlebarHeight,
cColour_SideBorder
cColour_SideBorder
);
+ // Get the font height
WM_Render_GetTextDims(
NULL, // TODO: Select font
Window->Title ? Window->Title : "jI", -1,
&text_width, &text_height
);
+ // - Use that to draw the window title on the left of the window
WM_Render_DrawText(Window,
ciTitlebarHeight + 4, -(ciTitlebarHeight - (ciTitlebarHeight/2 - text_height/2)),
Window->W - ciTitlebarHeight - 4, text_height,
(bActive ? cColourActive_TitleText : cColourInactive_TitleText),
Window->Title ? Window->Title : "--", -1
);
-
+
+ // TODO: Minimise, Maximise and Close
+
// Maximized windows don't have any other borders
if( Window->Flags & WINFLAG_MAXIMIZED )
return ;
- // Left
+ // Left Border
WM_Render_FillRect(Window,
-ciSideBorderWidth, -ciTitlebarHeight,
ciSideBorderWidth, Window->H + ciTitlebarHeight + ciBottomBorderWidth,
cColour_SideBorder
);
- // Right
+ // Right Border
WM_Render_FillRect(Window,
Window->W, -ciTitlebarHeight,
ciSideBorderWidth, Window->H + ciTitlebarHeight + ciBottomBorderWidth,
cColour_SideBorder
);
- // Bottom
+ // Bottom Border (hard line)
WM_Render_FillRect(Window,
-ciSideBorderWidth, Window->H,
ciSideBorderWidth*2+Window->W, 1,
0x000000
);
+ // Bottom Border
WM_Render_FillRect(Window,
-ciSideBorderWidth, Window->H+1,
ciSideBorderWidth*2+Window->W, ciBottomBorderWidth-1,
#define TODO(str)
+#define ASSERT(expr) do{if(!(expr)){_SysDebug("%s:%i - ASSERTION FAILED: "#expr, __FILE__, __LINE__);exit(-1);}}while(0)
+
#define UNIMPLEMENTED() do{_SysDebug("TODO: Implement %s", __func__); for(;;);}while(0)
#define AXWIN_VERSION 0x300
+++ /dev/null
-/*
- * Acess2 GUI (AxWin3)
- */
-#ifndef _MESSAGES_H_
-#define _MESSAGES_H_
-
-struct sAxWin_Message
-{
- uint16_t ID;
-};
-
-typedef struct sAxWin_Message tAxWin_Message;
-
-enum eMessages
-{
- MSG_NULL,
- MSG_CREATEWIN
-};
-
-#endif
-
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * wm_hotkeys.h
+ * - Hotkey and key shortcut code
+ */
+#ifndef _WM_HOTKEYS_H_
+#define _WM_HOTKEYS_H_
+
+typedef struct sHotkey tHotkey;
+typedef struct sHotkeyTarget tHotkeyTarget;
+
+struct sHotkey
+{
+ tHotkey *Next;
+
+ const char *Target;
+
+ int nKeys;
+ uint32_t Keys[];
+};
+
+struct sHotkeyTarget
+{
+ struct sHotkeyTarget *Next;
+
+ const char *Name;
+
+ tWindow *Window;
+ int Index;
+};
+
+
+extern void WM_Hotkey_Register(int nKeys, uint32_t *Keys, const char *ActionName);
+extern void WM_Hotkey_RegisterAction(const char *ActionName, tWindow *Target, uint16_t Index);
+extern void WM_Hotkey_KeyDown(uint32_t Scancode);
+extern void WM_Hotkey_KeyUp(uint32_t Scancode);
+
+#endif
+
+++ /dev/null
-/*
- * Acess2 Window Manager v3 (axwin3)
- * - By John Hodge (thePowersGang)
- *
- * include/wm_messages.h
- * - Core window messages
- */
-#ifndef _WM_MESSAGES_H_
-#define _WM_MESSAGES_H_
-
-/**
- * \brief Messages delivered to windows
- */
-enum eWM_WindowMessages
-{
- WNDMSG_NULL,
-
- WNDMSG_CREATE,
- WNDMSG_DESTROY,
- WNDMSG_FOCUS, // Called on change
- WNDMSG_SHOW, // Called on change
-
- WNDMSG_RESIZE,
-
- WNDMSG_MOUSEMOVE,
- WNDMSG_MOUSEBTN,
- WNDMSG_KEYDOWN,
- WNDMSG_KEYFIRE,
- WNDMSG_KEYUP,
-
- WNDMSG_CLASS_MIN = 0x1000,
- WNDMSG_CLASS_MAX = 0x2000,
-};
-
-struct sWndMsg_Bool
-{
- uint8_t Val;
-};
-
-struct sWndMsg_Resize
-{
- uint16_t W, H;
-};
-
-struct sWndMsg_MouseMove
-{
- int16_t X, Y;
- int16_t dX, dY;
-};
-
-struct sWndMsg_MouseButton
-{
- int16_t X, Y;
- uint8_t Button;
- uint8_t bPressed;
-};
-
-struct sWndMsg_KeyAction
-{
- uint32_t KeySym;
- uint32_t UCS32;
-};
-
-#endif
#include <common.h>
#include <acess/sys.h>
#include <wm_input.h>
+#include <stddef.h>
// TODO: Move out to a common header
typedef struct
// === IMPORTS ===
extern void Video_SetCursorPos(short X, short Y);
const char *gsMouseDevice;
-extern int giTerminalFD;
+extern int giTerminalFD_Input;
extern int giScreenWidth;
extern int giScreenHeight;
void Input_FillSelect(int *nfds, fd_set *set)
{
- if(*nfds < giTerminalFD) *nfds = giTerminalFD;
+ if(*nfds < giTerminalFD_Input) *nfds = giTerminalFD_Input;
if(*nfds < giMouseFD) *nfds = giMouseFD;
- FD_SET(giTerminalFD, set);
+ FD_SET(giTerminalFD_Input, set);
FD_SET(giMouseFD, set);
}
void Input_HandleSelect(fd_set *set)
{
- if(FD_ISSET(giTerminalFD, set))
+ if(FD_ISSET(giTerminalFD_Input, set))
{
uint32_t codepoint;
static uint32_t scancode;
#define KEY_CODEPOINT_MASK 0x3FFFFFFF
- if( read(giTerminalFD, &codepoint, sizeof(codepoint)) != sizeof(codepoint) )
+ size_t readlen = read(giTerminalFD_Input, &codepoint, sizeof(codepoint));
+ if( readlen != sizeof(codepoint) )
{
// oops, error
- _SysDebug("Terminal read failed?");
+ _SysDebug("Terminal read failed? (%i != %i)", readlen, sizeof(codepoint));
}
// _SysDebug("Keypress 0x%x", codepoint);
#include <stdio.h>
#include <wm.h>
#include <wm_internals.h>
+#include <wm_hotkeys.h>
#define AXWIN_PORT 4101
int tmp;
// TODO: Check this
giNetworkFileHandle = open("/Devices/ip/loop/udp", OPENFLAG_READ);
- tmp = AXWIN_PORT; ioctl(giNetworkFileHandle, 4, &tmp); // TODO: Don't hard-code IOCtl number
+ if( giNetworkFileHandle != -1 )
+ {
+ tmp = AXWIN_PORT;
+ ioctl(giNetworkFileHandle, 4, &tmp); // TODO: Don't hard-code IOCtl number
+ }
}
void IPC_FillSelect(int *nfds, fd_set *set)
{
- if( giNetworkFileHandle > *nfds ) *nfds = giNetworkFileHandle;
- FD_SET(giNetworkFileHandle, set);
+ if( giNetworkFileHandle != -1 )
+ {
+ if( giNetworkFileHandle > *nfds ) *nfds = giNetworkFileHandle;
+ FD_SET(giNetworkFileHandle, set);
+ }
}
void IPC_HandleSelect(fd_set *set)
{
- if( FD_ISSET(giNetworkFileHandle, set) )
+ if( giNetworkFileHandle != -1 )
{
- char staticBuf[STATICBUF_SIZE];
- int readlen, identlen;
- char *msg;
-
- readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf));
-
- identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] );
- msg = staticBuf + identlen;
-
- IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg);
-// _SysDebug("IPC_HandleSelect: UDP handled");
+ if( FD_ISSET(giNetworkFileHandle, set) )
+ {
+ char staticBuf[STATICBUF_SIZE];
+ int readlen, identlen;
+ char *msg;
+
+ readlen = read(giNetworkFileHandle, staticBuf, sizeof(staticBuf));
+
+ identlen = 4 + Net_GetAddressSize( ((uint16_t*)staticBuf)[1] );
+ msg = staticBuf + identlen;
+
+ IPC_Handle(&gIPC_Type_Datagram, staticBuf, readlen - identlen, (void*)msg);
+// _SysDebug("IPC_HandleSelect: UDP handled");
+ }
}
while(SysGetMessage(NULL, NULL))
}
// --- IPC Message Handlers ---
+int IPC_Msg_Ping(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+{
+ ASSERT(Msg->ID == IPCMSG_PING);
+
+ if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0;
+
+ if( Msg->Size < 4 ) return -1;
+
+ tIPCMsg_ReturnInt *ret = (void*)Msg->Data;
+ Msg->ID = IPCMSG_PING;
+ Msg->Size = sizeof(*ret);
+ ret->Value = AXWIN_VERSION;
+ Client->IPCType->SendMessage(Client->Ident, sizeof(*Msg)+sizeof(*ret), Msg);
+ return 0;
+}
+
+int IPC_Msg_GetDisplayCount(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+{
+ tAxWin_IPCMessage *ret_hdr;
+ tIPCMsg_ReturnInt *ret;
+ char buf[sizeof(*ret_hdr)+sizeof(*ret)];
+
+ ASSERT(Msg->ID == IPCMSG_GETDISPLAYCOUNT);
+
+ if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0;
+
+ ret_hdr = (void*)buf;
+ ret_hdr->ID = IPCMSG_GETDISPLAYCOUNT;
+ ret_hdr->Flags = 0;
+ ret_hdr->Window = -1;
+ ret_hdr->Size = sizeof(*ret);
+ ret = (void*)ret_hdr->Data;
+ ret->Value = 1; // HARD CODE - Current version only supports one display
+
+ Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
+ return 0;
+}
+
+int IPC_Msg_GetDisplayDims(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+{
+ tIPCMsg_GetDisplayDims *info;
+ tAxWin_IPCMessage *ret_hdr;
+ tIPCMsg_RetDisplayDims *ret;
+ char buf[sizeof(*ret_hdr)+sizeof(*ret)];
+
+ ASSERT(Msg->ID == IPCMSG_GETDISPLAYDIMS);
+
+ if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0;
+
+ info = (void*)Msg->Data;
+
+ ret_hdr = (void*)buf;
+ ret_hdr->ID = IPCMSG_GETDISPLAYDIMS;
+ ret_hdr->Flags = 0;
+ ret_hdr->Window = -1;
+ ret_hdr->Size = sizeof(*ret);
+ ret = (void*)ret_hdr->Data;
+
+ // HARD CODE! Only one display supported
+ if( info->DisplayID == 0 )
+ {
+ ret->X = 0;
+ ret->Y = 0;
+ ret->W = giScreenWidth;
+ ret->H = giScreenHeight;
+ }
+ else
+ {
+ ret->X = 0; ret->Y = 0;
+ ret->W = 0; ret->H = 0;
+ }
+
+ Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
+ return 0;
+}
+
int IPC_Msg_SendMsg(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
{
tIPCMsg_SendMsg *info = (void*)Msg->Data;
tWindow *src, *dest;
+
+ ASSERT(Msg->ID == IPCMSG_SENDMSG);
// - Sanity checks
if( Msg->Size < sizeof(tIPCMsg_SendMsg) )
return 0;
}
-int IPC_Msg_FocusWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
-{
- tWindow *win;
-
- // Don't allow the focus to be changed unless the client has the focus
- if(!gpWM_FocusedWindow) return 1;
- if(gpWM_FocusedWindow->Client != Client) return 1;
-
- win = IPC_int_GetWindow(Client, Msg->Window);
- if(!win) return 1;
-
- WM_FocusWindow(win);
-
- return 0;
-}
-
int IPC_Msg_CreateWin(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
{
tIPCMsg_CreateWin *info = (void*)Msg->Data;
tWindow *newwin, *parent;
+ ASSERT(Msg->ID == IPCMSG_CREATEWIN);
+
// - Sanity checks
// > +1 is for NULL byte on string
if( Msg->Size < sizeof(*info) + 1 ) {
{
tWindow *win;
+ ASSERT(Msg->ID == IPCMSG_SETWINTITLE);
+
if( Msg->Size < 1 ) return -1;
if( Msg->Data[ Msg->Size-1 ] != '\0' ) return -1;
tIPCMsg_Boolean *info = (void*)Msg->Data;
tWindow *win;
+ ASSERT(Msg->ID == IPCMSG_SHOWWINDOW);
+
if( Msg->Size < sizeof(*info) ) return -1;
win = IPC_int_GetWindow(Client, Msg->Window);
return 0;
}
+int IPC_Msg_FocusWindow(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+{
+ tWindow *win;
+
+ ASSERT(Msg->ID == IPCMSG_FOCUSWINDOW);
+
+ // Don't allow the focus to be changed unless the client has the focus
+ if(!gpWM_FocusedWindow) return 1;
+ if(gpWM_FocusedWindow->Client != Client) return 1;
+
+ win = IPC_int_GetWindow(Client, Msg->Window);
+ if(!win) return 1;
+
+ WM_FocusWindow(win);
+
+ return 0;
+}
+
int IPC_Msg_SetWinPos(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
{
tIPCMsg_SetWindowPos *info = (void*)Msg->Data;
tWindow *win;
+ ASSERT(Msg->ID == IPCMSG_SETWINPOS);
+
if(Msg->Size < sizeof(*info)) return -1;
win = IPC_int_GetWindow(Client, Msg->Window);
return 0;
}
-int IPC_Msg_GetDisplayCount(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
+int IPC_Msg_RegisterAction(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
{
- tAxWin_IPCMessage *ret_hdr;
- tIPCMsg_ReturnInt *ret;
- char buf[sizeof(*ret_hdr)+sizeof(*ret)];
-
- if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0;
-
- ret_hdr = (void*)buf;
- ret_hdr->ID = IPCMSG_GETDISPLAYCOUNT;
- ret_hdr->Flags = 0;
- ret_hdr->Window = -1;
- ret_hdr->Size = sizeof(*ret);
- ret = (void*)ret_hdr->Data;
- ret->Value = 1; // HARD CODE - Current version only supports one display
+ tIPCMsg_RegAction *info = (void*)Msg->Data;
+ tWindow *win;
- Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
- return 0;
-}
+ ASSERT(Msg->ID == IPCMSG_REGACTION);
-int IPC_Msg_GetDisplayDims(tIPC_Client *Client, tAxWin_IPCMessage *Msg)
-{
- tIPCMsg_GetDisplayDims *info;
- tAxWin_IPCMessage *ret_hdr;
- tIPCMsg_RetDisplayDims *ret;
- char buf[sizeof(*ret_hdr)+sizeof(*ret)];
+ if( Msg->Size < sizeof(*info) + 1 )
+ return -1;
- if( !(Msg->Flags & IPCMSG_FLAG_RETURN) ) return 0;
+ win = IPC_int_GetWindow(Client, Msg->Window);
+ if(!win) return 1;
- info = (void*)Msg->Data;
+ if( strnlen(info->Action, Msg->Size - sizeof(*info)) == Msg->Size - sizeof(*info) )
+ return 1;
+
+ _SysDebug("RegisterAction %p:%i [%i]\"%s\"",
+ Client, Msg->Window, info->Index, info->Action
+ );
+
+ WM_Hotkey_RegisterAction(info->Action, win, info->Index);
- ret_hdr = (void*)buf;
- ret_hdr->ID = IPCMSG_GETDISPLAYDIMS;
- ret_hdr->Flags = 0;
- ret_hdr->Window = -1;
- ret_hdr->Size = sizeof(*ret);
- ret = (void*)ret_hdr->Data;
-
- // HARD CODE! Only one display supported
- if( info->DisplayID == 0 )
- {
- ret->X = 0;
- ret->Y = 0;
- ret->W = giScreenWidth;
- ret->H = giScreenHeight;
- }
- else
- {
- ret->X = 0; ret->Y = 0;
- ret->W = 0; ret->H = 0;
- }
-
- Client->IPCType->SendMessage(Client->Ident, sizeof(buf), buf);
return 0;
}
+int (*gIPC_MessageHandlers[])(tIPC_Client *Client, tAxWin_IPCMessage *Msg) = {
+ IPC_Msg_Ping,
+ IPC_Msg_GetDisplayCount,
+ IPC_Msg_GetDisplayDims,
+ IPC_Msg_SendMsg,
+ IPC_Msg_CreateWin,
+ NULL, // Destroy window
+ IPC_Msg_SetWindowTitle,
+ IPC_Msg_ShowWindow,
+ IPC_Msg_DecorateWindow,
+ IPC_Msg_FocusWindow,
+ IPC_Msg_SetWinPos,
+ IPC_Msg_RegisterAction
+};
+const int giIPC_NumMessageHandlers = sizeof(gIPC_MessageHandlers)/sizeof(gIPC_MessageHandlers[0]);
+
void IPC_Handle(const tIPC_Type *IPCType, const void *Ident, size_t MsgLen, tAxWin_IPCMessage *Msg)
{
tIPC_Client *client;
client = IPC_int_GetClient(IPCType, Ident);
- switch((enum eAxWin_IPCMessageTypes) Msg->ID)
- {
- // --- Ping message (reset timeout and get server version)
- case IPCMSG_PING:
- _SysDebug(" IPC_Handle: IPCMSG_PING");
- if( Msg->Size < 4 ) return;
- if( Msg->Flags & IPCMSG_FLAG_RETURN )
- {
- tIPCMsg_ReturnInt *ret = (void*)Msg->Data;
- Msg->ID = IPCMSG_PING;
- Msg->Size = sizeof(*ret);
- ret->Value = AXWIN_VERSION;
- IPCType->SendMessage(Ident, sizeof(*Msg)+sizeof(*ret), Msg);
- }
- break;
-
- // -- Get display count
- case IPCMSG_GETDISPLAYCOUNT:
- rv = IPC_Msg_GetDisplayCount(client, Msg);
- break;
-
- // --- Get display dimensions
- case IPCMSG_GETDISPLAYDIMS:
- rv = IPC_Msg_GetDisplayDims(client, Msg);
- break;
-
- // --- Send a message
- case IPCMSG_SENDMSG:
- _SysDebug(" IPC_Handle: IPCMSG_SENDMSG %i", ((tIPCMsg_SendMsg*)Msg->Data)->ID);
- rv = IPC_Msg_SendMsg(client, Msg);
- break;
-
- // --- Create window
- case IPCMSG_CREATEWIN:
- _SysDebug(" IPC_Handle: IPCMSG_CREATEWIN");
- rv = IPC_Msg_CreateWin(client, Msg);
- break;
- // TODO: Destroy window
-
- // --- Set window title
- case IPCMSG_SETWINTITLE:
- _SysDebug(" IPC_Handle: IPCMSG_SETWINTITLE");
- rv = IPC_Msg_SetWindowTitle(client, Msg);
- break;
-
- // --- Give a window focus
- case IPCMSG_FOCUSWINDOW:
- _SysDebug(" IPC_Handle: IPCMSG_FOCUSWINDOW");
- rv = IPC_Msg_FocusWindow(client, Msg);
- break;
- // --- Show/Hide a window
- case IPCMSG_SHOWWINDOW:
- _SysDebug(" IPC_Handle: IPCMSG_SHOWWINDOW");
- rv = IPC_Msg_ShowWindow(client, Msg);
- break;
- case IPCMSG_DECORATEWINDOW:
- _SysDebug(" IPC_Handle: IPCMSG_DECORATEWINDOW");
- rv = IPC_Msg_DecorateWindow(client, Msg);
- break;
- // --- Move/Resize a window
- case IPCMSG_SETWINPOS:
- _SysDebug(" IPC_Handle: IPCMSG_SETWINPOS");
- rv = IPC_Msg_SetWinPos(client, Msg);
- break;
-
- // --- Unknown message
- default:
+ if( Msg->ID >= giIPC_NumMessageHandlers ) {
fprintf(stderr, "WARNING: Unknown message %i (%p)\n", Msg->ID, IPCType);
_SysDebug("WARNING: Unknown message %i (%p)", Msg->ID, IPCType);
- break;
+ return ;
}
- if(rv)
- _SysDebug("IPC_Handle: rv = %i", rv);
+
+ if( !gIPC_MessageHandlers[ Msg->ID ] ) {
+ fprintf(stderr, "WARNING: Message %i does not have a handler\n", Msg->ID);
+ _SysDebug("WARNING: Message %i does not have a handler", Msg->ID);
+ return ;
+ }
+
+ _SysDebug("IPC_Handle: Msg->ID = %i", Msg->ID);
+ rv = gIPC_MessageHandlers[Msg->ID](client, Msg);
+ _SysDebug("IPC_Handle: rv = %i", rv);
}
// --- Server->Client replies
#include <acess/sys.h>
#include <stdlib.h>
#include <stdio.h>
+#include <axwin3/keysyms.h>
// === IMPORTS ===
extern void Video_Setup(void);
extern int Renderer_Menu_Init(void);
extern int Renderer_Widget_Init(void);
extern int Renderer_Background_Init(void);
+extern int Renderer_Framebuffer_Init(void);
extern void WM_Update(void);
+extern void WM_Hotkey_Register(int nKeys, uint32_t *Keys, const char *ActionName);
// === PROTOTYPES ===
void ParseCommandline(int argc, char **argv);
int giScreenHeight = 480;
int giTerminalFD = -1;
+ int giTerminalFD_Input = 0;
int giMouseFD = -1;
#define __INSTALL_ROOT "/Acess/Apps/AxWin/3.0"
Renderer_Menu_Init();
Renderer_Widget_Init();
Renderer_Background_Init();
+ Renderer_Framebuffer_Init();
WM_Initialise();
+
+ // TODO: Config
+ uint32_t keys[4];
+ keys[0] = KEYSYM_LEFTGUI; keys[1] = KEYSYM_r;
+ WM_Hotkey_Register(2, keys, "Interface>Run");
// Spawn interface root
if( clone(CLONE_VM, 0) == 0 )
*/
#include <common.h>
#include <wm_renderer.h>
+#include <string.h>
+#include <framebuffer_messages.h>
+#include <wm_messages.h>
+
+// === TYPES ===
+typedef struct
+{
+ short W, H;
+ void *Data;
+ char _data[];
+} tFBBuffer;
+typedef struct
+{
+ tFBBuffer BackBuffer;
+ int MaxBufferCount;
+ tFBBuffer *Buffers[];
+} tFBWin;
// === PROTOTYPES ===
-tWindow *Renderer_Passthru_Create(int Flags);
-void Renderer_Passthru_Redraw(tWindow *Window);
- int Renderer_Passthru_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
+tWindow *Renderer_Framebuffer_Create(int Flags);
+void Renderer_Framebuffer_Redraw(tWindow *Window);
+ int Renderer_Framebuffer_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data);
// === GLOBALS ===
-tWMRenderer gRenderer_Passthru = {
- .Name = "Passthru",
- .CreateWindow = Renderer_Passthru_Create,
- .Redraw = Renderer_Passthru_Redraw,
- .HandleMessage = Renderer_Passthru_HandleMessage
+tWMRenderer gRenderer_Framebuffer = {
+ .Name = "FrameBuffer",
+ .CreateWindow = Renderer_Framebuffer_Create,
+ .Redraw = Renderer_Framebuffer_Redraw,
+ .HandleMessage = Renderer_Framebuffer_HandleMessage
};
// === CODE ===
-int Renderer_Passthru_Init(void)
+int Renderer_Framebuffer_Init(void)
{
+ WM_RegisterRenderer(&gRenderer_Framebuffer);
return 0;
}
-tWindow *Renderer_Passthru_Create(int Flags)
+tWindow *Renderer_Framebuffer_Create(int Flags)
+{
+ tWindow *ret;
+ tFBWin *info;
+ const int max_buffers = 10; // TODO: Have this be configurable
+
+ ret = WM_CreateWindowStruct( sizeof(*info) + max_buffers*sizeof(tFBBuffer*) );
+ info = ret->RendererInfo;
+
+ info->BackBuffer.W = 0;
+ info->BackBuffer.H = 0;
+ info->BackBuffer.Data = NULL;
+ info->MaxBufferCount = max_buffers;
+ memset( info->Buffers, 0, sizeof(tFBBuffer*) * max_buffers );
+
+ return ret;
+}
+
+void Renderer_Framebuffer_Redraw(tWindow *Window)
+{
+
+}
+
+// --- ---
+tFBBuffer *_GetBuffer(tWindow *Win, uint16_t ID)
+{
+ tFBWin *info = Win->RendererInfo;
+ if( ID == 0xFFFF )
+ return &info->BackBuffer;
+ else if( ID >= info->MaxBufferCount )
+ return NULL;
+ else
+ return info->Buffers[ ID ];
+}
+
+void _Blit(
+ tFBBuffer *Dest, uint16_t DX, uint16_t DY,
+ const tFBBuffer *Src, uint16_t SX, uint16_t SY,
+ uint16_t W, uint16_t H
+ )
+{
+ uint32_t *dest_data = Dest->Data;
+ const uint32_t *src_data = Src->Data;
+ // First, some sanity
+ if( DX > Dest->W ) return ;
+ if( DY > Dest->H ) return ;
+ if( SX > Src->W ) return ;
+ if( SY > Src->H ) return ;
+
+ if( DX + W > Dest->W ) W = Dest->W - DX;
+ if( SX + W > Src->W ) W = Src->W - SX;
+ if( DY + H > Dest->H ) H = Dest->H - DY;
+ if( SY + H > Src->H ) H = Src->H - SY;
+
+ dest_data += (DY * Dest->W) + DX;
+ src_data += (SY * Src->W ) + SX;
+ for( int i = 0; i < H; i ++ )
+ {
+ memcpy( dest_data, src_data, W * 4 );
+ dest_data += Dest->W;
+ src_data += Src->W;
+ }
+}
+
+void _Fill(tFBBuffer *Buf, uint16_t X, uint16_t Y, uint16_t W, uint16_t H, uint32_t Colour)
+{
+ uint32_t *data = Buf->Data;
+
+ if( X > Buf->W ) return ;
+ if( Y > Buf->H ) return ;
+ if( X + W > Buf->W ) W = Buf->W - X;
+ if( Y + H > Buf->H ) H = Buf->H - Y;
+
+ data += (Y * Buf->W) + X;
+ for( int i = 0; i < H; i ++ )
+ {
+ for( int j = 0; j < W; j ++ )
+ *data++ = Colour;
+ data += Buf->W - W;
+ }
+}
+
+// --- ---
+void _Handle_Commit(tWindow *Target, size_t Len, const void *Data)
+{
+ // Do a window invalidate
+}
+
+void _Handle_CreateBuf(tWindow *Target, size_t Len, const void *Data)
{
- return NULL;
+ const tFBMsg_NewBuf *msg = Data;
+ tFBBuffer *buf;
+ tFBWin *info = Target->RendererInfo;
+
+ if( Len < sizeof(*msg) ) return ;
+
+ if( msg->Buffer == -1 || msg->Buffer >= info->MaxBufferCount ) {
+ // Can't reallocate -1
+ return ;
+ }
+
+ if( info->Buffers[msg->Buffer] ) {
+ free(info->Buffers[msg->Buffer]);
+ info->Buffers[msg->Buffer] = NULL;
+ }
+
+ buf = malloc(sizeof(tFBBuffer) + msg->W * msg->H * 4);
+ buf->W = msg->W;
+ buf->H = msg->H;
+ buf->Data = buf->_data;
+
+ info->Buffers[msg->Buffer] = buf;
}
-void Renderer_Passthru_Redraw(tWindow *Window)
+void _Handle_Upload(tWindow *Target, size_t Len, const void *Data)
{
+ const tFBMsg_Transfer *msg = Data;
+ tFBBuffer *dest, src;
+
+ if( Len < sizeof(*msg) ) return ;
+ if( Len < sizeof(*msg) + msg->W * msg->H * 4 ) return ;
+
+ dest = _GetBuffer(Target, msg->Buffer);
+
+ src.W = msg->W;
+ src.H = msg->H;
+ src.Data = (void*)msg->ImageData;
+
+ _Blit( dest, msg->X, msg->Y, &src, 0, 0, msg->W, msg->H );
+}
+
+void _Handle_Download(tWindow *Target, size_t Len, const void *Data)
+{
+ #if 0
+ const tFBMsg_Transfer *msg = Data;
+ tFBBuffer dest, *src;
+
+ if( Len < sizeof(*msg) ) return ;
+ if( Len < sizeof(*msg) + msg->W * msg->H * 4 ) return ;
+
+ src = _GetBuffer(Target, msg->Buffer);
+
+ dest.W = msg->W;
+ dest.H = msg->H;
+ dest.Data = msg->ImageData;
+ _Blit( &dest, 0, 0, src, msg->X, msg->Y, msg->W, msg->H );
+ #endif
}
-int Renderer_Passthru_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
+void _Handle_LocalBlit(tWindow *Target, size_t Len, const void *Data)
{
+ const tFBMsg_Blit *msg = Data;
+ tFBBuffer *dest, *src;
+
+ if( Len < sizeof(*msg) ) return ;
+
+ src = _GetBuffer(Target, msg->Source);
+ dest = _GetBuffer(Target, msg->Dest);
+
+ _Blit( dest, msg->DstX, msg->DstY, src, msg->SrcX, msg->SrcY, msg->W, msg->H );
+}
+
+void _Handle_FillRect(tWindow *Target, size_t Len, const void *Data)
+{
+ const tFBMsg_Fill *msg = Data;
+ tFBBuffer *dest;
+
+ if( Len < sizeof(*msg) ) return ;
+
+ dest = _GetBuffer(Target, msg->Buffer);
+
+ _Fill( dest, msg->X, msg->Y, msg->W, msg->H, msg->Colour );
+}
+
+int Renderer_Framebuffer_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
+{
+ switch(Msg)
+ {
+ case WNDMSG_RESIZE:
+ // Resize the framebuffer
+ return 1; // Pass on
+
+ // Messages that get passed on
+ case WNDMSG_MOUSEBTN:
+ return 1;
+
+ // --- Local messages ---
+ // - Drawing completed, do an update
+ case MSG_FB_COMMIT:
+ _Handle_Commit(Target, Len, Data);
+ return 0;
+ // - New Buffer (create a new server-side buffer)
+ case MSG_FB_NEWBUF:
+ _Handle_CreateBuf(Target, Len, Data);
+ return 0;
+ // - Upload (Transfer data from client to server)
+ case MSG_FB_UPLOAD:
+ _Handle_Upload(Target, Len, Data);
+ return 0;
+ // - Download (Transfer image data from server to client)
+ case MSG_FB_DOWNLOAD:
+ _Handle_Download(Target, Len, Data);
+ return 0;
+ // - Local Blit (Transfer from server to server)
+ case MSG_FB_BLIT:
+ _Handle_LocalBlit(Target, Len, Data);
+ return 0;
+ // - Fill a rectangle
+ case MSG_FB_FILL:
+ _Handle_FillRect(Target, Len, Data);
+ return 0;
+ }
return 1;
}
// }
}
+int Widget_GetText(tWidgetWin *Info, int Len, const tWidgetMsg_SetText *Msg)
+{
+ if( Len < sizeof(*Msg) )
+ return 0;
+ if( Len > sizeof(*Msg) )
+ return 1; // Pass to user
+
+ const char *text = NULL;
+ tElement *ele = Widget_GetElementById(Info, Msg->WidgetID);
+ if(ele)
+ text = ele->Text;
+
+ char buf[sizeof(tWidgetMsg_SetText) + strlen(text?text:"") + 1];
+ tWidgetMsg_SetText *omsg = (void*)buf;
+
+ if( text ) {
+ omsg->WidgetID = Msg->WidgetID;
+ strcpy(omsg->Text, text);
+ }
+ else {
+ omsg->WidgetID = -1;
+ omsg->Text[0] = 0;
+ }
+
+ WM_SendMessage(Info->RootElement.Window, Info->RootElement.Window, MSG_WIDGET_GETTEXT, sizeof(buf), buf);
+ return 0;
+}
+
int Renderer_Widget_HandleMessage(tWindow *Target, int Msg, int Len, const void *Data)
{
tWidgetWin *info = Target->RendererInfo;
case MSG_WIDGET_SETTEXT:
Widget_SetText(info, Len, Data);
return 0;
+ case MSG_WIDGET_GETTEXT:
+ return Widget_GetText(info, Len, Data);
//
default:
#include <wm.h>
#include <string.h>
+// === IMPORTS ===
+extern int giTerminalFD_Input;
+
// === PROTOTYPES ===
void Video_Setup(void);
void Video_SetCursorPos(short X, short Y);
int tmpInt;
// Open terminal
+ #if 0
giTerminalFD = open(gsTerminalDevice, OPENFLAG_READ|OPENFLAG_WRITE);
if( giTerminalFD == -1 )
{
fprintf(stderr, "ERROR: Unable to open '%s' (%i)\n", gsTerminalDevice, _errno);
exit(-1);
}
-
+ #else
+ giTerminalFD = 1;
+ giTerminalFD_Input = 0;
+ // Check that the console is a VT
+ // - ioctl(..., 0, NULL) returns the type, which should be 2
+ if( ioctl(1, 0, NULL) != 2 )
+ {
+ fprintf(stderr, "stdout is not an Acess VT, can't start");
+ _SysDebug("stdout is not an Acess VT, can't start");
+ exit(-1);
+ }
+ #endif
// Set mode to video
tmpInt = TERM_MODE_FB;
_SysDebug("Video_Update - Updating lines %i to %i (0x%x+0x%x px)",
giVideo_FirstDirtyLine, giVideo_LastDirtyLine, ofs, size);
seek(giTerminalFD, ofs*4, 1);
+ _SysDebug("Video_Update - Sending");
write(giTerminalFD, gpScreenBuffer+ofs, size*4);
_SysDebug("Video_Update - Done");
giVideo_FirstDirtyLine = 0;
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * wm_hotkeys.c
+ * - Hotkey and key shortcut code
+ */
+#include <common.h>
+#include <wm_internals.h>
+#include <wm_messages.h>
+#include <wm_hotkeys.h>
+#include <string.h>
+
+#define true 1
+#define false 0
+
+#define MAX_STATE_SCANCODE 256
+
+// === GOBALS ===
+char gbWM_HasBeenKeyDown = true;
+uint8_t gWM_KeyStates[MAX_STATE_SCANCODE/8];
+tHotkey *gpWM_Hotkeys;
+tHotkeyTarget *gpWM_HotkeyTargets;
+tHotkeyTarget *gpWM_HotkeyTargets_Last;
+
+// === PROTOTYPES ===
+static void _SetKey(uint32_t sc);
+static void _UnsetKey(uint32_t sc);
+static int _IsKeySet(uint32_t sc);
+void WM_Hotkey_FireEvent(const char *Target);
+
+// === CODE ===
+void WM_Hotkey_Register(int nKeys, uint32_t *Keys, const char *ActionName)
+{
+ // TODO: Duplicate detection
+
+ // Create new structure
+ tHotkey *h = malloc(sizeof(tHotkey) + nKeys * sizeof(uint32_t) + strlen(ActionName) + 1);
+ h->nKeys = nKeys;
+ h->Target = (void*)( h->Keys + nKeys );
+ strcpy((char*)h->Target, ActionName);
+ memcpy(h->Keys, Keys, nKeys * sizeof(uint32_t));
+
+ h->Next = NULL;
+ if( gpWM_Hotkeys )
+ gpWM_Hotkeys->Next = h;
+ gpWM_Hotkeys = h;
+}
+
+void WM_Hotkey_RegisterAction(const char *ActionName, tWindow *Target, uint16_t Index)
+{
+ // Check for a duplicate registration
+ for( tHotkeyTarget *t = gpWM_HotkeyTargets; t; t = t->Next )
+ {
+ if( strcmp(t->Name, ActionName) != 0 )
+ continue ;
+ // Duplicate!
+ return ;
+ }
+
+ // Create new structure
+ tHotkeyTarget *t = malloc(sizeof(tHotkeyTarget) + strlen(ActionName) + 1);
+ t->Name = (void*)(t + 1);
+ strcpy((char*)t->Name, ActionName);
+ t->Window = Target;
+ t->Index = Index;
+
+ // TODO: Register to be informed when the window dies/closes?
+
+ // Append to list
+ if( gpWM_HotkeyTargets ) {
+ gpWM_HotkeyTargets_Last->Next = t;
+ }
+ else {
+ gpWM_HotkeyTargets = t;
+ }
+ gpWM_HotkeyTargets_Last = t;
+}
+
+void WM_Hotkey_KeyDown(uint32_t Scancode)
+{
+ _SetKey(Scancode);
+ gbWM_HasBeenKeyDown = true;
+}
+
+void WM_Hotkey_KeyUp(uint32_t Scancode)
+{
+ _UnsetKey(Scancode);
+
+ // Ensure that hotkeys are triggered on the longest sequence
+ // (so Win-Shift-R doesn't trigger Win-R if shift is released)
+ if( !gbWM_HasBeenKeyDown )
+ return ;
+
+ for( tHotkey *hk = gpWM_Hotkeys; hk; hk = hk->Next )
+ {
+ int i;
+ for( i = 0; i < hk->nKeys; i ++ )
+ {
+ if( hk->Keys[i] == Scancode ) continue ;
+ if( _IsKeySet(hk->Keys[i]) ) continue ;
+ break;
+ }
+ _SysDebug("%i/%i satisfied for %s", i, hk->nKeys, hk->Target);
+ if( i != hk->nKeys )
+ continue ;
+
+ // Fire shortcut
+ WM_Hotkey_FireEvent(hk->Target);
+
+ break;
+ }
+
+ gbWM_HasBeenKeyDown = false;
+}
+
+void WM_Hotkey_FireEvent(const char *Target)
+{
+// _SysDebug("WM_Hotkey_FireEvent: (%s)", Target);
+ // - Internal events (Alt-Tab, Close, Maximize, etc...)
+ // TODO: Internal event handling
+
+ // - Application registered events
+ for( tHotkeyTarget *t = gpWM_HotkeyTargets, *prev=NULL; t; t = t->Next )
+ {
+ if( strcmp(t->Name, Target) != 0 )
+ continue ;
+
+ struct sWndMsg_Hotkey info = {.ID=t->Index};
+ WM_SendMessage(NULL, t->Window, WNDMSG_HOTKEY, sizeof(info), &info);
+
+ // Sort the list by most-recently-used
+ if(prev != NULL) {
+ prev->Next = t->Next;
+ t->Next = gpWM_HotkeyTargets;
+ gpWM_HotkeyTargets = t;
+ }
+
+ return ;
+ }
+}
+
+static void _SetKey(uint32_t sc)
+{
+// _SysDebug("_SetKey: (%x)", sc);
+ if( sc >= MAX_STATE_SCANCODE ) return;
+ gWM_KeyStates[sc/8] |= 1 << (sc % 8);
+}
+static void _UnsetKey(uint32_t sc)
+{
+// _SysDebug("_UnsetKey: (%x)", sc);
+ if( sc >= MAX_STATE_SCANCODE ) return;
+ gWM_KeyStates[sc/8] &= ~(1 << (sc % 8));
+}
+static int _IsKeySet(uint32_t sc)
+{
+ if( sc >= MAX_STATE_SCANCODE ) return 0;
+
+ return !!(gWM_KeyStates[sc/8] & (1 << (sc % 8)));
+}
+
#include <common.h>
#include <wm_internals.h>
#include <wm_messages.h>
+#include <wm_hotkeys.h>
#define MAX_BUTTONS 3
for(win = ret->FirstChild; win; win = win->NextSibling)
{
if( !(win->Flags & WINFLAG_SHOW) ) continue ;
- if( X < win->X || X >= win->X + win->W ) continue;
- if( Y < win->Y || Y >= win->Y + win->H ) continue;
+ if( X < win->X || X >= win->X + win->RealW ) continue;
+ if( Y < win->Y || Y >= win->Y + win->RealH ) continue;
next_win = win; // Overwrite as we want the final rendered window
}
}
WM_SendMessage(NULL, win, WNDMSG_MOUSEMOVE, sizeof(msg), &msg);
}
-inline void WM_Input_int_SendBtnMsg(tWindow *Win, int X, int Y, int Index, int Pressed)
+void WM_Input_int_SendBtnMsg(tWindow *Win, int X, int Y, int Index, int Pressed)
{
struct sWndMsg_MouseButton msg;
void WM_Input_KeyDown(uint32_t Character, uint32_t Scancode)
{
struct sWndMsg_KeyAction msg;
+
+ WM_Hotkey_KeyDown(Scancode);
+
msg.KeySym = Scancode;
msg.UCS32 = Character;
WM_SendMessage(NULL, gpWM_FocusedWindow, WNDMSG_KEYDOWN, sizeof(msg), &msg);
void WM_Input_KeyUp(uint32_t Character, uint32_t Scancode)
{
struct sWndMsg_KeyAction msg;
+
+ WM_Hotkey_KeyUp(Scancode);
+
msg.KeySym = Scancode;
msg.UCS32 = Character;
WM_SendMessage(NULL, gpWM_FocusedWindow, WNDMSG_KEYUP, sizeof(msg), &msg);
--- /dev/null
+/*
+ * Acess2 Window Manager v3
+ * - By John Hodge (thePowersGang)
+ *
+ * framebuffer_messages.h
+ * - Drawing Surface / Framebuffer Window Type
+ */
+#ifndef _AXWIN3__FRAMEBUFFER_MESSAGES_H_
+#define _AXWIN3__FRAMEBUFFER_MESSAGES_H_
+
+enum
+{
+ MSG_FB_COMMIT = 0x1000,
+ MSG_FB_NEWBUF,
+ MSG_FB_UPLOAD,
+ MSG_FB_DOWNLOAD,
+ MSG_FB_BLIT,
+ MSG_FB_FILL
+};
+
+typedef struct
+{
+ uint16_t Buffer;
+ uint16_t W, H;
+} tFBMsg_NewBuf;
+
+typedef struct
+{
+ uint16_t Buffer;
+ uint16_t W, H;
+ uint16_t X, Y;
+ uint32_t ImageData[];
+} tFBMsg_Transfer;
+
+typedef struct
+{
+ uint16_t Source;
+ uint16_t Dest;
+ uint16_t SrcX, SrcY;
+ uint16_t DstX, DstY;
+ uint16_t W, H;
+} tFBMsg_Blit;
+
+typedef struct
+{
+ uint16_t Buffer;
+ uint16_t X, Y;
+ uint16_t W, H;
+ uint32_t Colour;
+} tFBMsg_Fill;
+
+#endif
+
typedef struct sIPCMsg_Boolean tIPCMsg_Boolean;
typedef struct sIPCMsg_SetWindowPos tIPCMsg_SetWindowPos;
typedef struct sIPCMsg_SendMsg tIPCMsg_SendMsg;
+typedef struct sIPCMsg_RegAction tIPCMsg_RegAction;
typedef struct sIPCMsg_GetDisplayDims tIPCMsg_GetDisplayDims;
typedef struct sIPCMsg_RetDisplayDims tIPCMsg_RetDisplayDims;
uint8_t bSetDims;
};
+struct sIPCMsg_RegAction
+{
+ uint16_t Index;
+ char Action[];
+};
+
struct sIPCMsg_GetDisplayDims
{
uint16_t DisplayID;
IPCMSG_DECORATEWINDOW, //!< Enable/Disable decorations
IPCMSG_FOCUSWINDOW, //!< Give a window focus (no data)
IPCMSG_SETWINPOS, //!< Set a window position
+ IPCMSG_REGACTION //!< Register an action name
};
#endif
--- /dev/null
+/*
+ * Acess2 Window Manager v3 (axwin3)
+ * - By John Hodge (thePowersGang)
+ *
+ * include/wm_messages.h
+ * - Core window messages
+ */
+#ifndef _WM_MESSAGES_H_
+#define _WM_MESSAGES_H_
+
+/**
+ * \brief Messages delivered to windows
+ */
+enum eWM_WindowMessages
+{
+ WNDMSG_NULL,
+
+ WNDMSG_CREATE,
+ WNDMSG_DESTROY,
+ WNDMSG_FOCUS, // Called on change
+ WNDMSG_SHOW, // Called on change
+
+ WNDMSG_RESIZE,
+
+ WNDMSG_MOUSEMOVE,
+ WNDMSG_MOUSEBTN,
+ WNDMSG_KEYDOWN,
+ WNDMSG_KEYFIRE,
+ WNDMSG_KEYUP,
+
+ WNDMSG_HOTKEY,
+
+ WNDMSG_CLASS_MIN = 0x1000,
+ WNDMSG_CLASS_MAX = 0x2000,
+};
+
+struct sWndMsg_Bool
+{
+ uint8_t Val;
+};
+
+struct sWndMsg_Resize
+{
+ uint16_t W, H;
+};
+
+struct sWndMsg_MouseMove
+{
+ int16_t X, Y;
+ int16_t dX, dY;
+};
+
+struct sWndMsg_MouseButton
+{
+ int16_t X, Y;
+ uint8_t Button;
+ uint8_t bPressed;
+};
+
+struct sWndMsg_KeyAction
+{
+ uint32_t KeySym;
+ uint32_t UCS32;
+};
+
+struct sWndMsg_Hotkey
+{
+ uint16_t ID;
+};
+
+#endif
// === CONSTANTS ===
enum eConnectionType
{
+ CONNTYPE_NONE,
CONNTYPE_SENDMESSAGE,
CONNTYPE_UDP,
CONNTYPE_TCP
switch(giConnectionType)
{
case CONNTYPE_SENDMESSAGE:
- _SysWaitEvent(THREAD_EVENT_IPCMSG);
- while(SysGetMessage(NULL, NULL))
+ for( ;; )
{
pid_t tid;
- len = SysGetMessage(&tid, NULL);
+
+ // Wait for a message to arrive
+ while( !(len = SysGetMessage(&tid, NULL)) )
+ {
+ _SysWaitEvent(THREAD_EVENT_IPCMSG);
+ }
+
// Check if the message came from the server
if(tid != giConnectionNum)
{
#include <axwin3/axwin.h>
#include <axwin3/widget.h>
#include "include/internal.h"
-#include "include/ipc.h"
#include <stdlib.h>
#include <widget_messages.h>
#include <string.h>
{
char buf[sizeof(tWidgetMsg_SetText)];
tWidgetMsg_SetText *msg = (void*)buf;
- tAxWin_IPCMessage *retmsg;
- char *ret;
+ size_t retmsg_size;
msg->WidgetID = Widget->ID;
AxWin3_SendMessage(Widget->Window, Widget->Window, MSG_WIDGET_GETTEXT, sizeof(buf), buf);
- retmsg = AxWin3_int_WaitIPCMessage(MSG_WIDGET_GETTEXT);
- msg = (void*)retmsg->Data;
-
- if( retmsg->Size < sizeof(*msg) ) {
- free(retmsg);
+ msg = AxWin3_WaitMessage(Widget->Window, MSG_WIDGET_GETTEXT, &retmsg_size);
+ if( retmsg_size < sizeof(*msg) ) {
+ free(msg);
return NULL;
}
- ret = strndup(msg->Text, retmsg->Size - sizeof(*msg));
- free(retmsg);
+ char *ret = strndup(msg->Text, retmsg_size - sizeof(*msg));
+ free(msg);
return ret;
}
#include <string.h>
#include "include/internal.h"
#include "include/ipc.h"
+#include <wm_messages.h>
-#define WINDOWS_PER_ALLOC (63)
+#define WINDOWS_PER_ALLOC (64-1) // -1 to make it 64 pointers (+ Next)
+#define MAX_HOTKEYS 32
typedef struct sWindowBlock tWindowBlock;
int giAxWin3_LowestFreeWinID;
int giAxWin3_HighestUsedWinID;
tWindowBlock gAxWin3_WindowList;
+tAxWin3_HotkeyCallback gAxWin3_Hotkeys[MAX_HOTKEYS];
// === CODE ===
tWindow *AxWin3_int_CreateWindowStruct(uint32_t ServerID, int ExtraBytes)
{
case IPCMSG_SENDMSG: {
tIPCMsg_SendMsg *info = (void*)Msg->Data;
- if(Msg->Size < sizeof(*info)) return ;
- if(Msg->Size < sizeof(*info) + info->Length) return ;
- if(!dest || !dest->Handler) return ;
- dest->Handler(dest, info->ID, info->Length, info->Data);
+ if(Msg->Size < sizeof(*info) || Msg->Size < sizeof(*info) + info->Length) {
+ _SysDebug("Message is undersized (%i < %i + %i)",
+ Msg->Size < sizeof(*info), info->Length);
+ return ;
+ }
+ if(!dest || !dest->Handler) {
+ _SysDebug("No handler for destination %p", dest);
+ return ;
+ }
+ _SysDebug("IPC Message 0x%x - %i bytes", info->ID, info->Length);
+
+ if( dest->Handler(dest, info->ID, info->Length, info->Data) )
+ ;
+ else {
+ switch( info->ID )
+ {
+ case WNDMSG_HOTKEY: {
+ const struct sWndMsg_Hotkey *mi = (void*)info->Data;
+ if( mi->ID >= MAX_HOTKEYS )
+ ; // TODO: Error when hotkey is out of range
+ else if( gAxWin3_Hotkeys[mi->ID] == 0 )
+ _SysDebug("--- Unmapped hotkey ID %i fired", mi->ID);
+ else
+ gAxWin3_Hotkeys[mi->ID]();
+ }break;
+ default:
+ _SysDebug("--- Unhandled SENDMSG %i", info->ID);
+ break;
+ }
+ }
break; }
+ default:
+ _SysDebug("Unknow message ID %i", Msg->ID);
+ break;
}
}
free(msg);
}
+void *AxWin3_WaitMessage(tHWND Window, int MessageID, size_t *Length)
+{
+ tAxWin_IPCMessage *msg;
+
+ for( ;; )
+ {
+ msg = AxWin3_int_WaitIPCMessage(IPCMSG_SENDMSG);
+ if( msg->Window != AxWin3_int_GetWindowID(Window) ) {
+ AxWin3_int_HandleMessage(msg);
+ continue ;
+ }
+ tIPCMsg_SendMsg *info = (void*)msg->Data;
+ if( info->ID != MessageID ) {
+ AxWin3_int_HandleMessage(msg);
+ continue ;
+ }
+
+ *Length = info->Length;
+ void *ret = malloc(info->Length);
+ memcpy(ret, info->Data, info->Length);
+ free(msg);
+
+ return ret;
+ }
+}
+
void AxWin3_FocusWindow(tHWND Window)
{
tAxWin_IPCMessage *msg;
free(msg);
}
+int AxWin3_RegisterAction(tHWND Window, const char *Action, tAxWin3_HotkeyCallback cb)
+{
+ int i;
+ for( i = 0; i < MAX_HOTKEYS; i ++ )
+ {
+ if( gAxWin3_Hotkeys[i] == NULL )
+ {
+ tAxWin_IPCMessage *msg;
+ struct sIPCMsg_RegAction *info;
+ gAxWin3_Hotkeys[i] = cb;
+
+ msg = AxWin3_int_AllocateIPCMessage(Window, IPCMSG_REGACTION, 0, sizeof(*info)+strlen(Action)+1);
+ info = (void*)msg->Data;
+
+ info->Index = i;
+ strcpy(info->Action, Action);
+
+ AxWin3_int_SendIPCMessage(msg);
+ free(msg);
+ return i;
+ }
+ }
+ return -1;
+}
+
{
int fd;
int num;
- char buf[BUF_SIZE+1];
+ char buf[BUF_SIZE];
if(argc < 2) {
printf("Usage: cat <file>\n");
do {
num = read(fd, buf, BUF_SIZE);
if(num < 0) break;
- buf[num] = '\0';
- printf("%s", buf);
+ write(1, buf, num);
} while(num == BUF_SIZE);
close(fd);
/*
+ *
+ * http://www.ietf.org/rfc/rfc2131.txt
*/
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include <net.h>
#define FILENAME_MAX 255
int Num;
int SocketFD;
int IfaceFD;
+
+ uint32_t TransactionID;
+ char HWAddr[6];
+
+ int64_t Timeout;
} tInterface;
// === PROTOTYPES ===
void Send_DHCPDISCOVER(tInterface *Iface);
void Send_DHCPREQUEST(tInterface *Iface, void *OfferBuffer, int TypeOffset);
int Handle_Packet(tInterface *Iface);
+void Handle_Timeout(tInterface *Iface);
+void Update_State(tInterface *Iface, int newState);
void SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router);
// === CODE ===
for( i = ifaces; i; i = i->Next )
{
- i->State = STATE_PREINIT;
if( Start_Interface(i) < 0 ) {
return -1;
}
+ i->State = STATE_PREINIT;
// Send request
Send_DHCPDISCOVER(i);
int maxfd;
fd_set fds;
tInterface *p;
+ int64_t timeout = 1000;
maxfd = 0;
FD_ZERO(&fds);
FD_SET(i->SocketFD, &fds);
if(maxfd < i->SocketFD) maxfd = i->SocketFD;
}
- if( select(maxfd+1, &fds, NULL, NULL, NULL) < 0 )
+
+ if( select(maxfd+1, &fds, NULL, NULL, &timeout) < 0 )
{
// TODO: Check error result
return -1;
}
+ _SysDebug("select() returned");
+
// Check for changes (with magic to allow inline deletion)
for( p = (void*)&ifaces, i = ifaces; i; p=i,i = i->Next )
{
i = p;
}
}
+
+ if( _SysTimestamp() > i->Timeout )
+ {
+ Handle_Timeout(i);
+ }
}
}
return 0;
int dp = open(Directory, OPENFLAG_READ);
char filename[FILENAME_MAX];
- while( readdir(dp, filename) )
+ if( dp == -1 ) {
+ fprintf(stderr, "Unable to open directory '%s'\n", Directory);
+ }
+
+ while( SysReadDir(dp, filename) )
{
if( filename[0] == '.' ) continue ;
if( strcmp(filename, "lo") == 0 ) continue ;
// TODO: Check that the adapter is not in use
+ // Request MAC address from network adapter
+ {
+ char path[] = "/Devices/ip/adapters/ethXXXX";
+ sprintf(path, "/Devices/ip/adapters/%s", Iface->Adapter);
+ fd = open(path, 0);
+ if(fd == -1) {
+ _SysDebug("Unable to open adapter %s", path);
+ return -1;
+ }
+ ioctl(fd, 4, Iface->HWAddr);
+ // TODO: Check if ioctl() failed
+ close(fd);
+ }
+
// Initialise an interface, with a dummy IP address (zero)
fd = open("/Devices/ip", 0);
if( fd == -1 ) {
}
tmp = 68; ioctl(fd, 4, &tmp); // Local port
tmp = 67; ioctl(fd, 5, &tmp); // Remote port
- tmp = 0; ioctl(fd, 7, &tmp); // Remote addr mask - we don't care where the reply comes from
+ tmp = 0; ioctl(fd, 7, &tmp); // Remote addr mask bits - we don't care where the reply comes from
addr[0] = addr[1] = addr[2] = addr[3] = 255; // 255.255.255.255
ioctl(fd, 8, addr); // Remote address
- return fd;
+ return 0;
+}
+
+void Send_DHCPRELEASE(tInterface *Iface)
+{
}
void Send_DHCPDISCOVER(tInterface *Iface)
char data[8 + sizeof(struct sDHCP_Message) + 3 + 1];
msg = (void*)data + 8;
+ _SysDebug("DHCPDISCOVER to %s", Iface->Adapter);
+
transaction_id = rand();
+ Iface->TransactionID = transaction_id;
msg->op = htonb(1); // BOOTREQUEST
msg->htype = htonb(1); // 10mb Ethernet
msg->hops = htonb(0); // Hop count so far
msg->xid = htonl(transaction_id); // Transaction ID
msg->secs = htons(0); // secs - No time has elapsed
- msg->flags = htons(0); // flags - TODO: Check if broadcast bit need be set
+ msg->flags = htons(0x0000); // flags - Broadcast is unset
msg->ciaddr = htonl(0); // ciaddr - Zero, as we don't have one yet
msg->yiaddr = htonl(0); // yiaddr - Zero?
msg->siaddr = htonl(0); // siaddr - Zero? maybe -1
msg->giaddr = htonl(0); // giaddr - Zero?
- // Request MAC address from network adapter
- {
- char path[] = "/Devices/ip/adapters/ethXXXX";
- sprintf(path, "/Devices/ip/adapters/%s", Iface->Adapter);
- int fd = open(path, 0);
- if(fd == -1) {
- _SysDebug("Unable to open adapter %s", path);
- }
- else {
- ioctl(fd, 4, msg->chaddr);
- // TODO: Check if ioctl() failed
- close(fd);
- }
- }
+ memcpy(msg->chaddr, Iface->HWAddr, 6);
+
memset(msg->sname, 0, sizeof(msg->sname)); // Nuke the rest
memset(msg->file, 0, sizeof(msg->file)); // Nuke the rest
msg->dhcp_magic = htonl(DHCP_MAGIC);
data[4] = 255; data[5] = 255; data[6] = 255; data[7] = 255;
write(Iface->SocketFD, data, sizeof(data));
- Iface->State = STATE_DISCOVER_SENT;
+ Update_State(Iface, STATE_DISCOVER_SENT);
}
void Send_DHCPREQUEST(tInterface *Iface, void *OfferPacket, int TypeOffset)
{
struct sDHCP_Message *msg;
+ int i;
msg = (void*) ((char*)OfferPacket) + 8;
// Reuses old data :)
- msg->op = 1;
- msg->options[TypeOffset+2] = 3; // DHCPREQUEST
- msg->options[TypeOffset+3] = 255;
+ msg->op = 1;
+ msg->htype = 1;
+ msg->hlen = 6;
+ msg->hops = 0;
+ msg->xid = msg->xid;
+ msg->secs = htons(0); // TODO: Maintain times
+ msg->flags = htons(0);
+ memcpy(msg->chaddr, Iface->HWAddr, 6);
+ memset(msg->sname, 0, sizeof(msg->sname)); // Nuke the rest
+ memset(msg->file, 0, sizeof(msg->file)); // Nuke the rest
+
+ i = 0;
+ msg->options[i++] = 53; // Message type = DHCPREQUEST
+ msg->options[i++] = 1;
+ msg->options[i++] = 3;
+ msg->options[i++] = 50; // Requested Address
+ msg->options[i++] = 4;
+ memcpy(msg->options + i, &msg->yiaddr, 4); i += 4;
+// msg->options[i++] = 54; // Server identifier
+// msg->options[i++] = 4;
+// memcpy(msg->options + i, (char*)OfferPacket + 4, 4); i += 4;
+ msg->options[i++] = 255;
- write(Iface->SocketFD, OfferPacket, 8 + sizeof(*msg) + TypeOffset + 4);
- Iface->State = STATE_REQUEST_SENT;
+ // Clear last because yiaddr is needed in option setup
+ msg->ciaddr = htonl(0);
+ msg->yiaddr = htonl(0);
+ msg->siaddr = htonl(0);
+ msg->giaddr = htonl(0);
+
+ // HACK
+ ((uint8_t*)OfferPacket)[4] = 255;
+ ((uint8_t*)OfferPacket)[5] = 255;
+ ((uint8_t*)OfferPacket)[6] = 255;
+ ((uint8_t*)OfferPacket)[7] = 255;
+
+ write(Iface->SocketFD, OfferPacket, 8 + sizeof(*msg) + i);
+ Update_State(Iface, STATE_REQUEST_SENT);
}
int Handle_Packet(tInterface *Iface)
return 0;
}
+
+ // Check if the packet is related to our requests
+ if( ntohl(msg->xid) != Iface->TransactionID ) {
+ _SysDebug("Transaction ID mis-match, ignoring (0x%x != 0x%x)",
+ ntohl(msg->xid), Iface->TransactionID);
+ return 0;
+ }
+ if( memcmp(msg->chaddr, Iface->HWAddr, 6) != 0 ) {
+ _SysDebug("Hardware address mis-match, ignoring");
+ return 0;
+ }
+
+ // Parse options
i = 0;
while( i < len - sizeof(*msg) - 8 && msg->options[i] != 255 )
{
case 4: // DHCPDECLINE - ?
break;
case 5: // DHCPACK
- // TODO: Apply address
SetAddress(Iface, &msg->yiaddr, subnet_mask, router);
+ // Return 1 to remove from list
return 1;
}
return 0;
}
+void Handle_Timeout(tInterface *Iface)
+{
+ switch(Iface->State)
+ {
+ case STATE_DISCOVER_SENT:
+ Send_DHCPDISCOVER(Iface);
+ break;
+ default:
+ _SysDebug("Timeout with state = %i", Iface->State);
+ break;
+ }
+}
+
+void Update_State(tInterface *Iface, int newState)
+{
+ if( Iface->State != newState )
+ {
+ Iface->Timeout = _SysTimestamp() + 500;
+ Iface->State = newState;
+ }
+ else
+ {
+ // TODO: Exponential backoff
+ Iface->Timeout = _SysTimestamp() + 3000;
+ _SysDebug("State %i repeated, timeout is 3000ms now", newState);
+ }
+}
+
void SetAddress(tInterface *Iface, void *Addr, void *Mask, void *Router)
{
int mask_bits = 0;
dp = open(IPSTACK_ROOT, OPENFLAG_READ);
- while( readdir(dp, filename) )
+ while( SysReadDir(dp, filename) )
{
if(filename[0] == '.') continue;
DumpInterface(filename);
printf("Type\tNetwork \tGateway \tMetric\tIFace\n");
- while( readdir(dp, filename) )
+ while( SysReadDir(dp, filename) )
{
if(filename[0] == '.') continue;
DumpRoute(filename);
include $(BASE)header.mk
# Variables
-SRCS := main.c
+SRCS := main.c addr.c routes.c
BIN := $(OUTPUTDIR)Bin/ifconfig
LDFLAGS-$(DIR) += -lnet
return -1;
}
- printf("pid = %i\n", pid);
-
// Spawn shell in a child process
if(pid == 0)
{
}
// Traverse Directory
- while( (tmp = readdir(fd, buf)) > 0 )
+ while( (tmp = SysReadDir(fd, buf)) > 0 )
{
// Error check
if(tmp < 0) {
--- /dev/null
+# Project: PCI Device Listing
+
+-include ../Makefile.cfg
+
+LDFLAGS +=
+
+OBJ = main.o
+BIN = lspci
+
+-include ../Makefile.tpl
--- /dev/null
+/*
+ * Acess2 lspci
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <acess/sys.h>
+
+#define PCI_BASE "/Devices/pci"
+// === PROTOTYPES ===
+ int main(int argc, char *argv[]);
+void show_device(int PFD, const char *File, int bVerbose);
+
+// === CODE ===
+int main(int argc, char *argv[])
+{
+ int fd = open(PCI_BASE, OPENFLAG_READ);
+
+ char name[256];
+
+ while( SysReadDir(fd, name) )
+ {
+ if(name[0] == '.') continue ;
+
+ show_device(fd, name, 0);
+ }
+
+ return 0;
+}
+
+void show_device(int PFD, const char *File, int bVerbose)
+{
+ int fd;
+ int rv;
+
+ struct {
+ uint16_t vendor;
+ uint16_t device;
+ uint32_t _unused;
+ uint32_t revclass;
+ } pciinfo;
+
+ fd = _SysOpenChild(PFD, File, OPENFLAG_READ);
+ if( fd == -1 ) {
+ printf("%s - ERR (open failure)\n", File);
+ return ;
+ }
+ rv = read(fd, &pciinfo, sizeof(pciinfo));
+ if( rv != sizeof(pciinfo) ) {
+ printf("%s - ERR (read %i < %i)\n", File, rv, sizeof(pciinfo));
+ close(fd);
+ return ;
+ }
+ uint32_t class_if = pciinfo.revclass >> 8;
+ uint8_t revision = pciinfo.revclass & 0xFF;
+ printf("%s - %04x:%04x %06x:%02x\n",
+ File,
+ pciinfo.vendor, pciinfo.device,
+ class_if, revision
+ );
+
+ if( bVerbose )
+ {
+ printf("\n");
+ }
+
+ close(fd);
+}
+
#include <stdio.h>
#define MOUNTABLE_FILE "/Acess/Conf/Mountable"
-#define MOUNTED_FILE "/Devices/System/VFS/Mounts"
+#define MOUNTED_FILE "/Devices/system/VFS/Mounts"
// === PROTOTYPES ===
void ShowUsage(char *ProgName);
int fd;
int i;
char *arg;
+
char *sType = NULL;
char *sDevice = NULL;
char *sDir = NULL;
char *sOptions = NULL;
+ int bUnmount = 0;
// List mounted filesystems
// - This is cheating, isn't it?
if(argc == 1) {
// Dump the contents of /Devices/system/VFS/Mounts
- FILE *fp = fopen("/Devices/system/VFS/Mounts", "r");
+ FILE *fp = fopen(MOUNTED_FILE, "r");
char buf[1024];
int len;
while( (len = fread(buf, 1024, 1, fp)) )
{
// -t <driver> :: Filesystem driver to use
case 't': sType = argv[++i]; break;
+ // -o option_list :: Options to pass the driver
+ case 'o': sOptions = argv[++i]; break;
+ // -u :: Unmount
+ case 'u': bUnmount = 1; break;
case '-':
//TODO: Long Arguments
default:
return EXIT_FAILURE;
}
+ if( bUnmount )
+ {
+ // TODO: Check for a match in the fstab
+
+ if( sDir ) {
+ fprintf(stderr, "`mount -u` takes one argument\n");
+ }
+
+ sDir = sDevice;
+ if( _SysMount(NULL, sDir, NULL, NULL) ) // Unmount (Dev=NULL means unmount)
+ {
+ fprintf(stderr, "Unmount failed\n");
+ }
+ return EXIT_SUCCESS;
+ }
+
// Check if we even got a device/mountpoint
if(sDevice == NULL) {
ShowUsage(argv[0]);
else
{
// Check that we were passed a filesystem type
- if(sType == NULL) {
- fprintf(stderr, "Please pass a filesystem type\n");
- return EXIT_FAILURE;
- }
+// if(sType == NULL) {
+// fprintf(stderr, "Please pass a filesystem type\n");
+// return EXIT_FAILURE;
+// }
}
// Check Device
if(sOptions == NULL) sOptions = "";
// Let's Mount!
- _SysMount(sDevice, sDir, sType, sOptions);
+ if( _SysMount(sDevice, sDir, sType, sOptions) ) {
+// perror("_SysMount");
+ if( !sType )
+ fprintf(stderr, "Filesystem autodetection failed, please pass a type\n");
+ else {
+ fprintf(stderr, "Mount %s:'%s'=>'%s' failed\n", sType, sDevice, sDir);
+ }
+ }
return 0;
}
void ShowUsage(char *ProgName)
{
fprintf(stderr, "Usage:\n");
- fprintf(stderr, " %s [-t <type>] <device> <directory>\n", ProgName);
+ fprintf(stderr, " %s [-t <type>] <device> <directory> [-o <options>]\n", ProgName);
fprintf(stderr, "or %s <device>\n", ProgName);
fprintf(stderr, "or %s <directory>\n", ProgName);
fprintf(stderr, "or %s\n", ProgName);
# Rules
ASFLAGS-$(DIR) := -felf -D ARCHDIR=$(ARCHDIR) -D __ASSEMBLER__=1
-CPPFLAGS-$(DIR) := -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS-$(DIR) := -ffreestanding -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS-$(DIR) += $(addprefix -I,$(wildcard $(ACESSUSERDIR)Libraries/*/include_exp/))
CFLAGS-$(DIR) := -g -Wall -fno-stack-protector -O3
LDFLAGS-$(DIR) := -T $(OUTPUTDIR)Libs/acess.ld -rpath-link $(OUTPUTDIR)Libs -L $(OUTPUTDIR)Libs -I /Acess/Libs/ld-acess.so -lld-acess -lc $(OUTPUTDIR)Libs/crtbegin.o $(OUTPUTDIR)Libs/crtend.o
--- /dev/null
+# Project: wget clone
+
+-include ../Makefile.cfg
+
+CFLAGS += -std=gnu99
+LDFLAGS += -lnet -lpsocket -luri
+OBJ = main.o
+BIN = wget
+
+-include ../Makefile.tpl
+
--- /dev/null
+/*
+ * Acess2 Command-line HTTP Client (wget)
+ * - By John Hodge
+ *
+ * main.c
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <net.h>
+#include <uri.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+
+enum eProcols
+{
+ PROTO_NONE,
+ PROTO_HTTP,
+ PROTO_HTTPS
+};
+
+const char **gasURLs;
+ int giNumURLs;
+
+ int main(int argc, char *argv[]);
+ int _ParseHeaderLine(char *Line, int State, size_t *Size);
+void writef(int fd, const char *format, ...);
+
+int main(int argc, char *argv[])
+{
+ int proto, rv;
+ gasURLs = malloc( (argc - 1) * sizeof(*gasURLs) );
+
+ // Parse arguments
+ for(int i = 1; i < argc; i ++ )
+ {
+ char *arg = argv[i];
+ if( arg[0] != '-' ) {
+ // URL
+ gasURLs[giNumURLs++] = arg;
+ }
+ else if( arg[1] != '-') {
+ // Short arg
+ }
+ else {
+ // Long arg
+ }
+ }
+
+ // Do the download
+ for( int i = 0; i < giNumURLs; i ++ )
+ {
+ char *outfile = NULL;
+ tURI *uri = URI_Parse(gasURLs[i]);
+ struct addrinfo *addrinfo;
+
+ if( !uri ) {
+ fprintf(stderr, "'%s' is not a valid URL", gasURLs[i]);
+ continue ;
+ }
+
+ printf("Proto: %s, Host: %s, Path: %s\n", uri->Proto, uri->Host, uri->Path);
+
+ if( uri->Path[0] == '\0' || uri->Path[strlen(uri->Path)-1] == '/' )
+ outfile = "index.html";
+ else {
+ outfile = strrchr(uri->Path, '/');
+ if( !outfile )
+ outfile = uri->Path;
+ else
+ outfile += 1;
+ }
+
+ if( strcmp(uri->Proto, "http") == 0 ) {
+ proto = PROTO_HTTP;
+ }
+ else if( strcmp(uri->Proto, "https") == 0 ) {
+ proto = PROTO_HTTPS;
+ }
+ else {
+ // Unknown
+ fprintf(stderr, "Unknown protocol '%s'\n", uri->Proto);
+ free(uri);
+ continue ;
+ }
+
+ if( proto != PROTO_HTTP ) {
+ fprintf(stderr, "TODO: Support protocols other than HTTP\n");
+ free(uri);
+ continue ;
+ }
+
+ rv = getaddrinfo(uri->Host, "http", NULL, &addrinfo);
+ if( rv != 0 ) {
+ fprintf(stderr, "Unable to resolve %s: %s\n", uri->Host, gai_strerror(rv));
+ continue ;
+ }
+
+ for( struct addrinfo *addr = addrinfo; addr != NULL; addr = addr->ai_next )
+ {
+ int bSkipLine = 0;
+ // TODO: Convert to POSIX/BSD
+ // NOTE: using addr->ai_addr will break for IPv6, as there is more info before the address
+ int sock;
+
+ printf("Attempting [%s]:80\n", Net_PrintAddress(addr->ai_family, addr->ai_addr->sa_data));
+
+ sock = Net_OpenSocket_TCPC(addr->ai_family, addr->ai_addr->sa_data, 80);
+ if( sock == -1 ) {
+ continue ;
+ }
+
+ _SysDebug("Connected as %i", sock);
+
+ writef(sock, "GET /%s HTTP/1.1\r\n", uri->Path);
+ writef(sock, "Host: %s\r\n", uri->Host);
+// writef(sock, "Accept-Encodings: */*\r\n");
+ writef(sock, "User-Agent: awget/0.1 (Acess2)\r\n");
+ writef(sock, "\r\n");
+
+ // Parse headers
+ char inbuf[BUFSIZ+1];
+ size_t offset = 0, len = 0;
+ int state = 0;
+ size_t bytes_seen = 0;
+ size_t bytes_wanted = -1; // invalid
+
+
+ inbuf[0] = '\0';
+ while( state == 0 || state == 1 )
+ {
+ if( offset == BUFSIZ ) {
+ bSkipLine = 1;
+ offset = 0;
+ }
+ inbuf[len] = '\0';
+
+ char *eol = strchr(inbuf, '\n');
+ // No end of line char? read some more
+ if( eol == NULL ) {
+ // TODO: Handle -1 return
+ len += read(sock, inbuf + offset, BUFSIZ - 1 - offset);
+ continue ;
+ }
+
+ // abuse offset as the end of the string
+ offset = (eol - inbuf) + 1;
+
+ // Clear EOL bytes
+ *eol = '\0';
+ // Nuke the \r
+ if( eol - 1 >= inbuf )
+ eol[-1] = '\0';
+
+ if( !bSkipLine )
+ state = _ParseHeaderLine(inbuf, state, &bytes_wanted);
+
+ // Move unused data down in memory
+ len -= offset;
+ memmove( inbuf, inbuf + offset, BUFSIZ - offset );
+ offset = len;
+ }
+
+ if( state == 2 )
+ {
+ _SysDebug("RXing %i bytes to '%s'", bytes_wanted, outfile);
+ int outfd = open(outfile, O_WR|O_CREAT, 0666);
+ if( outfd == -1 ) {
+ fprintf(stderr, "Unable to open '%s' for writing\n", outfile);
+ }
+ else
+ {
+ // Write the remainder of the buffer
+ do
+ {
+ write(outfd, inbuf, len);
+ bytes_seen += len;
+ _SysDebug("%i/%i bytes done", bytes_seen, bytes_wanted);
+ } while( bytes_seen < bytes_wanted && (len = read(sock, inbuf, sizeof(inbuf))) > 0 );
+ close(outfd);
+ }
+ }
+
+ _SysDebug("Closing socket");
+ close(sock);
+ break ;
+ }
+
+ free(uri);
+ }
+
+ return 0;
+}
+
+int _ParseHeaderLine(char *Line, int State, size_t *Size)
+{
+ _SysDebug("Header - %s", Line);
+ // First line (Status and version)
+ if( State == 0 )
+ {
+ // HACK - assumes HTTP/1.1 (well, 9 chars before status)
+ switch( atoi(Line + 9) )
+ {
+ case 200:
+ // All good!
+ return 1;
+ default:
+ fprintf(stderr, "Unknown HTTP status - %s\n", Line + 9);
+ return -1;
+ }
+ }
+ // Last line?
+ else if( Line[0] == '\0' )
+ {
+ return 2;
+ }
+ // Body lines
+ else
+ {
+ char *value;
+ char *colon = strchr(Line, ':');
+ if(colon == NULL) return 1;
+
+ *colon = '\0';
+ value = colon + 2;
+ if( strcmp(Line, "Content-Length") == 0 ) {
+ *Size = atoi(value);
+ }
+ else {
+ printf("Ignorning header '%s' = '%s'\n", Line, value);
+ }
+
+ return 1;
+ }
+}
+
+void writef(int fd, const char *format, ...)
+{
+ va_list args;
+ size_t len;
+
+ va_start(args, format);
+ len = vsnprintf(NULL, 0, format, args);
+ va_end(args);
+
+ char data[len + 1];
+ va_start(args, format);
+ vsnprintf(data, len+1, format, args);
+ va_end(args);
+
+ write(fd, data, len);
+}
+
MAKEDEP = $(CC) -M
ASFLAGS += -D ARCHDIR=$(ARCHDIR) -D __ASSEMBLER__=1
-CPPFLAGS := -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS := -ffreestanding -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS += $(addprefix -I,$(wildcard $(ACESSUSERDIR)Libraries/*/include_exp/))
CFLAGS := -g -Wall -fPIC -fno-stack-protector -O3
-LDFLAGS := -g -nostdlib -shared -I/Acess/Libs/ld-acess.so -lld-acess -e SoMain -x -L$(OUTPUTDIR)Libs/ --no-undefined
+LDFLAGS := -g -nostdlib -shared -I/Acess/Libs/ld-acess.so -lld-acess -e SoMain -x -L$(OUTPUTDIR)Libs/ --no-undefined `$(CC) -print-libgcc-file-name`
ifneq ($(_XBIN),)
$(xCP) $(_XBIN) $(DISTROOT)/Libs/
endif
+#ifneq ($(INCFILES),)
+# for f in $(INCFILES); do ln -s $f $(ACESSDIR)/include/$f; done
+#endif
$(_BIN): $(OBJ) $(_LIBS)
@mkdir -p $(dir $(_BIN))
@echo [LD] -o $(BIN) $(OBJ)
- @$(LD) $(LDFLAGS) -o $(_BIN) $(OBJ)
+ @$(LD) $(LDFLAGS) -o $(_BIN) $(OBJ) $(shell $(CC) -print-libgcc-file-name)
@$(DISASM) -S $(_BIN) > $(_OBJPREFIX)$(BIN).dsm
$(_OBJPREFIX)%.o: %.c
--- /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_*) }
+}
+
+
BIN = ld-acess.so
EXTRABIN := libld-acess.so
EXTRACLEAN := $(_OBJPREFIX)_stublib.o
+INCFILES := sys/sys.h
CFLAGS = -g -Wall -fno-builtin -fno-leading-underscore -fno-stack-protector -fPIC
CFLAGS += $(CPPFLAGS)
# create libld-acess.so
$(_XBIN): $(_OBJPREFIX)_stublib.o
@echo [LD] -o -shared libld-acess.so
- $(LD) -shared -o $@ $<
+ $(LD) -shared -o $@ $< $(LDFLAGS)
# @$(LD) $(LDFLAGS) -o $@ $(OBJ)
#include "arch/syscalls.s.h"
// libgcc functions
+#if 0
uint64_t __udivdi3(uint64_t Num, uint64_t Den){return 0;}
uint64_t __umoddi3(uint64_t Num, uint64_t Den){return 0;}
int32_t __modsi3(int32_t Num, int32_t Den){return 0;}
uint32_t __udivsi3(uint32_t Num, uint32_t Den){return 0;}
uint32_t __umodsi3(uint32_t Num, uint32_t Den){return 0;}
+#endif
void *_crt0_exit_handler;
+void abort(void){}
--- /dev/null
+//
+// Acess2 ARMv7 - System Calls
+//
+
+.globl _start
+.extern SoMain
+_start:
+ pop {r0}
+ ldm sp, {r1,r2,r3}
+ bl SoMain
+
+ mov r4, r0
+
+ pop {r0,r1,r2}
+ blx r4
+
+ b _exit
+
+@ Stupid GCC
+.globl __ucmpdi2
+__ucmpdi2:
+ cmp r0, r2
+ movmi r0, #0
+ movmi pc, lr
+ movhi r0, #2
+ movhi pc, lr
+ cmp r1, r2
+ movmi r0, #0
+ movmi pc, lr
+ movhi r0, #2
+ movhi pc, lr
+ mov r0, #1
+ mov pc, lr
+
+@ Well, can't blame it
+@ - Clear the instruction cache
+.globl __clear_cache
+__clear_cache:
+ svc #0x1001
+ mov pc, lr
+
+@ DEST
+@ SRC
+@_memcpy:
+@ push rbp
+@ mov rbp, rsp
+@
+@ ; RDI - First Param
+@ ; RSI - Second Param
+@ mov rcx, rdx ; RDX - Third
+@ rep movsb
+@
+@ pop rbp
+@ ret
+@
+.globl _errno
+_errno: .long 0 @ Placed in .text, to allow use of relative addressing
+
+.macro syscall0 _name, _num
+.globl \_name
+\_name:
+ push {lr}
+ svc #\_num
+ str r2, _errno
+ pop {pc}
+.endm
+
+.macro syscall5 _name, _num
+.globl \_name
+\_name:
+ push {r4, lr}
+ ldr r4, [sp,#8]
+ svc #\_num
+ str r2, _errno
+ pop {r4, pc}
+.endm
+
+.macro syscall6 _name, _num
+.globl \_name
+\_name:
+ push {r4,r5,lr}
+ ldr r4, [sp,#12]
+ ldr r5, [sp,#16]
+ svc #\_num
+ str r2, _errno
+ pop {r4,r5,pc}
+.endm
+
+#define SYSCALL0(_name,_num) syscall0 _name, _num
+#define SYSCALL1(_name,_num) SYSCALL0(_name, _num)
+#define SYSCALL2(_name,_num) SYSCALL0(_name, _num)
+#define SYSCALL3(_name,_num) SYSCALL0(_name, _num)
+#define SYSCALL4(_name,_num) SYSCALL0(_name, _num)
+// TODO: 5/6 need special handling, because the args are on the stack
+#define SYSCALL5(_name,_num) syscall5 _name, _num
+#define SYSCALL6(_name,_num) syscall6 _name, _num
+
+// Override the clone syscall
+#define _exit _exit_raw
+#define _clone _clone_raw
+#include "syscalls.s.h"
+#undef _exit
+#undef _clone
+
+.globl _clone
+_clone:
+ push {r4}
+ mov r4, r1
+ svc #SYS_CLONE
+ str r2, _errno
+ tst r4, r4
+ beq _clone_ret
+ @ If in child, set SP
+ tst r0,r0
+ movne sp, r4
+_clone_ret:
+ pop {r4}
+ mov pc, lr
+
+.globl _exit
+_exit:
+ svc #0
+ b .
+
+.globl abort
+abort:
+ mov r0, #0
+ svc #0
+ b .
+
+.globl __exidx_start
+__exidx_start:
+ b .
+.globl __exidx_end
+__exidx_end:
+ b .
+
--- /dev/null
+ENTRY(_start)
+OUTPUT_FORMAT(elf32-littlearm)
+
+SECTIONS {
+ . = 0x6FFF0000;
+ gLinkedBase = .;
+ . += SIZEOF_HEADERS;
+ .interp : { *(.interp) }
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ }
+
+ .text : AT(ADDR(.text)) {
+ code = .;
+ *(.text)
+ *(.rodata*)
+ PROVIDE_HIDDEN(__exidx_start = .);
+ .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+ PROVIDE_HIDDEN(__exidx_end = .);
+ }
+
+ .data ALIGN (0x1000) : AT(ADDR(.data)) {
+ data = .;
+ *(.data)
+ }
+
+ .bss ALIGN (0x1000) : AT(ADDR(.bss)) {
+ _sbss = .;
+ *(COMMON)
+ *(.bss)
+ _ebss = .;
+ bss = .;
+ }
+ _end = .;
+}
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
}
+ __exidx_start = .;
.text : AT(ADDR(.text)) {
code = .;
*(.text)
*(.rodata*)
}
+ __exidx_end = .;
.data ALIGN (0x1000) : AT(ADDR(.data)) {
data = .;
SYSCALL1(SysSetName, SYS_SETNAME)
SYSCALL2(SysGetName, SYS_GETNAME)
+SYSCALL0(_SysTimestamp, SYS_GETTIME)
SYSCALL1(SysSetPri, SYS_SETPRI)
SYSCALL4(seek, SYS_SEEK) // int, uint64_t, int
SYSCALL1(tell, SYS_TELL) // int
SYSCALL3(finfo, SYS_FINFO) // int, void*, int
-SYSCALL2(readdir, SYS_READDIR) // int, char*
+SYSCALL2(SysReadDir, SYS_READDIR) // int, char*
SYSCALL2(_SysGetACL,SYS_GETACL) // int, void*
SYSCALL1(chdir, SYS_CHDIR) // char*
SYSCALL3(ioctl, SYS_IOCTL) // int, int, void*
SYSCALL4(_SysMount, SYS_MOUNT) // char*, char*, char*, char*
SYSCALL6(_SysSelect, SYS_SELECT) // int, fd_set*, fd_set*, fd_set*, tTime*, uint32_t
+SYSCALL1(unlink, SYS_UNLINK) // const char*
SYSCALL3(_SysOpenChild, SYS_OPENCHILD)
* elf.c
* - ELF32/ELF64 relocation
*/
-#define DEBUG 0
+#ifndef DEBUG // This code is #include'd from the kernel, so DEBUG may already be defined
+# define DEBUG 0
+#endif
#include "common.h"
#include <stdint.h>
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 ];
-
+
// Get hash
iNameHash = ElfHashString(Name);
iNameHash %= nbuckets;
int i;
Elf64_Ehdr *hdr = Base;
Elf64_Phdr *phtab;
- Elf64_Dyn *dyntab;
+ Elf64_Dyn *dyntab = NULL;
Elf64_Addr compiledBase = -1, baseDiff;
Elf64_Sym *symtab = NULL;
char *strtab = NULL;
DEBUGS("Elf64Relocate: e_phnum = %i", hdr->e_phnum);
// Scan for the dynamic table (and find the compiled base)
- phtab = Base + hdr->e_phoff;
+ phtab = (void*)((uintptr_t)Base + hdr->e_phoff);
for( i = 0; i < hdr->e_phnum; i ++ )
{
if(phtab[i].p_type == PT_DYNAMIC)
break;
case R_X86_64_COPY: {
size_t size;
- void *sym = GetSymbol(symname, &size);
- memcpy(ptr, sym, size);
+ void *symptr = GetSymbol(symname, &size);
+ memcpy(ptr, symptr, size);
} break;
case R_X86_64_GLOB_DAT:
*(uint64_t*)ptr = (uintptr_t)GetSymbol(symname, NULL);
#define STR(x) _STR(x)
#define EXP(sym) {&sym, STR(sym)}
+#define SYSCALL0(name,num) EXP(name),
+#define SYSCALL1(name,num) EXP(name),
+#define SYSCALL2(name,num) EXP(name),
+#define SYSCALL3(name,num) EXP(name),
+#define SYSCALL4(name,num) EXP(name),
+#define SYSCALL5(name,num) EXP(name),
+#define SYSCALL6(name,num) EXP(name),
+
// === CONSTANTS ===
const struct {
void *Value;
char *Name;
} caLocalExports[] = {
EXP(gLoadedLibraries),
- EXP(_exit),
- EXP(clone),
- EXP(kill),
- EXP(yield),
- EXP(sleep),
- EXP(_SysWaitEvent),
- EXP(waittid),
- EXP(gettid),
- EXP(getpid),
- EXP(getuid),
- EXP(getgid),
-
- EXP(setuid),
- EXP(setgid),
-
- EXP(SysSetName),
- //EXP(SysGetName),
-
- //EXP(SysSetPri),
-
- EXP(SysSendMessage),
- EXP(SysGetMessage),
-
- EXP(_SysSpawn),
- EXP(execve),
- EXP(SysLoadBin),
- EXP(SysUnloadBin),
-
- EXP(_SysSetFaultHandler),
+ EXP(_errno),
- EXP(open),
- EXP(reopen),
- EXP(close),
- EXP(read),
- EXP(write),
- EXP(seek),
- EXP(tell),
- EXP(finfo),
- EXP(readdir),
- EXP(_SysGetACL),
- EXP(chdir),
- EXP(ioctl),
- EXP(_SysMount),
- EXP(_SysSelect),
-
- EXP(_SysOpenChild),
-
- EXP(_SysGetPhys),
- EXP(_SysAllocate),
- EXP(_SysDebug),
-
+ #define __ASSEMBLER__
+ #include "arch/syscalls.s.h"
+ #undef __ASSEMBLER__
+#if 0
EXP(__umoddi3),
EXP(__udivdi3),
EXP(__divsi3),
EXP(__modsi3),
EXP(__udivsi3),
EXP(__umodsi3)
+#endif
};
const int ciNumLocalExports = sizeof(caLocalExports)/sizeof(caLocalExports[0]);
--- /dev/null
+/**
+ * \file drivers.h
+ */
+#ifndef _SYS_DRIVERS_H
+#define _SYS_DRIVERS_H
+
+// === COMMON ===
+enum eDrv_Common {
+ DRV_IOCTL_NULL,
+ DRV_IOCTL_TYPE,
+ DRV_IOCTL_IDENT,
+ DRV_IOCTL_VER
+};
+
+enum eDrv_Types {
+ DRV_TYPE_NULL, //!< NULL Type - Custom Interface
+ DRV_TYPE_TERMINAL, //!< Terminal
+ DRV_TYPE_VIDEO, //!< Video - LFB
+ DRV_TYPE_SOUND, //!< Audio
+ DRV_TYPE_MOUSE, //!< Mouse
+ DRV_TYPE_JOYSTICK //!< Joystick / Gamepad
+};
+
+// === VIDEO ===
+enum eDrv_Video {
+ VID_IOCTL_SETMODE = 4,
+ VID_IOCTL_GETMODE,
+ VID_IOCTL_FINDMODE,
+ VID_IOCTL_MODEINFO,
+ VID_IOCTL_REQLFB // Request LFB
+};\r
+struct sVideo_IOCtl_Mode {\r
+ short id;\r
+ Uint16 width;\r
+ Uint16 height;\r
+ Uint16 bpp;\r
+};\r
+typedef struct sVideo_IOCtl_Mode tVideo_IOCtl_Mode; //!< Mode Type
+
+// === MOUSE ===
+enum eDrv_Mouse {\r
+ MSE_IOCTL_SENS = 4,\r
+ MSE_IOCTL_MAX_X,\r
+ MSE_IOCTL_MAX_Y\r
+};
+
+// === Terminal ===
+#include "devices/terminal.h"
+
+#endif
--- /dev/null
+/**
+ * \file devices/terminal.h
+ */
+#ifndef _SYS_DEVICES_TERMINAL_H
+#define _SYS_DEVICES_TERMINAL_H
+
+#include <stdint.h>
+
+enum eDrv_Terminal {
+ TERM_IOCTL_MODETYPE = 4,
+ TERM_IOCTL_WIDTH,
+ TERM_IOCTL_HEIGHT,
+ TERM_IOCTL_QUERYMODE,
+ TERM_IOCTL_FORCESHOW,
+ TERM_IOCTL_GETSETCURSOR,
+ TERM_IOCTL_SETCURSORBITMAP
+};
+
+
+struct sTerm_IOCtl_Mode
+{
+ int16_t ID; //!< Zero Based index of mode
+ int16_t DriverID; //!< Driver's ID number (from ::tVideo_IOCtl_Mode)
+ uint16_t Height; //!< Height
+ uint16_t Width; //!< Width
+ uint8_t Depth; //!< Bits per cell
+ uint8_t Flags; //!< Flags (1: Text Mode)
+};
+
+/**
+ * \brief Terminal Modes
+ */
+enum eTplTerminal_Modes {
+ /**
+ * \brief UTF-8 Text Mode
+ * Any writes to the terminal file are treated as UTF-8 encoded
+ * strings and reads will also return UTF-8 strings.
+ */
+ TERM_MODE_TEXT,
+
+ /**
+ * \brief 32bpp Framebuffer
+ * Writes to the terminal file will write to the framebuffer.
+ * Reads will return UTF-32 characters
+ */
+ TERM_MODE_FB,
+
+ /**
+ * \brief OpenGL 2D/3D
+ * Writes to the terminal file will send 3D commands
+ * Reads will return UTF-32 characters
+ * \note May or may not stay in the spec
+ */
+ TERM_MODE_OPENGL,
+
+ NUM_TERM_MODES
+};
+
+#endif
--- /dev/null
+/*
+ */
+#ifndef _ACESS_INTDEFS_H_
+#define _ACESS_INTDEFS_H_
+
+#include <stdint.h>
+#include <limits.h>
+
+#if 0
+#define INT_MIN -0x80000000
+#define INT_MAX 0x7FFFFFFF
+
+typedef unsigned char __uint8_t;
+typedef unsigned short __uint16_t;
+typedef unsigned int __uint32_t;
+typedef unsigned long long __uint64_t;
+
+typedef signed char __int8_t;
+typedef signed short __int16_t;
+typedef signed int __int32_t;
+typedef signed long long __int64_t;
+
+#if defined(ARCHDIR_is_x86)
+typedef __int32_t __intptr_t;
+typedef __uint32_t __uintptr_t;
+#elif defined(ARCHDIR_is_x86_64)
+typedef __int64_t __intptr_t;
+typedef __uint64_t __uintptr_t;
+#elif defined(ARCHDIR_is_armv7) | defined(ARCHDIR_is_armv6)
+typedef __int32_t __intptr_t;
+typedef __uint32_t __uintptr_t;
+#else
+# error "Unknown pointer size"
+#endif
+
+#endif
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 System Interface Header
+ */
+#ifndef _ACESS_SYS_H_
+#define _ACESS_SYS_H_
+
+#include <stdint.h>
+#include "../sys/types.h"
+
+// === CONSTANTS ===
+#ifndef NULL
+# define NULL ((void*)0)
+#endif
+
+#define THREAD_EVENT_VFS 0x0001
+#define THREAD_EVENT_IPCMSG 0x0002
+#define THREAD_EVENT_SIGNAL 0x0004
+
+#define OPENFLAG_EXEC 0x01
+#define OPENFLAG_READ 0x02
+#define OPENFLAG_WRITE 0x04
+#define OPENFLAG_TRUNCATE 0x10
+#define OPENFLAG_APPEND 0x20
+#define OPENFLAG_NOLINK 0x40
+#define OPENFLAG_CREATE 0x80
+#ifndef SEEK_CUR
+# define SEEK_SET 1
+# define SEEK_CUR 0
+# define SEEK_END -1
+#endif
+#define GETMSG_IGNORE ((void*)-1)
+#define FILEFLAG_DIRECTORY 0x10
+#define FILEFLAG_SYMLINK 0x20
+
+// === TYPES ===
+
+// === VARIABLES ===
+extern int _errno;
+
+// === FUNCTIONS ===
+extern void _SysDebug(const char *format, ...);
+// --- Proc ---
+extern void _exit(int status) __attribute__((noreturn));
+extern void sleep(void);
+extern void yield(void);
+extern int kill(int pid, int sig);
+//extern void wait(int miliseconds);
+extern int _SysWaitEvent(int EventMask);
+extern int waittid(int id, int *status);
+extern int clone(int flags, void *stack);
+extern int execve(char *path, char **argv, char **envp);
+extern int _SysSpawn(const char *Path, const char **argv, const char **envp, int nFDs, int *FDs);
+extern int gettid(void);
+extern int getpid(void);
+extern int _SysSetFaultHandler(int (*Handler)(int));
+extern void SysSetName(const char *Name);
+extern int SysGetName(char *NameDest);
+extern int SysSetPri(int Priority);
+extern int64_t _SysTimestamp(void);
+
+// --- Permissions ---
+extern int getuid(void);
+extern int getgid(void);
+extern void setuid(int id);
+extern void setgid(int id);
+
+// --- VFS ---
+extern int chdir(const char *dir);
+extern int open(const char *path, int flags, ...);
+extern int reopen(int fd, const char *path, int flags);
+extern int close(int fd);
+extern uint read(int fd, void *buffer, uint length);
+extern uint write(int fd, const void *buffer, uint length);
+extern int seek(int fd, int64_t offset, int whence);
+extern uint64_t tell(int fd);
+extern int ioctl(int fd, int id, void *data);
+extern int finfo(int fd, t_sysFInfo *info, int maxacls);
+extern int SysReadDir(int fd, char *dest);
+extern int _SysOpenChild(int fd, const char *name, int flags);
+extern int _SysGetACL(int fd, t_sysACL *dest);
+extern int _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options);
+extern int _SysSelect(int nfds, fd_set *read, fd_set *write, fd_set *err, int64_t *timeout, unsigned int extraevents);
+#define select(nfs, rdfds, wrfds, erfds, timeout) _SysSelect(nfs, rdfds, wrfds, erfds, timeout, 0)
+extern int unlink(const char *pathname);
+
+// --- IPC ---
+extern int SysSendMessage(pid_t dest, uint length, const void *Data);
+extern int SysGetMessage(pid_t *src, void *Data);
+
+// --- MEMORY ---
+uint64_t _SysGetPhys(uint vaddr);
+uint64_t _SysAllocate(uint vaddr);
+
+#endif
--- /dev/null
+#ifndef _STDDEF_H_
+#define _STDDEF_H_
+
+#include "acess/intdefs.h"
+
+#ifndef NULL
+# define NULL ((void*)0)
+#endif
+
+typedef __intptr_t size_t;
+
+#endif
--- /dev/null
+/**
+ * \file basic_drivers.h
+ */
+#ifndef _SYS_BASIC_DRIVERS_H
+#define _SYS_BASIC_DRIVERS_H
+
+// === COMMON ===
+enum eDrv_Common {
+ DRV_IOCTL_NULL,
+ DRV_IOCTL_TYPE,
+ DRV_IOCTL_IDENT,
+ DRV_IOCTL_VER
+};
+
+enum eDrv_Types {
+ DRV_TYPE_NULL, //!< NULL Type - Custom Interface
+ DRV_TYPE_TERMINAL, //!< Terminal
+ DRV_TYPE_VIDEO, //!< Video - LFB
+ DRV_TYPE_SOUND, //!< Audio
+ DRV_TYPE_MOUSE, //!< Mouse
+ DRV_TYPE_JOYSTICK //!< Joystick / Gamepad
+};
+
+// === VIDEO ===
+enum eDrv_Video {
+ VID_IOCTL_SETMODE = 4,
+ VID_IOCTL_GETMODE,
+ VID_IOCTL_FINDMODE,
+ VID_IOCTL_MODEINFO,
+ VID_IOCTL_REQLFB // Request LFB
+};\r
+struct sVideo_IOCtl_Mode {\r
+ short id;\r
+ Uint16 width;\r
+ Uint16 height;\r
+ Uint16 bpp;\r
+};\r
+typedef struct sVideo_IOCtl_Mode tVideo_IOCtl_Mode; //!< Mode Type
+
+// === MOUSE ===
+enum eDrv_Mouse {\r
+ MSE_IOCTL_SENS = 4,\r
+ MSE_IOCTL_MAX_X,\r
+ MSE_IOCTL_MAX_Y\r
+};
+
+#endif
--- /dev/null
+/*
+ * Acess2 Dynamic Linker
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/param.h
+ * - System Parameters (?)
+ */
+#ifndef _SYS__PARAM_H_
+#define _SYS__PARAM_H_
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ */
+#ifndef _SYS_STAT_H_
+#define _SYS_STAT_H_
+
+//#include "../acess/intdefs.h" /* Evil */
+//#include "../stddef.h"
+#include <stdint.h>
+
+typedef void *dev_t; /* TODO: How to identify a device with Acess */
+typedef uint64_t ino_t;
+typedef unsigned int blksize_t;
+typedef uint64_t blkcnt_t;
+typedef unsigned int nlink_t;
+typedef uint32_t mode_t;
+
+typedef uint32_t uid_t;
+typedef uint32_t gid_t;
+
+#define S_IFMT 0170000 /* type of file */
+#define S_IFDIR 0040000 /* directory */
+#define S_IFCHR 0020000 /* character special */
+#define S_IFBLK 0060000 /* block special */
+#define S_IFREG 0100000 /* regular */
+#define S_IFLNK 0120000 /* symbolic link */
+#define S_IFSOCK 0140000 /* socket */
+#define S_IFIFO 0010000 /* fifo */
+
+
+struct stat
+{
+ dev_t st_dev; /* ID of device containing file */
+ ino_t st_ino; /* inode number */
+ mode_t st_mode; /* protection */
+ nlink_t st_nlink; /* number of hard links */
+ uid_t st_uid; /* user ID of owner */
+ gid_t st_gid; /* group ID of owner */
+ dev_t st_rdev; /* device ID (if special file) */
+ off_t st_size; /* total size, in bytes */
+ blksize_t st_blksize; /* blocksize for file system I/O */
+ blkcnt_t st_blocks; /* number of 512B blocks allocated */
+ time_t st_atime; /* time of last access */
+ time_t st_mtime; /* time of last modification */
+ time_t st_ctime; /* time of last status change */
+};
+
+extern int stat(const char *path, struct stat *buf);
+extern int fstat(int fd, struct stat *buf);
+
+#endif
--- /dev/null
+/*\r
+ Syscall Definitions\r
+*/\r
+#ifndef _SYS_SYS_H_\r
+#define _SYS_SYS_H_\r
+\r
+#include <acess/sys.h>\r
+\r
+#include <sys/types.h>\r
+\r
+//#define O_RDONLY OPENFLAG_READ\r
+//#define O_WRONLY OPENFLAG_WRITE\r
+//#define O_CREAT (OPENFLAG_CREATE|OPENFLAG_WRITE)\r
+//#define O_TRUNC OPENFLAG_WRITE\r
+//#define O_APPEND OPENFLAG_WRITE\r
+\r
+\r
+#if 0\r
+#define OPEN_FLAG_READ 1\r
+#define OPEN_FLAG_WRITE 2\r
+#define OPEN_FLAG_EXEC 4\r
+\r
+enum {\r
+ K_WAITPID_DIE = 0\r
+};\r
+\r
+// === System Calls ===\r
+extern void _exit(int ret);\r
+extern int brk(int bssend);\r
+extern int execve(char *file, char *args[], char *envp[]);\r
+extern int fork();\r
+extern int yield();\r
+extern int sleep();\r
+\r
+extern int open(char *file, int flags);\r
+extern int close(int fp);\r
+extern int read(int fp, int len, void *buf);\r
+extern int write(int fp, int len, void *buf);\r
+extern int tell(int fp);\r
+extern void seek(int fp, int64_t dist, int flag);\r
+extern int fstat(int fp, t_fstat *st);\r
+extern int ioctl(int fp, int call, void *arg);\r
+extern int readdir(int fp, char *file);\r
+\r
+extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errfds, time_t *timeout);\r
+\r
+extern int kdebug(char *fmt, ...);\r
+extern int waitpid(int pid, int action);\r
+extern int gettid(); // Get Thread ID\r
+extern int getpid(); // Get Process ID\r
+extern int sendmsg(int dest, unsigned int *Data);\r
+extern int pollmsg(int *src, unsigned int *Data);\r
+extern int getmsg(int *src, unsigned int *Data);\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*
+ */
+#ifndef _SYS_TYPES_H
+#define _SYS_TYPES_H
+
+#include "../acess/intdefs.h"
+
+typedef struct stat t_fstat;
+
+#define FD_SETSIZE 128
+
+
+#define CLONE_VM 0x10
+
+typedef unsigned int id_t;
+typedef unsigned long pid_t;
+typedef unsigned long tid_t;
+typedef signed long long int time_t;
+typedef long long int off_t;
+
+typedef unsigned int uint;
+
+typedef unsigned short fd_set_ent_t;
+
+/**
+ * \brief fd_set for select()
+ */
+typedef struct
+{
+ fd_set_ent_t flags[FD_SETSIZE/16];
+} fd_set;
+
+struct s_sysACL {
+ unsigned long object; /*!< Group or user (bit 31 determines) */
+ unsigned long perms; /*!< Inverted by bit 31 */
+};
+struct s_sysFInfo {
+ unsigned int mount;
+ unsigned long long inode;
+ unsigned int uid;
+ unsigned int gid;
+ unsigned int flags;
+ unsigned long long size;
+ time_t atime;
+ time_t mtime;
+ time_t ctime;
+ int numacls;
+ struct s_sysACL acls[];
+} __attribute__((packed));
+typedef struct s_sysFInfo t_sysFInfo;
+typedef struct s_sysACL t_sysACL;
+
+extern void FD_ZERO(fd_set *fdsetp);
+extern void FD_CLR(int fd, fd_set *fdsetp);
+extern void FD_SET(int fd, fd_set *fdsetp);
+extern int FD_ISSET(int fd, fd_set *fdsetp);
+
+#include "../sys/stat.h"
+
+#endif
--- /dev/null
+#ifndef _UNISTD_H_
+#define _UNISTD_H_
+
+#define O_RDWR (OPENFLAG_READ|OPENFLAG_WRITE)
+#define O_WR (OPENFLAG_WRITE)
+#define O_RD (OPENFLAG_READ)
+#define O_CREAT (OPENFLAG_CREATE)
+#define O_RDONLY OPENFLAG_READ
+#define O_WRONLY OPENFLAG_WRITE
+#define O_TRUNC OPENFLAG_TRUNCATE
+#define O_APPEND OPENFLAG_APPEND
+
+//typedef intptr_t ssize_t;
+
+#include "acess/sys.h"
+
+
+#endif
+
return ret;
}
+#if 0
uint32_t __divmod32(uint32_t Num, uint32_t Den, uint32_t *Rem)
{
uint32_t ret = 0, add = 1;
__divmod32(Num, Den, &ret);
return ret;
}
+#endif
#endif\r
for(;;);\r
}\r
+\r
+void abort(void)\r
+{\r
+ _exit(-4);\r
+}\r
+++ /dev/null
-# Acess 2 - AxWin GUI Library
-#
-
-include ../Makefile.cfg
-
-CPPFLAGS +=
-CFLAGS += -Wall
-LDFLAGS += -lc -soname libaxwin2.so
-
-OBJ = main.o messages.o
-BIN = libaxwin2.so
-
-include ../Makefile.tpl
+++ /dev/null
-/*
- * AxWin Window Manager Interface Library
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess Licence. See the
- * file COPYING for details.
- *
- * common.h - Internal Variable and Constant definitions
- */
-#ifndef _COMMON_H_
-#define _COMMON_H_
-
-// === Includes ===
-#include <acess/sys.h>
-#include <axwin2/axwin.h>
-#include <stdlib.h>
-
-// === Constants ===
-enum eAxWin_Modes
-{
- AXWIN_MODE_IPC
-};
-
-// === Variables ===
-extern int giAxWin_Mode;
-extern int giAxWin_PID;
-
-#endif
+++ /dev/null
-/*
- * AxWin Window Manager Interface Library
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess Licence. See the
- * file COPYING for details.
- *
- * main.c - Library Initialisation
- */
-#include "common.h"
-#include <string.h>
-
-// === GLOBALS ===
- int giAxWin_Mode = 0;
- int giAxWin_PID = 9; // HACK!
-tAxWin_MessageCallback *gAxWin_DefaultCallback;
-
-// === CODE ===
-int SoMain()
-{
- return 0;
-}
-
-tAxWin_Message *AxWin_int_SendAndWait(int RetID, tAxWin_Message *Message)
-{
- tAxWin_Message *msg;
- tAxWin_RetMsg *rmsg;
-
- AxWin_SendMessage(Message);
-
- for(;;)
- {
- msg = AxWin_WaitForMessage();
-
- rmsg = (void*)msg->Data;
- if(msg->ID == MSG_SRSP_RETURN && rmsg->ReqID == Message->ID )
- break;
-
- AxWin_HandleMessage(msg);
- free(msg);
- }
-
- return msg;
-}
-
-int AxWin_Register(const char *Name, tAxWin_MessageCallback *DefaultCallback)
-{
- tAxWin_Message req;
- tAxWin_Message *msg;
- int ret;
- int len = strlen(Name);
-
- req.ID = MSG_SREQ_REGISTER;
- req.Size = 1 + (len+1)/4;
- strcpy(req.Data, Name);
-
- msg = AxWin_int_SendAndWait(MSG_SRSP_RETURN, &req);
- ret = ((tAxWin_RetMsg*)msg->Data)->Value;
- free(msg);
-
- gAxWin_DefaultCallback = DefaultCallback;
-
- return !!ret;
-}
-
-tAxWin_Element *AxWin_CreateWindow(const char *Title)
-{
- tAxWin_Message req;
- tAxWin_Message *msg;
- tAxWin_Element *ret;
- int len = strlen(Title);
-
- req.ID = MSG_SREQ_ADDWIN;
- req.Size = 1 + (len+1)/4;
- strcpy(req.Data, Title);
-
- msg = AxWin_int_SendAndWait(MSG_SRSP_RETURN, &req);
- ret = (tAxWin_Element*) ((tAxWin_RetMsg*)msg->Data)->Value;
- free(msg);
-
- return ret;
-}
-
-tAxWin_Element *AxWin_AddMenuItem(tAxWin_Element *Parent, const char *Label, int Message)
-{
- return NULL;
-}
+++ /dev/null
-/*
- * AxWin Window Manager Interface Library
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess Licence. See the
- * file COPYING for details.
- *
- * messages.c - Message Handling
- */
-#include "common.h"
-
-// === PROTOTYPES ===
- int AxWin_MessageLoop();
-tAxWin_Message *AxWin_WaitForMessage();
- int AxWin_HandleMessage(tAxWin_Message *Message);
-
-// === ===
-
-// === CODE ===
-int AxWin_SendMessage(tAxWin_Message *Message)
-{
- switch(giAxWin_Mode)
- {
- case AXWIN_MODE_IPC:
- SysSendMessage(giAxWin_PID, Message->Size*4, Message);
- break;
- default:
- break;
- }
- return 0;
-}
-
-/**
- * \brief Loop forever, checking and waiting for messages
- */
-int AxWin_MessageLoop()
-{
- tAxWin_Message *msg;
- int ret;
- for(;;)
- {
- msg = AxWin_WaitForMessage();
- ret = AxWin_HandleMessage(msg);
-
- if(ret < 0) return 0;
- }
- return 0;
-}
-
-/**
- * \brief Wait for a message
- */
-tAxWin_Message *AxWin_WaitForMessage()
-{
- int length;
- pid_t src;
- tAxWin_Message *ret = NULL;
-
- switch( giAxWin_Mode )
- {
- case AXWIN_MODE_IPC:
- while( (length = SysGetMessage(&src, NULL)) == 0 ) sleep();
- ret = malloc(length);
- SysGetMessage(NULL, ret);
- break;
- default:
- break;
- }
- return ret;
-}
-
-/**
- * \brief Handles a recieved message
- */
-int AxWin_HandleMessage(tAxWin_Message *Message)
-{
- switch(Message->ID)
- {
- default: return 0;
- }
-}
+++ /dev/null
-/*
- * AxWin Window Manager Interface Library
- * By John Hodge (thePowersGang)
- * This file is published under the terms of the Acess Licence. See the
- * file COPYING for details.
- *
- * window.c - Window Control
- */
-#include "common.h"
-
-// === TYPES & STRUCTURES ===
-struct sAxWin_Window
-{
- struct sAxWin_Window *Next;
- uint32_t WmHandle;
- tAxWin_MessageCallback *Callback;
-};
-
-// === PROTOTYPES ===
-tAxWin_Window *AxWin_CreateWindow(
- int16_t X, int16_t Y, int16_t W, int16_t H,
- uint32_t Flags, tAxWin_MessageCallback *Callback
- );
-
-// === GLOBALS ===
-//mutex_t glProcessWindows;
-tAxWin_Window *gProcessWindows;
-
-// === CODE ===
-tAxWin_Window *AxWin_CreateWindow(
- int16_t X, int16_t Y,
- int16_t W, int16_t H,
- uint32_t Flags, tAxWin_MessageCallback *Callback)
-{
- tAxWin_Message req;
- tAxWin_Message *msg;
- tAxWin_Window *win;
-
- req.ID = MSG_SREQ_NEWWINDOW;
- req.Size = 1 + sizeof(struct sAxWin_SReq_NewWindow)/4;
- req.SReq_NewWindow.X = X;
- req.SReq_NewWindow.Y = Y;
- req.SReq_NewWindow.W = W;
- req.SReq_NewWindow.H = H;
- req.SReq_NewWindow.Flags = Flags;
-
- AxWin_SendMessage(&msg);
-
- for(;;)
- {
- msg = AxWin_WaitForMessage();
-
- if(msg.ID == MSG_SRSP_WINDOW)
- break;
-
- AxWin_HandleMessage(msg);
- free(msg);
- }
-
- win = malloc(sizeof(tAxWin_Window));
- win->WmHandle = msg->SRsp_Window.Handle;
- win->Callback = Callback;
-
- //mutex_acquire(glProcessWindows);
- win->Next = gProcessWindows;
- gProcessWindows = win;
- //mutex_release(glProcessWindows);
-
- return 0;
-}
--- /dev/null
+/*
+ * Acess2 GUI Version 3 (AxWin3)
+ * - By John Hodge (thePowersGang)
+ *
+ * axwin.h
+ * - Core API Header
+ */
+#ifndef _AXWIN3_AXWIN_H_
+#define _AXWIN3_AXWIN_H_
+
+#include <stddef.h> // size_t
+
+// === CONSTANTS ===
+
+// === TYPES ===
+typedef struct sAxWin3_Window *tHWND;
+typedef unsigned int tAxWin3_Colour; // TODO: Actual 32-bit
+
+typedef void (*tAxWin3_MessageCallback)(int SourceTID, int Length);
+typedef void (*tAxWin3_HotkeyCallback)(void);
+
+typedef int (*tAxWin3_WindowMessageHandler)(tHWND Window, int Message, int Length, void *Data);
+
+// --- Connection management
+extern void AxWin3_Connect(const char *ServerDesc);
+extern tAxWin3_MessageCallback AxWin3_SetMessageCallback(tAxWin3_MessageCallback Callback);
+extern void AxWin3_MainLoop(void);
+
+// --- Non-Window based functions
+extern int AxWin3_GetDisplayCount(void);
+extern int AxWin3_GetDisplayDims(int Display, int *X, int *Y, int *Width, int *Height);
+
+// --- Window creation/deletion
+/**
+ * \brief Create a new window (with the required client structures)
+ * \param Parent Parent window handle
+ * \param Renderer Symbolic name of the renderer to use
+ * \param RendererArg Argument to pass to the renderer's initialisation
+ * \param DataBytes Number of bytes to allocate for the caller's use
+ * \param MessageHandler Function to call when a message arrives for the window
+ * \return New window handle
+ * \note Usually wrapped by renderer-specific functions
+ */
+extern tHWND AxWin3_CreateWindow(
+ tHWND Parent,
+ const char *Renderer, int RendererArg,
+ int DataBytes,
+ tAxWin3_WindowMessageHandler MessageHandler
+ );
+/**
+ * \brief Destroy a window
+ * \param Window Handle to a window to destroy
+ */
+extern void AxWin3_DestroyWindow(tHWND Window);
+extern int AxWin3_RegisterAction(tHWND Window, const char *Action, tAxWin3_HotkeyCallback cb);
+
+// --- Core window management functions
+extern void AxWin3_SendMessage(tHWND Window, tHWND Dest, int Message, int Length, void *Data);
+extern void *AxWin3_WaitMessage(tHWND Window, int MessageID, size_t *Length);
+extern void AxWin3_SetWindowTitle(tHWND Window, const char *Title);
+extern void AxWin3_FocusWindow(tHWND Window);
+extern void AxWin3_ShowWindow(tHWND Window, int bShow);
+extern void AxWin3_DecorateWindow(tHWND Window, int bDecorate);
+extern void AxWin3_SetWindowPos(tHWND Window, short X, short Y, short W, short H);
+extern void AxWin3_MoveWindow(tHWND Window, short X, short Y);
+extern void AxWin3_ResizeWindow(tHWND Window, short W, short H);
+
+#endif
+
--- /dev/null
+../../../../../KernelLand/Kernel/include/keysyms.h
\ No newline at end of file
--- /dev/null
+/*
+ * Acess2 GUI Version 3 (AxWin3)
+ * - By John Hodge (thePowersGang)
+ *
+ * menu.h
+ * - Menu window type
+ */
+#ifndef _AXWIN3_MENU_H_
+#define _AXWIN3_MENU_H_
+
+typedef void (*tAxWin3_Menu_Callback)(void *Ptr);
+typedef struct sAxWin3_MenuItem tAxWin3_MenuItem;
+
+extern tHWND AxWin3_Menu_Create(tHWND Parent);
+extern void AxWin3_Menu_ShowAt(tHWND Menu, int X, int Y);
+
+extern tAxWin3_MenuItem *AxWin3_Menu_AddItem(
+ tHWND Menu, const char *Label,
+ tAxWin3_Menu_Callback Cb, void *Ptr,
+ int Flags, tHWND SubMenu
+ );
+extern tAxWin3_MenuItem *AxWin3_Menu_GetItem(tHWND Menu, int Index);
+extern void AxWin3_Menu_SetFlags(tAxWin3_MenuItem *Item, int Flags, int Mask);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 GUI Version 3 (AxWin3)
+ * - By John Hodge (thePowersGang)
+ *
+ * widget.h
+ * - Server-side widget library
+ */
+#ifndef _AXWIN3_WIDGET_H_
+#define _AXWIN3_WIDGET_H_
+
+#include "axwin.h"
+
+typedef struct sAxWin3_Widget tAxWin3_Widget;
+
+// --- Callback types
+typedef int (*tAxWin3_Widget_FireCb)(tAxWin3_Widget *Widget);
+typedef int (*tAxWin3_Widget_KeyUpDownCb)(tAxWin3_Widget *Widget, int KeySym);
+typedef int (*tAxWin3_Widget_KeyFireCb)(tAxWin3_Widget *Widget, int KeySym, int Character);
+typedef int (*tAxWin3_Widget_MouseMoveCb)(tAxWin3_Widget *Widget, int X, int Y);
+typedef int (*tAxWin3_Widget_MouseBtnCb)(tAxWin3_Widget *Widget, int X, int Y, int Button, int bPressed);
+
+// --- Windows
+extern tHWND AxWin3_Widget_CreateWindow(tHWND Parent, int W, int H, int RootEleFlags);
+extern void AxWin3_Widget_DestroyWindow(tHWND Window);
+extern tAxWin3_Widget *AxWin3_Widget_GetRoot(tHWND Window);
+
+// --- Element Creation
+extern tAxWin3_Widget *AxWin3_Widget_AddWidget(tAxWin3_Widget *Parent, int Type, int Flags, const char *DebugName);
+extern void AxWin3_Widget_DelWidget(tAxWin3_Widget *Widget);
+
+// --- Callbacks
+extern void AxWin3_Widget_SetFireHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_FireCb Callback);
+extern void AxWin3_Widget_SetKeyHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_KeyUpDownCb Callback);
+extern void AxWin3_Widget_SetKeyFireHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_KeyFireCb Callback);
+extern void AxWin3_Widget_SetMouseMoveHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_MouseMoveCb Callback);
+extern void AxWin3_Widget_SetMouseButtonHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_MouseBtnCb Callback);
+// --- Manipulation
+extern void AxWin3_Widget_SetFlags(tAxWin3_Widget *Widget, int FlagSet, int FlagMask);
+extern void AxWin3_Widget_SetSize(tAxWin3_Widget *Widget, int Size);
+extern void AxWin3_Widget_SetText(tAxWin3_Widget *Widget, const char *Text);
+extern void AxWin3_Widget_SetColour(tAxWin3_Widget *Widget, int Index, tAxWin3_Colour Colour);
+// --- Inspection
+extern char *AxWin3_Widget_GetText(tAxWin3_Widget *Widget);
+
+enum eElementTypes
+{
+ ELETYPE_NONE,
+
+ ELETYPE_SUBWIN,
+
+ ELETYPE_BOX, //!< Content box (invisible in itself)
+ ELETYPE_TEXT, //!< Text
+ ELETYPE_IMAGE, //!< Image
+ ELETYPE_BUTTON, //!< Push Button
+ ELETYPE_SPACER, //!< Visual Spacer (horizontal / vertical rule)
+ ELETYPE_TEXTINPUT, //!< Text Input Field
+ ELETYPE_TEXTBOX, //!< Text Box Input
+
+ ELETYPE_TABBAR, //!< Tab Bar
+ ELETYPE_TOOLBAR, //!< Tool Bar
+
+ NUM_ELETYPES
+};
+
+enum eElementFlags
+{
+ /**
+ * \brief Rendered
+ *
+ * If set, the element will be ignored in calculating sizes and
+ * rendering.
+ */
+ ELEFLAG_NORENDER = 0x001,
+ /**
+ * \brief Element visibility
+ *
+ * If set, the element is not drawn (but still is used for size calculations)
+ */
+ ELEFLAG_INVISIBLE = 0x002,
+
+ /**
+ * \brief Position an element absulutely (ignored in size calcs)
+ */
+ ELEFLAG_ABSOLUTEPOS = 0x004,
+
+ /**
+ * \brief Fixed size element
+ */
+ ELEFLAG_FIXEDSIZE = 0x008,
+
+ /**
+ * \brief Element "orientation"
+ *
+ * Vertical means that the children of this element are stacked,
+ * otherwise they list horizontally
+ */
+ ELEFLAG_VERTICAL = 0x010,// ELEFLAG_HORIZONTAL = 0x000,
+ /**
+ * \brief Action for text that overflows
+ */
+ ELEFLAG_WRAP = 0x020,// ELEFLAG_NOWRAP = 0x000,
+ /**
+ * \brief Cross size action
+ *
+ * If this flag is set, the element will only be as large (across
+ * its parent) as is needed to encase the contents of the element.
+ * Otherwise, the element will expand to fill all avaliable space.
+ */
+ ELEFLAG_NOEXPAND = 0x040,
+
+ /**
+ * \brief With (length) size action
+ * If this flag is set, the element will only be as large as
+ * is required along it's parent
+ */
+ ELEFLAG_NOSTRETCH = 0x080,
+
+ /**
+ * \brief Center alignment
+ */
+ ELEFLAG_ALIGN_CENTER= 0x100,
+ /**
+ * \brief Right/Bottom alignment
+ *
+ * If set, the element aligns to the end of avaliable space (instead
+ * of the beginning)
+ */
+ ELEFLAG_ALIGN_END = 0x200
+};
+
+
+#endif
+
ASFLAGS +=\r
LDFLAGS += -soname libc.so -Map map.txt -lgcc\r
\r
+INCFILES := stdio.h stdlib.h\r
+\r
OBJ = stub.o heap.o stdlib.o env.o fileIO.o string.o select.o rand.o\r
+OBJ += perror.o\r
OBJ += arch/$(ARCHDIR).ao\r
# signals.o\r
DEPFILES := $(OBJ:%.o=%.d)\r
\r
include ../Makefile.tpl\r
\r
-#all: $(OUTPUTDIR)Libs/crt0.o\r
-\r
-# C Runtime 0\r
-#$(OUTPUTDIR)Libs/crt0.o: crt0.asm\r
-# @echo --- $(AS) -o $@\r
-# @$(AS) $(ASFLAGS) -o $@ $<\r
--- /dev/null
+@
+@ Acess2 C Library
+@ - By John Hodge (thePowersGang)
+@
+@ arch/armv6.S
+@ - ARMv6 specific code
+.globl setjmp
+setjmp:
+ @ RO: Buffer
+ stm r0, {r0-r14}
+ eor r0, r0
+ mov pc, lr
+
+.globl longjmp
+longjmp:
+ @ R0: Buffer
+ @ R1: Value
+ add r0, #8
+ ldm r0, {r2-r14}
+ mov r0, r1
+ tst r0, r0
+ addeq r0, #1
+ mov pc, lr @ Will return to after setjmp
+
///\todo Implement\r
}\r
\r
+EXPORT void clearerr(FILE *stream)\r
+{\r
+ /// \todo Impliment\r
+}\r
+\r
+EXPORT int feof(FILE *stream)\r
+{\r
+ return 0; //stream->; // ?\r
+}\r
+\r
+EXPORT int ferror(FILE *stream)\r
+{\r
+ return 0;\r
+}\r
+EXPORT int fileno(FILE *stream)\r
+{\r
+ return stream->FD;\r
+}\r
+\r
EXPORT off_t ftell(FILE *fp)\r
{\r
if(!fp || !fp->FD) return -1;\r
{\r
va_list tmpList;\r
int size;\r
- char sbuf[1024];\r
- char *buf = sbuf;\r
\r
if(!fp || !format) return -1;\r
\r
va_copy(tmpList, args);\r
\r
- size = vsnprintf(sbuf, sizeof(sbuf), (char*)format, tmpList);\r
- \r
- if( size >= sizeof(sbuf) )\r
- {\r
- buf = (char*)malloc(size+1);\r
- if(!buf) {\r
- WRITE_STR(_stdout, "vfprintf ERROR: malloc() failed");\r
- return 0;\r
- }\r
- buf[size] = '\0';\r
- \r
- // Print\r
- vsnprintf(buf, size+1, (char*)format, args);\r
- }\r
+ size = vsnprintf(NULL, 0, (char*)format, tmpList);\r
+ char buf[size+1];\r
+ vsnprintf(buf, size+1, (char*)format, args);\r
\r
// Write to stream\r
write(fp->FD, buf, size);\r
{\r
#if 1\r
int size;\r
- char sbuf[1024];\r
- char *buf = sbuf;\r
va_list args;\r
\r
// Get final size\r
va_start(args, format);\r
- size = vsnprintf(sbuf, 1024, (char*)format, args);\r
+ size = vsnprintf(NULL, 0, (char*)format, args);\r
+ va_end(args);\r
+ char buf[size+1];\r
+ // Fill Buffer\r
+ va_start(args, format);\r
+ vsnprintf(buf, size+1, (char*)format, args);\r
va_end(args);\r
- \r
- if( size >= 1024 ) {\r
- // Allocate buffer\r
- buf = (char*)malloc(size+1);\r
- if(buf) {\r
- WRITE_STR(_stdout, "PRINTF ERROR: malloc() failed\n");\r
- return 0;\r
- }\r
- buf[size] = '\0';\r
- \r
- // Fill Buffer\r
- va_start(args, format);\r
- vsnprintf(buf, size+1, (char*)format, args);\r
- va_end(args);\r
- }\r
\r
// Send to stdout\r
write(_stdout, buf, size+1);\r
#include <string.h>\r
#include "lib.h"\r
\r
+#if 0\r
+# define DEBUGS(s...) _SysDebug(s)\r
+#else\r
+# define DEBUGS(s...) do{}while(0)\r
+#endif\r
+\r
// === Constants ===\r
#define MAGIC 0xACE55051 //AcessOS1\r
#define MAGIC_FREE (~MAGIC)\r
typedef struct {\r
uint32_t magic;\r
size_t size;\r
+ char data[];\r
} heap_head;\r
typedef struct {\r
heap_head *header;\r
LOCAL void *extendHeap(int bytes);\r
static void *FindHeapBase();\r
LOCAL uint brk(uintptr_t newpos);\r
+LOCAL void Heap_Dump(void);\r
\r
//Code\r
\r
size_t closestMatch = 0;\r
void *bestMatchAddr = 0;\r
heap_head *curBlock;\r
- \r
+\r
// _SysDebug("&_heap_start = %p, _heap_start = %p", &_heap_start, _heap_start);\r
// Initialise Heap\r
if(_heap_start == NULL)\r
else if(curBlock->magic != MAGIC)\r
{\r
//Corrupt Heap\r
+ Heap_Dump();\r
_SysDebug("malloc: Corrupt Heap\n");\r
return NULL;\r
}\r
return NULL;\r
}\r
curBlock->magic = MAGIC;\r
- return (void*)((uintptr_t)curBlock + sizeof(heap_head));\r
+ DEBUGS("malloc(0x%x) = %p (extend) 0x%x", bytes, curBlock->data, bestSize);\r
+ return curBlock->data;\r
}\r
\r
+ heap_head *besthead = (void*)bestMatchAddr;\r
+ \r
//Split Block?\r
if(closestMatch - bestSize > BLOCK_SIZE) {\r
heap_foot *foot;\r
foot = (heap_foot*)(bestMatchAddr + closestMatch - sizeof(heap_foot));\r
foot->header = curBlock;\r
\r
- ((heap_head*)bestMatchAddr)->magic = MAGIC; //mark as used\r
- return (void*)(bestMatchAddr + sizeof(heap_head));\r
+ besthead->magic = MAGIC; //mark as used\r
+ DEBUGS("malloc(0x%x) = %p (split) 0x%x", bytes, besthead->data, bestSize);\r
+ return besthead->data;\r
}\r
\r
//Don't Split the block\r
- ((heap_head*)bestMatchAddr)->magic = MAGIC;\r
- return (void*)(bestMatchAddr+sizeof(heap_head));\r
+ besthead->magic = MAGIC;\r
+ DEBUGS("malloc(0x%x) = %p (reuse) 0x%x", bytes, besthead->data, besthead->size);\r
+ return besthead->data;\r
}\r
\r
/**\r
return;\r
\r
head->magic = MAGIC_FREE;\r
+ DEBUGS("free(%p) : 0x%x bytes", mem, head->size);\r
\r
//Unify Right\r
if((intptr_t)head + head->size < (intptr_t)_heap_end)\r
\r
return ret; // Return old curpos\r
}\r
+\r
+void Heap_Dump(void)\r
+{\r
+ heap_head *cur = _heap_start;\r
+ while( cur < (heap_head*)_heap_end )\r
+ {\r
+ switch( cur->magic )\r
+ {\r
+ case MAGIC:\r
+ _SysDebug("Used block %p[0x%x] - ptr=%p", cur, cur->size, cur->data);\r
+ break;\r
+ case MAGIC_FREE:\r
+ _SysDebug("Free block %p[0x%x] - ptr=%p", cur, cur->size, cur->data);\r
+ break;\r
+ default:\r
+ _SysDebug("Block %p bad magic (0x%x)", cur, cur->magic);\r
+ return ;\r
+ }\r
+ cur = (void*)( (char*)cur + cur->size );\r
+ }\r
+}\r
+\r
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * assert.h
+ * - assert(expr)
+ */
+#ifndef _LIBC__ASSERT_H_
+#define _LIBC__ASSERT_H_
+
+#ifdef NDEBUG
+# define assert(expr) do{}while(0)
+#else
+# define assert(expr) do{if(!(expr)) { fprintf(stderr, "%s:%i: Assertion '%s' failed\n", __FILE__, __LINE__, #expr); exit(-1);}}while(0)
+#endif
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * ctype.h
+ * - Type manipulation?
+ */
+#ifndef _CTYPE_H_
+#define _CTYPE_H_
+
+static inline int isalpha(int ch) {
+ if('A'<=ch&&ch<='Z') return 1;
+ if('a'<=ch&&ch<='z') return 1;
+ return 0;
+}
+static inline int isdigit(int ch) {
+ if('0'<=ch&&ch<='9') return 1;
+ return 0;
+}
+
+static inline int isalnum(int ch) {
+ return isalpha(ch) || isdigit(ch);
+}
+
+static inline int toupper(int ch) {
+ if('a'<=ch && ch <='z')
+ return ch - 'a' + 'A';
+ return ch;
+}
+
+static inline int isspace(int ch) {
+ if(ch == ' ') return 1;
+ if(ch == '\t') return 1;
+ if(ch == '\r') return 1;
+ if(ch == '\n') return 1;
+ return 0;
+}
+
+#endif
--- /dev/null
+#ifndef _ERRNO_H_
+#define _ERRNO_H_
+
+// TODO: Fully implement errno.h, make sure it matches the kernel one
+
+extern int _errno;
+#define errno _errno
+
+#define strerror(_x) "Unimplemented"
+
+enum
+{
+ EOK,
+ EINVAL,
+ ERANGE,
+ ENODEV,
+ EBADF,
+ EINTR,
+ EAGAIN,
+ ENOMEM,
+
+ EADDRNOTAVAIL,
+ EINPROGRESS,
+
+ E_LAST
+};
+
+#endif
--- /dev/null
+/*
+ * Acess2 LibC
+ * - By John Hodge (thePowersGang)
+ *
+ * setjmp.h
+ * - setjmp/longjmp support
+ */
+#ifndef _LIBC_SETJMP_H_
+#define _LIBC_SETJMP_H_
+
+#if ARCHDIR_is_x86
+typedef uint32_t jmp_buf[8];
+#elif ARCHDIR_is_x86_64
+typedef uint64_t jmp_buf[16];
+#else
+# error "Unknown Architecture"
+#endif
+
+extern int setjmp(jmp_buf buf);
+extern void longjmp(jmp_buf buf, int val);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * signal.h
+ * - POSIX Signal Emulation/Interface
+ */
+#ifndef _SIGNAL_H_
+#define _SIGNAL_H_
+
+#define SIG_DFL ((void*)0)
+#define SIG_ERR ((void*)-1)
+
+#define SIGABRT 6
+
+#define SIGPIPE 1001
+#define SIGCHLD 1002
+
+#endif
+
--- /dev/null
+/*
+ * AcessOS LibC
+ * stdlib.h
+ */
+#ifndef __STDIO_H
+#define __STDIO_H
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+/* === Types === */
+typedef struct sFILE FILE;
+
+/* === CONSTANTS === */
+#define EOF (-1)
+#define BUFSIZ 1024
+
+/* --- Standard IO --- */
+extern int printf(const char *format, ...);
+extern int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args);
+extern int vsprintf(char *buf, const char *format, va_list args);
+extern int sprintf(char *buf, const char *format, ...);
+extern int snprintf(char *buf, size_t maxlen, const char *format, ...);
+extern void perror(const char *s);
+
+extern FILE *fopen(const char *file, const char *mode);
+extern FILE *freopen(const char *file, const char *mode, FILE *fp);
+extern FILE *fdopen(int fd, const char *modes);
+extern int fclose(FILE *fp);
+extern void fflush(FILE *fp);
+extern off_t ftell(FILE *fp);
+extern int fseek(FILE *fp, long int amt, int whence);
+extern void clearerr(FILE *stream);
+extern int feof(FILE *stream);
+extern int ferror(FILE *stream);
+extern int fileno(FILE *stream);
+
+extern size_t fread(void *buf, size_t size, size_t n, FILE *fp);
+extern size_t fwrite(void *buf, size_t size, size_t n, FILE *fp);
+extern int fgetc(FILE *fp);
+extern int fputc(int ch, FILE *fp);
+extern int getchar(void);
+extern int putchar(int ch);
+
+extern int fprintf(FILE *fp, const char *format, ...);
+extern int vfprintf(FILE *fp, const char *format, va_list args);
+
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+
+#endif
+
--- /dev/null
+/*\r
+ * AcessOS LibC\r
+ * stdlib.h\r
+ */\r
+#ifndef __STDLIB_H\r
+#define __STDLIB_H\r
+\r
+#include <stddef.h>\r
+#include <stdarg.h>\r
+#include <sys/types.h>\r
+\r
+#define EXIT_FAILURE 1\r
+#define EXIT_SUCCESS 0\r
+\r
+/* --- Spinlock Macros --- */\r
+/* TODO: Support non-x86 architectures */\r
+#define DEFLOCK(_name) static int _spinlock_##_name=0;\r
+#define LOCK(_name) do{int v=1;while(v){__asm__ __volatile__("lock cmpxchgl %0, (%1)":"=a"(v):"D"((&_spinlock_##_name)),"a"(1));yield();}}while(0)\r
+#define UNLOCK(_name) __asm__ __volatile__("lock andl $0, (%0)"::"D"(&_spinlock_##_name))\r
+\r
+/* --- StdLib --- */\r
+extern void _exit(int code) __attribute__((noreturn)); /* NOTE: Also defined in acess/sys.h */\r
+extern long long strtoll(const char *ptr, char **end, int base);\r
+extern long strtol(const char *ptr, char **end, int base);\r
+extern int atoi(const char *ptr);\r
+extern void exit(int status) __attribute__((noreturn));\r
+extern void atexit(void (*__func)(void));\r
+extern void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));\r
+extern int abs(int j);\r
+extern long int labs(long int j);\r
+extern long long int llabs(long long int j);\r
+\r
+/* --- Environment --- */\r
+extern char *getenv(const char *name);\r
+\r
+/* --- Heap --- */\r
+extern void free(void *mem);\r
+extern void *malloc(size_t bytes);\r
+extern void *calloc(size_t __nmemb, size_t __size);\r
+extern void *realloc(void *__ptr, size_t __size);\r
+extern int IsHeap(void *ptr);\r
+\r
+/* --- Random --- */\r
+extern void srand(unsigned int seed);\r
+extern int rand(void);\r
+extern int rand_p(unsigned int *seedp);\r
+\r
+#ifndef SEEK_CUR\r
+# define SEEK_CUR 0\r
+# define SEEK_SET 1\r
+# define SEEK_END (-1)\r
+#endif\r
+\r
+#endif\r
--- /dev/null
+/*
+ * AcessOS LibC
+ * string.h
+ */
+#ifndef __STRING_H
+#define __STRING_H
+
+#include <stddef.h>
+
+/* Strings */
+extern size_t strlen(const char *string);
+extern size_t strnlen(const char *string, size_t maxlen);
+extern int strcmp(const char *str1, const char *str2);
+extern int strncmp(const char *str1, const char *str2, size_t maxlen);
+extern int strcasecmp(const char *s1, const char *s2);
+extern int strncasecmp(const char *s1, const char *s2, size_t maxlen);
+extern char *strcpy(char *dst, const char *src);
+extern char *strncpy(char *dst, const char *src, size_t num);
+extern char *strcat(char *dst, const char *src);
+extern char *strdup(const char *src);
+extern char *strndup(const char *src, size_t length);
+extern char *strchr(const char *str, int character);
+extern char *strrchr(const char *str, int character);
+extern char *strstr(const char *str1, const char *str2);
+extern size_t strcspn(const char *haystack, const char *reject);
+extern size_t strspn(const char *haystack, const char *accept);
+
+/* Memory */
+extern void *memset(void *dest, int val, size_t count);
+extern void *memcpy(void *dest, const void *src, size_t count);
+extern void *memmove(void *dest, const void *src, size_t count);
+extern int memcmp(const void *mem1, const void *mem2, size_t count);
+extern void *memchr(const void *ptr, int value, size_t num);
+
+#endif
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * time.h
+ * - POSIX time functions
+ */
+#ifndef _TIME_H_
+#define _TIME_H_
+
+#include <acess/intdefs.h>
+#include <sys/types.h> // time_t
+
+struct tm
+{
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year; // 1900 based
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+};
+
+#define CLOCKS_PER_SEC 1000
+
+typedef signed long long clock_t;
+
+extern clock_t clock();
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 C Library
+ * - By John Hodge (thePowersGang)
+ *
+ * perror.c
+ * - perror() and friends
+ */
+#include <errno.h>
+#include <stdio.h>
+
+void perror(const char *s)
+{
+ fprintf(stderr, "%s: Error (%i)\n", s, errno);
+}
# Variables
SRCS := stub.c heap.c stdlib.c env.c fileIO.c string.c select.c
+SRCS += perror.c
SRCS += arch/$(ARCHDIR).$(ASSUFFIX)
# signals.c
BIN := $(OUTPUTDIR)Libs/libc.so
* AcessOS Basic C Library\r
* stdlib.c\r
*/\r
-/**\r
- * \todo Move half of these to stdio\r
- */\r
#include <acess/sys.h>\r
#include <stdlib.h>\r
#include <stdio.h>\r
+#include <errno.h>\r
+#include <ctype.h>\r
+#include <limits.h>\r
#include "lib.h"\r
\r
#define _stdout 1\r
}\r
}\r
\r
-/**\r
- * \fn EXPORT int atoi(const char *str)\r
- * \brief Convert a string to an integer\r
- */\r
-EXPORT int atoi(const char *str)\r
+EXPORT long long strtoll(const char *str, char **end, int base)\r
{\r
int neg = 0;\r
- int ret = 0;\r
- \r
- // NULL Check\r
- if(!str) return 0;\r
+ long long ret = 0;\r
\r
- while(*str == ' ' || *str == '\t') str++;\r
+ if( !str || base < 0 || base > 36 || base == 1 ) {\r
+ if(end)\r
+ *end = (char*)str;\r
+ errno = EINVAL;\r
+ return 0;\r
+ }\r
+\r
+ while( isspace(*str) )\r
+ str++;\r
\r
- // Check for negative\r
- if(*str == '-') {\r
- neg = 1;\r
+ // Check for negative (or positive) sign\r
+ if(*str == '-' || *str == '+') {\r
+ neg = (*str == '-');\r
str++;\r
}\r
\r
- if(*str == '0') {\r
+ if( base == 0 || base == 16 ) {\r
+ if( *str == '0' && str[1] == 'x' ) {\r
+ str += 2;\r
+ base = 16;\r
+ }\r
+ }\r
+ \r
+ if( base == 0 && *str == '0' ) {\r
str ++;\r
- if(*str == 'x') {\r
- str++;\r
- // Hex\r
- while( ('0' <= *str && *str <= '9')\r
- || ('A' <= *str && *str <= 'F' )\r
- || ('a' <= *str && *str <= 'f' )\r
- )\r
- {\r
- ret *= 16;\r
- if(*str <= '9') {\r
- ret += *str - '0';\r
- } else if (*str <= 'F') {\r
- ret += *str - 'A' + 10;\r
- } else {\r
- ret += *str - 'a' + 10;\r
- }\r
- str++;\r
- }\r
- } else {\r
- // Octal\r
- while( '0' <= *str && *str <= '7' )\r
- {\r
- ret *= 8;\r
- ret += *str - '0';\r
- str++;\r
- }\r
+ base = 8;\r
+ }\r
+\r
+ if( base == 0 )\r
+ base = 10;\r
+\r
+ while( *str )\r
+ {\r
+ int next = -1;\r
+ if( base <= 10 ) {\r
+ if( '0' <= *str && *str <= '0'+base-1 )\r
+ next = *str - '0';\r
}\r
- } else {\r
- // Decimal\r
- while( '0' <= *str && *str <= '9' )\r
- {\r
- ret *= 10;\r
- ret += *str - '0';\r
- str++;\r
+ else {\r
+ if( '0' <= *str && *str <= '9' )\r
+ next = *str - '0';\r
+ if( 'A' <= *str && *str <= 'A'+base-10-1 )\r
+ next = *str - 'A';\r
+ if( 'a' <= *str && *str <= 'a'+base-10-1 )\r
+ next = *str - 'a';\r
}\r
+ if( next < 0 )\r
+ break;\r
+ ret *= base;\r
+ ret += next;\r
+ str ++;\r
}\r
- \r
- // Negate if needed\r
- if(neg) ret = -ret;\r
+\r
+ if( neg )\r
+ ret = -ret; \r
+\r
+ if(end)\r
+ *end = (char*)str;\r
return ret;\r
}\r
+\r
+EXPORT long strtol(const char *str, char **end, int base)\r
+{\r
+ long long tmp = strtoll(str, end, base);\r
+ if( tmp > LONG_MAX || tmp < LONG_MIN ) {\r
+ errno = ERANGE;\r
+ return (tmp > LONG_MAX) ? LONG_MAX : LONG_MIN;\r
+ }\r
+ return tmp;\r
+}\r
+\r
+/**\r
+ * \fn EXPORT int atoi(const char *str)\r
+ * \brief Convert a string to an integer\r
+ */\r
+EXPORT int atoi(const char *str)\r
+{\r
+ long long tmp = strtoll(str, NULL, 0);\r
+ if( tmp > INT_MAX || tmp < INT_MIN ) {\r
+ errno = ERANGE;\r
+ return (tmp > INT_MAX) ? INT_MAX : INT_MIN;\r
+ }\r
+ return tmp;\r
+}\r
+\r
+int abs(int j) { return j < 0 ? -j : j; }\r
+long int labs(long int j) { return j < 0 ? -j : j; }\r
+\r
char *sp = (char *)src;
char *dp = (char *)dest;
// Check if the areas overlap
- if( (intptr_t)dest > (intptr_t)src && (intptr_t)dest < (intptr_t)src+count )
- for(;count--;) dp[count] = sp[count];
+ if( (intptr_t)src < (intptr_t)dest && (intptr_t)dest < (intptr_t)src+count )
+ for(;count--;)
+ dp[count] = sp[count];
else
- for(;count--;) *dp++ = *sp++;
+ memcpy(dest, src, count);
return dest;
}
--- /dev/null
+/*
+ */
+#ifndef _IMAGE_H_
+#define _IMAGE_H_
+
+// === TYPES ===
+typedef struct sImage tImage;
+struct sImage
+{
+ short Width;
+ short Height;
+ int Format;
+ uint8_t Data[];
+};
+
+// === CONSTANTS ===
+enum eImageFormats
+{
+ IMGFMT_BGRA,
+ IMGFMT_RGB,
+ NUM_IMGFMTS
+};
+
+#endif
CFLAGS += -Wall
LDFLAGS += -lc -soname libnet.so
-OBJ = main.o address.o
+OBJ = main.o address.o socket.o
BIN = libnet.so
include ../Makefile.tpl
--- /dev/null
+/*
+ * Acess2 Common Networking Library
+ * By John Hodge (thePowersGang)
+ */
+
+#ifndef __LIBNET_H_
+#define __LIBNET_H_
+
+enum {
+ NET_ADDRTYPE_NULL = 0,
+ NET_ADDRTYPE_IPV4 = 4,
+ NET_ADDRTYPE_IPV6 = 6
+};
+
+/**
+ * \brief Parse a string as an IP Address
+ * \param String Input string
+ * \param Addr Output binary format of the address
+ * \return Address family (0: Invalid, 4: IPv4, 6: IPv6)
+ */
+extern int Net_ParseAddress(const char *String, void *Addr);
+
+/**
+ * \brief Convert a network address into a string
+ * \param AddressType Address family as returned by Net_ParseAddress
+ * \param Address Address data
+ */
+extern const char *Net_PrintAddress(int AddressType, void *Address);
+
+/**
+ * \brief Get the size in bytes of an address type
+ * \param AddressType Address type returned by Net_ParseAddress
+ * \return Size of an address in bytes
+ */
+extern int Net_GetAddressSize(int AddressType);
+
+/**
+ * \brief Get the interface required to reach \a Addr
+ * \param AddrType Addresss Family (4: IPv4, 6: IPv6)
+ * \param Addr Address in binary format
+ * \return Interface number
+ */
+extern char *Net_GetInterface(int AddrType, void *Addr);
+
+/**
+ * \brief Open a network socket file
+ * \param AddrType Address family
+ * \param Addr Binary address
+ * \param SocketName Socket type to open (e.g. tcpc for TCP client)
+ * If NULL, the node directory is opened
+ * \return Socket file descriptor (as returned by \a open), or -1 on error
+ *
+ * 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_TCPC(int AddrType, void *Addr, int Port);
+
+#endif
}
}
-int Net_OpenSocket(int AddrType, 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]);
-
- if(Filename)
- {
- int len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
- char path[len+1];
- snprintf(path, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
- return open(path, OPENFLAG_READ|OPENFLAG_WRITE);
- }
- else
- {
- int len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
- char path[len+1];
- snprintf(path, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
- return open(path, OPENFLAG_READ);
- }
-}
-
//TODO: Move out to another file
char *Net_GetInterface(int AddressType, void *Address)
{
// Open
fd = open("/Devices/ip/routes", 0);
if( !fd ) {
- fprintf(stderr, "ERROR: It seems that '/Devices/ip/routes' does not exist, are you running Acess2?\n");
+ fprintf(stderr, "ERROR: Unable to open '/Devices/ip/routes'\n");
return NULL;
}
// Open route
fd = open(buf, 0);
if( fd == -1 ) {
- fprintf(stderr, "Net_GetInterface - ERROR: Unabel to open %s\n", buf);
+ fprintf(stderr, "Net_GetInterface - ERROR: Unable to open %s\n", buf);
return NULL; // Shouldn't happen :/
}
+++ /dev/null
-/*
- * Acess2 Common Networking Library
- * By John Hodge (thePowersGang)
- */
-
-#ifndef __LIBNET_H_
-#define __LIBNET_H_
-
-enum {
- NET_ADDRTYPE_NULL = 0,
- NET_ADDRTYPE_IPV4 = 4,
- NET_ADDRTYPE_IPV6 = 6
-};
-
-/**
- * \brief Parse a string as an IP Address
- * \param String Input string
- * \param Addr Output binary format of the address
- * \return Address family (0: Invalid, 4: IPv4, 6: IPv6)
- */
-extern int Net_ParseAddress(const char *String, void *Addr);
-
-/**
- * \brief Convert a network address into a string
- * \param AddressType Address family as returned by Net_ParseAddress
- * \param Address Address data
- */
-extern const char *Net_PrintAddress(int AddressType, void *Address);
-
-/**
- * \brief Get the size in bytes of an address type
- * \param AddressType Address type returned by Net_ParseAddress
- * \return Size of an address in bytes
- */
-extern int Net_GetAddressSize(int AddressType);
-
-/**
- * \brief Get the interface required to reach \a Addr
- * \param AddrType Addresss Family (4: IPv4, 6: IPv6)
- * \param Addr Address in binary format
- * \return Interface number
- */
-extern char *Net_GetInterface(int AddrType, void *Addr);
-
-/**
- * \brief Open a network socket file
- * \param AddrType Address family
- * \param Addr Binary address
- * \param SocketName Socket type to open (e.g. tcpc for TCP client)
- * If NULL, the node directory is opened
- * \return Socket file descriptor (as returned by \a open), or -1 on error
- *
- * Opens a file using /Devices/ip/routes/@<AddrType>:<Addr>/<SocketName>
- *
- */
-extern int Net_OpenSocket(int AddrType, void *Addr, const char *SocketName);
-
-#endif
--- /dev/null
+/*
+ * Acess2 Networking Toolkit
+ * By John Hodge (thePowersGang)
+ *
+ * socket.c
+ * -
+ */
+#include <net.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <acess/sys.h>
+
+int Net_OpenSocket(int AddrType, 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]);
+
+ if(Filename)
+ {
+ int len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
+ char path[len+1];
+ snprintf(path, 100, "/Devices/ip/routes/@%i:%s/%s", AddrType, hexAddr, Filename);
+ _SysDebug("%s", path);
+ return open(path, OPENFLAG_READ|OPENFLAG_WRITE);
+ }
+ else
+ {
+ int len = snprintf(NULL, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
+ char path[len+1];
+ snprintf(path, 100, "/Devices/ip/routes/@%i:%s", AddrType, hexAddr);
+ return open(path, OPENFLAG_READ);
+ }
+}
+
+int Net_OpenSocket_TCPC(int AddrType, void *Addr, int Port)
+{
+ int fd = Net_OpenSocket(AddrType, Addr, "tcpc");
+ if( fd == -1 ) return -1;
+
+ ioctl(fd, 5, &Port); // Remote Port
+ ioctl(fd, 6, Addr); // Remote address
+ ioctl(fd, 7, NULL); // connect
+ return fd;
+}
+
--- /dev/null
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * dirent.h
+ * - Directory Reading
+ */
+#ifndef _LIBPOSIX__SYS__DIRENT_H_
+#define _LIBPOSIX__SYS__DIRENT_H_
+
+#define NAME_MAX 255
+
+struct dirent
+{
+ ino_t d_ino;
+ char d_name[NAME_MAX+1];
+};
+
+typedef struct DIR_s DIR;
+
+extern int closedir(DIR *);
+extern DIR *opendir(const char *);
+extern struct dirent *readdir(DIR *);
+extern int readdir_r(DIR *, struct dirent *, struct dirent **);
+extern void rewinddir(DIR *);
+extern void seekdir(DIR *, long int);
+extern long int telldir(DIR *);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 C Library (UNIX Emulation)
+ * - By John Hodge (thePowersGang)
+ *
+ * fcntl.h
+ * - ??
+ */
+
+#ifndef _FCNTL_H_
+#define _FCNTL_H_
+
+#include <sys/sys.h>
+
+// Hacks to handle different behaviors in Acess
+
+// Open doesn't take a chmod
+#define open(_1,_2,...) open(_1, _2)
+
+// Close returns void
+#define close(_1) (close(_1),0)
+
+// Acess doesn't implement lseek
+#define lseek(_1,_2,_3) (seek(_1,_2,_3),tell(_1))
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * grp.h
+ * - Group Management
+ */
--- /dev/null
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * pwd.h
+ * - Password Structure
+ */
+#ifndef _LIBPOSIX__PWD_H_
+#define _LIBPOSIX__PWD_H_
+
+#include <sys/types.h> // gid_t/uid_t
+
+struct passwd
+{
+ char *pw_name;
+ uid_t pw_uid;
+ gid_t pw_gid;
+ char *pw_dir;
+ char *pw_shell;
+};
+
+extern struct passwd *getpwnam(const char *);
+extern struct passwd *getpwuid(uid_t);
+extern int getpwnam_r(const char *, struct passwd *, char *, size_t, struct passwd **);
+extern int getpwuid_r(uid_t, struct passwd *, char *, size_t, struct passwd **);
+extern void endpwent(void);
+extern struct passwd *getpwent(void);
+extern void setpwent(void);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/resource.h
+ * - (XSI) Resource Operations
+ */
+#ifndef _LIBPOSIX__SYS__RESOURCE_H_
+#define _LIBPOSIX__SYS__RESOURCE_H_
+
+#include <sys/time.h> // struct timeval
+
+// (get|set)priority(which)
+enum
+{
+ PRIO_PROCESS,
+ PRIO_PGRP,
+ PRIO_USER
+};
+
+typedef unsigned int rlim_t;
+#define RLIM_INFINITY -1
+#define RLIM_SAVED_MAX -2
+#define RLIM_SAVED_CUR -3
+
+struct rlimit
+{
+ rlim_t rlim_cur;
+ rlim_t rlim_max;
+};
+
+struct rusage
+{
+ struct timeval ru_time;
+ struct timeval ru_stime;
+};
+
+extern int getpriority(int, id_t);
+extern int getrlimit(int, struct rlimit *);
+extern int getrusage(int, struct rusage *);
+extern int setpriority(int, id_t, int);
+extern int setrlimit(int, const struct rlimit *);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/time.h
+ * - Timing calls
+ */
+#ifndef _LIBPOSIX__SYS__TIME_H_
+#define _LIBPOSIX__SYS__TIME_H_
+
+typedef unsigned long suseconds_t;
+
+struct timeval
+{
+ time_t tv_sec;
+ suseconds_t tv_usec;
+};
+
+struct itimerval
+{
+ struct timeval it_interval;
+ struct timeval it_value;
+};
+
+// TODO: This should also define fd_set and select()
+
+extern int getitimer(int, struct itimerval *);
+extern int setitimer(int, const struct itimerval *, struct itimerval *);
+extern int gettimeofday(struct timeval *, void *);
+// select
+extern int utimes(const char *, const struct timeval [2]);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/wait.h
+ * - Waiting
+ */
+#ifndef _LIBPOSIX__SYS__WAIT_H_
+#define _LIBPOSIX__SYS__WAIT_H_
+
+// POSIX, waitpid()
+#define WNOHANG 0x01
+#define WUNTRACED 0x02
+
+// POSIX, status values
+#define WEXITSTATUS(v) v
+#define WIFCONTINUED(v) 0
+
+// POSIX/XSI, waitid(options)
+#define WEXITED 0x10
+#define WSTOPPED 0x20
+#define WCONTINUED 0x40
+#define WNOWAIT 0x80
+
+// POSIX/XSI, idtype_t
+typedef enum
+{
+ P_ALL,
+ P_PID,
+ P_PGID
+} idtype_t;
+
+// POSIX
+extern pid_t wait(int *);
+// POSIX/XSI
+//extern int waitid(idtype_t, id_t, siginfo_t *, int);
+// POSIX
+extern pid_t waitpid(pid_t, int *, int);
+
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * syslog.h
+ * - Centra Loggin
+ */
+#ifndef _LIBPOSIX__SYSLOG_H_
+#define _LIBPOSIX__SYSLOG_H_
+
+// openlog(logopt)
+#define LOG_PID 0x01
+#define LOG_CONS 0x02
+#define LOG_NDELAY 0x04
+#define LOG_ODELAY 0x08
+#define LOG_NOWAIT 0x10
+
+// openlog(facility)
+enum {
+ LOG_KERN,
+ LOG_USER,
+ LOG_MAIL,
+ LOG_NEWS,
+ LOG_UUCP,
+ LOG_DAEMON,
+ LOG_AUTH,
+ LOG_CRON,
+ LOG_LPR,
+ LOG_LOCAL0,
+ LOG_LOCAL1,
+ LOG_LOCAL2,
+ LOG_LOCAL3,
+ LOG_LOCAL4,
+ LOG_LOCAL5,
+ LOG_LOCAL6,
+ LOG_LOCAL7
+};
+
+// setlogmask(maskpri)
+#define LOG_MASK(pri) pri
+
+// syslog(priority)
+enum {
+ LOG_EMERG,
+ LOG_ALERT,
+ LOG_CRIT,
+ LOG_ERR,
+ LOG_WARNING,
+ LOG_NOTICE,
+ LOG_INFO,
+ LOG_DEBUG
+};
+
+extern void closelog(void);
+extern void openlog(const char *, int, int);
+extern int setlogmask(int);
+extern void syslog(int, const char *, ...);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * termios.h
+ * - Terminal Control
+ */
+#ifndef _LIBPOSIX__TERMIOS_H_
+#define _LIBPOSIX__TERMIOS_H_
+
+typedef unsigned char cc_t;
+typedef unsigned long speed_t;
+typedef unsigned short tcflag_t;
+
+enum {
+ VEOF,
+ VEOL,
+ VERASE,
+ VINTR,
+ VKILL,
+ VMIN,
+ VQUIT,
+ VSTART,
+ VSTOP,
+ VSUSP,
+ VTIME,
+ NCCS
+};
+
+struct termios
+{
+ tcflag_t c_iflag;
+ tcflag_t c_oflag;
+ tcflag_t c_cflag;
+ tcflag_t c_lflag;
+ cc_t c_cc[NCCS];
+};
+
+#endif
+
--- /dev/null
+# Acess 2 - POSIX Sockets
+
+include ../Makefile.cfg
+
+CPPFLAGS +=
+CFLAGS += -Wall
+LDFLAGS += -lc -soname libpsocket.so -lnet
+
+OBJ = main.o getaddrinfo.o socket.o
+BIN = libpsocket.so
+
+include ../Makefile.tpl
--- /dev/null
+/*
+ * Acess2 POSIX Sockets Library
+ * - By John Hodge (thePowersGang)
+ *
+ * getaddrinfo.c
+ * - getaddrinfo/freeaddrinfo/getnameinfo/gai_strerror
+ */
+#include <netdb.h>
+#include <netinet/in.h>
+#include <net.h> // Net_ParseAddress
+#include <stdlib.h> // malloc
+#include <string.h> // memcpy
+#include <acess/sys.h>
+
+// === CODE ===
+int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
+{
+ static const struct addrinfo defhints = {.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG};
+ struct addrinfo *ret = NULL;
+
+ // Error checks
+ if( !node && !service ) return EAI_NONAME;
+
+ if( !hints )
+ hints = &defhints;
+
+ if( !node )
+ {
+ if( !(hints->ai_flags & AI_PASSIVE) )
+ ; // Use localhost
+ else
+ ; // Use wildcard
+ }
+ else
+ {
+ // 1. Check if the node is an IP address
+ // TODO: Break this function out into inet_pton?
+ {
+ int type;
+ char addrdata[16];
+ type = Net_ParseAddress(node, addrdata);
+ switch(type)
+ {
+ case 0:
+ 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 );
+ break;
+ default:
+ _SysDebug("getaddrinfo: Unknown address family %i", type);
+ return 1;
+ }
+ }
+
+ // 2. Check for a DNS name
+ // - No luck with above, and hints->ai_flags doesn't have AI_NUMERICHOST set
+ if( !ret && !(hints->ai_flags & AI_NUMERICHOST) )
+ {
+ // TODO: DNS Lookups
+ // ? /Acess/Conf/Nameservers
+ // ? /Acess/Conf/Hosts
+ }
+
+ // 3. No Match, chuck sad
+ if( !ret )
+ {
+ return EAI_NONAME;
+ }
+ }
+
+ int default_socktype = 0;
+ int default_protocol = 0;
+ int default_port = 0;
+
+ // Convert `node` into types
+ if( service )
+ {
+ // TODO: Read something like /Acess/Conf/services
+ }
+
+ struct addrinfo *ai;
+ for( ai = ret; ai; ai = ai->ai_next)
+ {
+ struct sockaddr_in *in = (void*)ai->ai_addr;
+ struct sockaddr_in6 *in6 = (void*)ai->ai_addr;
+
+ // Check ai_socktype/ai_protocol
+ // TODO: Do both of these need to be zero for defaults to apply?
+ if( ai->ai_socktype == 0 )
+ ai->ai_socktype = default_socktype;
+ if( ai->ai_protocol == 0 )
+ ai->ai_protocol = default_protocol;
+
+ switch(ai->ai_family)
+ {
+ case AF_INET:
+ if( in->sin_port == 0 )
+ in->sin_port = default_port;
+ break;
+ case AF_INET6:
+ if( in6->sin6_port == 0 )
+ in6->sin6_port = default_port;
+ break;
+ default:
+ _SysDebug("getaddrinfo: Unknown address family %i (setting port)", ai->ai_family);
+ return 1;
+ }
+ }
+
+ *res = ret;
+ return 0;
+}
+
+void freeaddrinfo(struct addrinfo *res)
+{
+
+}
+
+const char *gai_strerror(int errnum)
+{
+ switch(errnum)
+ {
+ case EAI_SUCCESS: return "No error";
+ case EAI_FAIL: return "Permanent resolution failure";
+ default: return "UNKNOWN";
+ }
+}
+
--- /dev/null
+/*
+ * Acess2 POSIX Sockets Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * arpa/inet.h
+ * -
+ */
+#ifndef _LIBPSOCKET__ARPA__INET_H_
+#define _LIBPSOCKET__ARPA__INET_H_
+
+#include <netinet/in.h>
+#include <stdint.h> // Should be inttypes.h?
+
+extern uint32_t htonl(uint32_t hostlong);
+extern uint16_t htons(uint16_t hostshort);
+extern uint32_t ntohl(uint32_t netlong);
+extern uint16_t ntohs(uint16_t netshort);
+
+extern in_addr_t inet_addr(const char *cp);
+extern in_addr_t inet_lnaof(struct in_addr in);
+extern struct in_addr inet_makeaddr(in_addr_t net, in_addr_t lna);
+extern in_addr_t inet_netof(struct in_addr in);
+extern in_addr_t inet_network(const char *cp);
+extern char *inet_ntoa(struct in_addr in);
+
+#endif
+
--- /dev/null
+#ifndef _LIBPSOCKET__NETDB_H_
+#define _LIBPSOCKET__NETDB_H_
+
+#include <sys/socket.h>
+
+#define AI_PASSIVE 0x001
+#define AI_V4MAPPED 0x002
+#define AI_ADDRCONFIG 0x004
+#define AI_NUMERICHOST 0x008
+
+enum
+{
+ EAI_SUCCESS,
+ EAI_AGAIN,
+ EAI_BADFLAGS,
+ EAI_FAMILY,
+ EAI_SOCKTTPE,
+
+ EAI_ADDRFAMILY,
+ EAI_FAIL,
+ EAI_MEMORY,
+ EAI_NODATA,
+ EAI_NONAME,
+ EAI_SERVICE,
+ EAI_SYSTEM
+};
+
+struct addrinfo
+{
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ socklen_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct addrinfo *ai_next;
+};
+
+extern int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
+extern void freeaddrinfo(struct addrinfo *res);
+const char *gai_strerror(int errorcode);
+
+
+#endif
+
--- /dev/null
+#ifndef _LIBPSOCKET__NETINET__IN_H_
+#define _LIBPSOCKET__NETINET__IN_H_
+
+#include <stdint.h>
+
+typedef uint32_t in_addr_t;
+
+struct in_addr
+{
+ in_addr_t s_addr;
+};
+
+struct sockaddr_in
+{
+ uint16_t sin_family;
+ uint16_t sin_port;
+ struct in_addr sin_addr;
+};
+
+#define INADDR_ANY 0x00000000
+#define INADDR_BROADCAST 0xFFFFFFFF
+
+// getsockopt/setsockopt(level)
+enum {
+ IPPROTO_IP,
+ IPPROTO_ICMP,
+ IPPROTO_TCP,
+ IPPROTO_UDP
+};
+
+struct in6_addr
+{
+ unsigned char s6_addr[16];
+};
+
+struct sockaddr_in6
+{
+ uint16_t sin6_family;
+ uint16_t sin6_port;
+ uint32_t sin6_flowinfo;
+ struct in6_addr sin6_addr;
+ uint32_t sin6_scope_id;
+};
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Sockets Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/sockets.h
+ * - POSIX Sockets
+ */
+#ifndef _SYS_SOCKETS_H_
+#define _SYS_SOCKETS_H_
+
+#include <sys/types.h>
+#include <stddef.h> // size_t
+
+typedef uint32_t socklen_t;
+
+typedef enum
+{
+ AF_UNSPEC = 0,
+ AF_PACKET = 1,
+ AF_INET = 4,
+ AF_INET6 = 6,
+} sa_family_t;
+
+struct sockaddr
+{
+ sa_family_t sa_family;
+ char sa_data[16];
+};
+
+struct msghdr
+{
+ void *msg_name;
+ socklen_t msg_namelen;
+ struct iovec *msg_iov;
+ int msg_iovlen;
+ void *msg_control;
+ socklen_t msg_controllen;
+ int msg_flags;
+};
+
+struct cmsghdr
+{
+ socklen_t cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+};
+
+#define SCM_RIGHTS 0x1
+
+#define CMSG_DATA(cmsg) ((unsigned char*)(cmsg + 1))
+#define CMSG_NXTHDR(mhdr, cmsg) 0
+#define CMSG_FIRSTHDR(mhdr) 0
+
+struct linger
+{
+ int l_onoff;
+ int l_linger;
+};
+
+enum eSocketTypes
+{
+ SOCK_STREAM, //!< Stream (TCP)
+ SOCK_DGRAM, //!< Datagram (UDP)
+ SOCK_SEQPACKET, //!<
+ SOCK_RAW, //!< Raw packet access
+ SOCK_RDM //!< Reliable non-ordered datagrams
+};
+
+/**
+ * \brief Values for \a domain of socket()
+ */
+enum eSocketDomains
+{
+ PF_LOCAL, //!< Machine-local comms
+ PF_INET, //!< IPv4
+ PF_INET6, //!< IPv6
+ PF_PACKET //!< Low level packet interface
+};
+#define PF_UNIX PF_LOCAL
+
+/**
+ * \brief Create a new socket descriptor
+ * \param domain Address family
+ */
+extern int socket(int domain, int type, int protocol);
+
+/**
+ * \brief Bind a socket to an address
+ */
+extern int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+/**
+ * \brief Connect to another socket
+ */
+extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
+
+/**
+ * \brief Listen for incoming connections
+ */
+extern int listen(int sockfd, int backlog);
+
+/**
+ * \brief Accept an incoming connection
+ */
+extern int accept(int sockfd, struct sockaddr *clientaddr, socklen_t addrlen);
+
+extern int recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *clientaddr, socklen_t *addrlen);
+extern int recv(int sockfd, void *buffer, size_t length, int flags);
+extern int sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *clientaddr, socklen_t addrlen);
+extern int send(int sockfd, void *buffer, size_t length, int flags);
+
+extern int setsockopt(int socket, int level, int option_name, const void *option_value, socklen_t option_len);
+extern int getsockopt(int socket, int level, int option_name, void *option_value, socklen_t *option_len);
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Sockets Emulation
+ * - By John Hodge (thePowersGang)
+ *
+ * sys/un.h
+ * - UNIX Domain Sockets
+ */
+#ifndef _LIBPSOCKET__SYS__UN_H_
+#define _LIBPSOCKET__SYS__UN_H_
+
+#define _SUN_PATH_MAX 108
+
+// POSIX Defined
+struct sockaddr_un
+{
+ sa_family_t sun_family;
+ char sun_path[_SUN_PATH_MAX];
+};
+
+#endif
+
--- /dev/null
+/*
+ * Acess2 POSIX Sockets Library
+ * - By John Hodge (thePowersGang)
+ *
+ * main.c
+ * - Entrypoint and misc code
+ */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+int SoMain(void)
+{
+ return 0;
+}
+
+char *mkstr(const char *format, ...)
+{
+ va_list args;
+ int len;
+ char *ret;
+
+ va_start(args, format);
+ len = vsnprintf(NULL, 0, format, args);
+ va_end(args);
+ ret = malloc(len + 1);
+ va_start(args, format);
+ vsnprintf(ret, len+1, format, args);
+ va_end(args);
+ return ret;
+}
+
--- /dev/null
+/*
+ * Acess2 POSIX Sockets Library
+ * - By John Hodge (thePowersGang)
+ *
+ * socket.c
+ * - sys/socket.h calls
+ */
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h> // malloc/free
+#include <string.h>
+#include <netinet/in.h>
+
+#define MAXFD 32
+
+typedef struct s_sockinfo
+{
+ int fd;
+ char domain;
+ char type;
+ char protocol;
+ struct sockaddr *local;
+ struct sockaddr *remote;
+} t_sockinfo;
+
+struct s_sockinfo gSockInfo[MAXFD];
+static int giNumPreinit = 0;
+
+// === CODE ===
+static t_sockinfo *_GetInfo(int FD)
+{
+ int i, nInit = 0;;
+ if( FD == 0 && giNumPreinit == MAXFD )
+ return NULL;
+ for( i = 0; i < MAXFD; i ++ )
+ {
+ if( gSockInfo[i].fd == FD )
+ return &gSockInfo[i];
+ if( gSockInfo[i].fd )
+ nInit ++;
+ if( FD != 0 && nInit == giNumPreinit )
+ return NULL;
+ }
+ return NULL;
+}
+
+int socket(int domain, int type, int protocol)
+{
+ t_sockinfo *si = NULL;
+
+ if( domain < 0 || domain > AF_INET6 ) return -1;
+ if( type < 0 || type > SOCK_RDM ) return -1;
+
+ // Allocate an info struct
+ si = _GetInfo(0);
+ if( !si ) return -1;
+
+ int fd = open("/Devices/null", O_RDWR);
+ if( fd == -1 ) return -1;
+
+ giNumPreinit ++;
+ si->fd = fd;
+ si->domain = domain;
+ si->type = type;
+ si->protocol = protocol;
+ si->local = NULL;
+ si->remote = NULL;
+
+ return fd;
+}
+
+int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+ t_sockinfo *si = _GetInfo(sockfd);;
+ if( !si ) return -1;
+
+ if( si->local ) {
+ // Oops?
+ return -1;
+ }
+
+ si->local = malloc( addrlen );
+ memcpy(si->local, addr, addrlen);
+
+ return 0;
+}
+
+int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
+{
+ t_sockinfo *si = _GetInfo(sockfd);;
+ if( !si ) return -1;
+
+ if( si->remote ) {
+ // Oops?
+ return -1;
+ }
+
+ si->remote = malloc( addrlen );
+ memcpy(si->remote, addr, addrlen);
+
+ return 0;
+}
+
+int listen(int sockfd, int backlog)
+{
+ // TODO: Save this to the t_sockinfo structure
+ return 0;
+}
+
+void _ClearInfo(t_sockinfo *si)
+{
+ if( si->local ) {
+ free(si->local);
+ si->local = NULL;
+ }
+
+ if( si->remote ) {
+ free(si->remote);
+ si->remote = NULL;
+ }
+
+ si->fd = 0;
+ giNumPreinit --;
+}
+
+void _CommitServer(int sockfd)
+{
+ t_sockinfo *si = _GetInfo(sockfd);
+ if( !si ) return ;
+
+ const char *file;
+
+ file = "tcps";
+
+ if( !si->local ) {
+ // Um... oops?
+ return ;
+ }
+
+ uint8_t *addrBuffer = NULL;
+ size_t addrLen = 0;
+ switch( si->local->sa_family )
+ {
+ case AF_INET:
+ addrBuffer = (void*)&((struct sockaddr_in*)si->local)->sin_addr;
+ addrLen = 4;
+ break;
+ case AF_INET6:
+ addrBuffer = (void*)&((struct sockaddr_in6*)si->local)->sin6_addr;
+ addrLen = 16;
+ break;
+ default:
+ return ;
+ }
+
+ char hexAddr[addrLen*2+1];
+ int bNonZero = 0, i;
+ for( i = 0; i < addrLen; i ++ ) {
+ hexAddr[i*2+0] = "0123456789ABCDEF"[addrBuffer[i] >> 4];
+ hexAddr[i*2+1] = "0123456789ABCDEF"[addrBuffer[i] & 15];
+ if(addrBuffer[i]) bNonZero = 1;
+ }
+
+ char *path;
+ if( bNonZero )
+ path = mkstr("/Devices/ip/routes/@%i:%s/%s", si->local->sa_family, file);
+ else
+ path = mkstr("/Devices/ip/*%i/%s", si->local->sa_family, file);
+
+ reopen(si->fd, path, O_RDWR);
+ // TODO: Error-check
+
+ free(path);
+
+ // TODO: Set up socket
+
+ _ClearInfo(si);
+}
+
+void _CommitClient(int sockfd)
+{
+ t_sockinfo *si = _GetInfo(sockfd);
+ if( !si ) return ;
+
+ _ClearInfo(si);
+}
+
+int accept(int sockfd, struct sockaddr *clientaddr, socklen_t addrlen)
+{
+ _CommitServer(sockfd);
+ int child;
+
+
+ child = _SysOpenChild(sockfd, "", O_RDWR);
+ if( child == -1 ) return -1;
+
+ ioctl(child, 8, clientaddr);
+
+ return child;
+}
+
+int recvfrom(int sockfd, void *buffer, size_t length, int flags, struct sockaddr *clientaddr, socklen_t *addrlen)
+{
+ _CommitClient(sockfd);
+ // TODO: Determine socket type (TCP/UDP) and use a bounce-buffer for UDP
+ return read(sockfd, buffer, length);
+}
+
+int recv(int sockfd, void *buffer, size_t length, int flags)
+{
+ _CommitClient(sockfd);
+ return read(sockfd, buffer, length);
+}
+
+int sendto(int sockfd, const void *buffer, size_t length, int flags, const struct sockaddr *clientaddr, socklen_t addrlen)
+{
+ _CommitClient(sockfd);
+ // TODO: Determine socket type (TCP/UDP) and use a bounce-buffer for UDP
+ return write(sockfd, buffer, length);
+}
+
+int send(int sockfd, void *buffer, size_t length, int flags)
+{
+ _CommitClient(sockfd);
+ return write(sockfd, buffer, length);
+}
+
--- /dev/null
+/*
+ * Acess2 Library Suite
+ * - Readline
+ *
+ * Text mode entry with history
+ */
+#ifndef _READLINE_H_
+#define _READLINE_H_
+
+// === TYPES ===
+typedef struct sReadline tReadline;
+
+// === STRUCTURES ===
+
+// === FUNCTIONS ===
+/**
+ *
+ */
+extern tReadline *Readline_Init(int UseHistory);
+
+/**
+ * \brief Read a line from stdin
+ * \return Heap string containing the command string (to be free'd by the caller)
+ */
+extern char *Readline(tReadline *Info);
+
+/**
+ * \brief Read a line from stdin (non-blocking)
+ * \return Heap string containing the command string (to be free'd by the caller)
+ */
+extern char *Readline_NonBlock(tReadline *Info);
+
+#endif
write(STDOUT_FD, "\x1B[C", 3);
break;
}
+ break;
+ case '\0':
+ ofs --;
+ break;
}
break;
--- /dev/null
+/*
+ * Acess2 - URI Parser and opener
+ * By John Hodge (thePowersGang)
+ */
+#ifndef _LIB_URI_H_
+#define _LIB_URI_H_
+
+typedef struct sURI tURI;
+typedef struct sURIFile tURIFile;
+typedef struct sURIHandler tURIHandler;
+
+enum eURIModes
+{
+ URI_MODE_READ = 0x01,
+ URI_MODE_WRITE = 0x02
+};
+
+struct sURI
+{
+ char *Proto;
+ char *Host;
+ char *PortStr;
+ int PortNum;
+ char *Path;
+};
+
+struct sURIHandler
+{
+ char *Name;
+ int BlockSize;
+
+ int (*Open)(char *Host, int Port, char *Path, int Flags);
+ void (*Close)(int Handle);
+ size_t (*Read)(int Handle, size_t Bytes, void *Buffer);
+ size_t (*Write)(int Handle, size_t Bytes, void *Buffer);
+ size_t (*GetSize)(int Handle);
+};
+
+// === FUNCTIONS ===
+extern tURI *URI_Parse(const char *String);
+extern tURIFile *URI_Open(int Mode, tURI *URI);
+extern int URI_GetSize(tURIFile *File, size_t *Size);
+extern size_t URI_Read(tURIFile *File, size_t Bytes, void *Buffer);
+extern size_t URI_Write(tURIFile *File, size_t Bytes, void *Buffer);
+extern void URI_Close(tURIFile *File);
+
+#endif
# Rules
ASFLAGS-$(DIR) := -D ARCHDIR=$(ARCHDIR) -D __ASSEMBLER__=1
-CPPFLAGS-$(DIR) := -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS-$(DIR) := -ffreestanding -I$(ACESSDIR)/Usermode/include/ -DARCHDIR=$(ARCHDIR) -DARCHDIR_is_$(ARCHDIR)=1
+CPPFLAGS-$(DIR) += $(addprefix -I,$(wildcard $(ACESSUSERDIR)Libraries/*/include_exp/))
CFLAGS-$(DIR) := -g -Wall -fPIC -fno-stack-protector -O3
LDFLAGS-$(DIR) := -g -nostdlib -shared -I/Acess/Libs/ld-acess.so -lld-acess -e SoMain -x -L$(OUTPUTDIR)Libs/ --no-undefined
# Include Root Makefile.cfg
-include $(dir $(lastword $(MAKEFILE_LIST)))../Makefile.cfg
-
# Set variables
# > Usermode directory
ACESSUSERDIR := $(ACESSDIR)/Usermode/
# > Distroot
DISTROOT := $(DISTROOT)/$(ARCH)
+
+++ /dev/null
-/**
- * \file drivers.h
- */
-#ifndef _SYS_DRIVERS_H
-#define _SYS_DRIVERS_H
-
-// === COMMON ===
-enum eDrv_Common {
- DRV_IOCTL_NULL,
- DRV_IOCTL_TYPE,
- DRV_IOCTL_IDENT,
- DRV_IOCTL_VER
-};
-
-enum eDrv_Types {
- DRV_TYPE_NULL, //!< NULL Type - Custom Interface
- DRV_TYPE_TERMINAL, //!< Terminal
- DRV_TYPE_VIDEO, //!< Video - LFB
- DRV_TYPE_SOUND, //!< Audio
- DRV_TYPE_MOUSE, //!< Mouse
- DRV_TYPE_JOYSTICK //!< Joystick / Gamepad
-};
-
-// === VIDEO ===
-enum eDrv_Video {
- VID_IOCTL_SETMODE = 4,
- VID_IOCTL_GETMODE,
- VID_IOCTL_FINDMODE,
- VID_IOCTL_MODEINFO,
- VID_IOCTL_REQLFB // Request LFB
-};\r
-struct sVideo_IOCtl_Mode {\r
- short id;\r
- Uint16 width;\r
- Uint16 height;\r
- Uint16 bpp;\r
-};\r
-typedef struct sVideo_IOCtl_Mode tVideo_IOCtl_Mode; //!< Mode Type
-
-// === MOUSE ===
-enum eDrv_Mouse {\r
- MSE_IOCTL_SENS = 4,\r
- MSE_IOCTL_MAX_X,\r
- MSE_IOCTL_MAX_Y\r
-};
-
-// === Terminal ===
-#include "devices/terminal.h"
-
-#endif
+++ /dev/null
-/**
- * \file devices/terminal.h
- */
-#ifndef _SYS_DEVICES_TERMINAL_H
-#define _SYS_DEVICES_TERMINAL_H
-
-#include <stdint.h>
-
-enum eDrv_Terminal {
- TERM_IOCTL_MODETYPE = 4,
- TERM_IOCTL_WIDTH,
- TERM_IOCTL_HEIGHT,
- TERM_IOCTL_QUERYMODE,
- TERM_IOCTL_FORCESHOW,
- TERM_IOCTL_GETSETCURSOR,
- TERM_IOCTL_SETCURSORBITMAP
-};
-
-
-struct sTerm_IOCtl_Mode
-{
- int16_t ID; //!< Zero Based index of mode
- int16_t DriverID; //!< Driver's ID number (from ::tVideo_IOCtl_Mode)
- uint16_t Height; //!< Height
- uint16_t Width; //!< Width
- uint8_t Depth; //!< Bits per cell
- uint8_t Flags; //!< Flags (1: Text Mode)
-};
-
-/**
- * \brief Terminal Modes
- */
-enum eTplTerminal_Modes {
- /**
- * \brief UTF-8 Text Mode
- * Any writes to the terminal file are treated as UTF-8 encoded
- * strings and reads will also return UTF-8 strings.
- */
- TERM_MODE_TEXT,
-
- /**
- * \brief 32bpp Framebuffer
- * Writes to the terminal file will write to the framebuffer.
- * Reads will return UTF-32 characters
- */
- TERM_MODE_FB,
-
- /**
- * \brief OpenGL 2D/3D
- * Writes to the terminal file will send 3D commands
- * Reads will return UTF-32 characters
- * \note May or may not stay in the spec
- */
- TERM_MODE_OPENGL,
-
- NUM_TERM_MODES
-};
-
-#endif
+++ /dev/null
-/*
- */
-#ifndef _ACESS_INTDEFS_H_
-#define _ACESS_INTDEFS_H_
-
-#define INT_MIN -0x80000000
-#define INT_MAX 0x7FFFFFFF
-
-typedef unsigned char __uint8_t;
-typedef unsigned short __uint16_t;
-typedef unsigned int __uint32_t;
-typedef unsigned long long __uint64_t;
-
-typedef signed char __int8_t;
-typedef signed short __int16_t;
-typedef signed int __int32_t;
-typedef signed long long __int64_t;
-
-#if defined(ARCHDIR_is_x86)
-typedef __int32_t __intptr_t;
-typedef __uint32_t __uintptr_t;
-#elif defined(ARCHDIR_is_x86_64)
-typedef __int64_t __intptr_t;
-typedef __uint64_t __uintptr_t;
-#elif defined(ARCHDIR_is_armv7)
-typedef __int32_t __intptr_t;
-typedef __uint32_t __uintptr_t;
-#else
-# error "Unknown pointer size"
-#endif
-
-//typedef uint64_t off_t;
-
-#endif
-
+++ /dev/null
-/*
- * Acess2 System Interface Header
- */
-#ifndef _ACESS_SYS_H_
-#define _ACESS_SYS_H_
-
-#include <stdint.h>
-#include "../sys/types.h"
-
-// === CONSTANTS ===
-#ifndef NULL
-# define NULL ((void*)0)
-#endif
-
-#define THREAD_EVENT_VFS 0x0001
-#define THREAD_EVENT_IPCMSG 0x0002
-#define THREAD_EVENT_SIGNAL 0x0004
-
-#define OPENFLAG_EXEC 0x01
-#define OPENFLAG_READ 0x02
-#define OPENFLAG_WRITE 0x04
-#define OPENFLAG_NOLINK 0x40
-#define OPENFLAG_CREATE 0x80
-#ifndef SEEK_CUR
-# define SEEK_SET 1
-# define SEEK_CUR 0
-# define SEEK_END -1
-#endif
-#define GETMSG_IGNORE ((void*)-1)
-#define FILEFLAG_DIRECTORY 0x10
-#define FILEFLAG_SYMLINK 0x20
-
-// === TYPES ===
-
-// === VARIABLES ===
-extern int _errno;
-
-// === FUNCTIONS ===
-extern void _SysDebug(const char *format, ...);
-// --- Proc ---
-extern void _exit(int status) __attribute__((noreturn));
-extern void sleep(void);
-extern void yield(void);
-extern int kill(int pid, int sig);
-//extern void wait(int miliseconds);
-extern int _SysWaitEvent(int EventMask);
-extern int waittid(int id, int *status);
-extern int clone(int flags, void *stack);
-extern int execve(char *path, char **argv, char **envp);
-extern int _SysSpawn(const char *Path, const char **argv, const char **envp, int nFDs, int *FDs);
-extern int gettid(void);
-extern int getpid(void);
-extern int _SysSetFaultHandler(int (*Handler)(int));
-extern void SysSetName(const char *Name);
-//extern int SysGetName(const char *Name);
-
-// --- Permissions ---
-extern int getuid(void);
-extern int getgid(void);
-extern void setuid(int id);
-extern void setgid(int id);
-
-// --- VFS ---
-extern int chdir(const char *dir);
-extern int open(const char *path, int flags, ...);
-extern int reopen(int fd, const char *path, int flags);
-extern int close(int fd);
-extern uint read(int fd, void *buffer, uint length);
-extern uint write(int fd, const void *buffer, uint length);
-extern int seek(int fd, int64_t offset, int whence);
-extern uint64_t tell(int fd);
-extern int ioctl(int fd, int id, void *data);
-extern int finfo(int fd, t_sysFInfo *info, int maxacls);
-extern int readdir(int fd, char *dest);
-extern int _SysOpenChild(int fd, char *name, int flags);
-extern int _SysGetACL(int fd, t_sysACL *dest);
-extern int _SysMount(const char *Device, const char *Directory, const char *Type, const char *Options);
-extern int _SysSelect(int nfds, fd_set *read, fd_set *write, fd_set *err, time_t *timeout, int extraevents);
-#define select(nfs, rdfds, wrfds, erfds, timeout) _SysSelect(nfs, rdfds, wrfds, erfds, timeout, 0)
-
-// --- IPC ---
-extern int SysSendMessage(pid_t dest, uint length, const void *Data);
-extern int SysGetMessage(pid_t *src, void *Data);
-
-// --- MEMORY ---
-uint64_t _SysGetPhys(uint vaddr);
-uint64_t _SysAllocate(uint vaddr);
-
-#endif
+++ /dev/null
-/**
- * \file axwin.h
- * \author John Hodge (thePowersGang)
- * \brief AxWin Core functions
- */
-#ifndef _AXWIN_AXWIN_H
-#define _AXWIN_AXWIN_H
-
-// === Core Types ===
-typedef void *tAxWin_Handle;
-
-// === Messaging ===
-#include "messages.h"
-
-extern int AxWin_Register(const char *Name);
-
-extern int AxWin_MessageLoop();
-extern int AxWin_SendMessage(tAxWin_Message *Message);
-extern tAxWin_Message *AxWin_WaitForMessage(void);
-extern int AxWin_HandleMessage(tAxWin_Message *Message);
-
-// === Window Control ===
-/**
- * \brief Window Type
- * \note Opaque Type
- */
-typedef struct sAxWin_Window tAxWin_Window;
-
-typedef int tAxWin_MessageCallback(tAxWin_Message *);
-
-/**
- * \brief Window Flags
- * \{
- */
-#define WINFLAG_NOBORDER 0x100
-/**
- * \}
- */
-
-extern tAxWin_Window *AxWin_CreateWindow(
- int16_t X, int16_t Y, int16_t W, int16_t H,
- uint32_t Flags, tAxWin_MessageCallback *Callback);
-
-#endif
+++ /dev/null
-/**
- * \file messages.h
- * \author John Hodge (thePowersGang)
- * \brief AxWin Control Messages and structures
- */
-#ifndef _AXWIN_MESSAGES_H
-#define _AXWIN_MESSAGES_H
-
-#include <stdint.h>
-
-typedef struct sAxWin_Message tAxWin_Message;
-typedef struct sAxWin_RetMsg tAxWin_RetMsg;
-
-// Higherarchy:
-// - HANDLE
-// + ELEMENT
-// > DIALOG
-// > TAB
-
-/**
- * \brief Message IDs
- */
-enum eAxWin_Messages
-{
- // Server Requests
- MSG_SREQ_PING,
- // - Windows
- MSG_SREQ_REGISTER, // bool (char[] Name) - Registers this PID with the Window Manager
-
- MSG_SREQ_ADDTAB, // TAB (char[] Name) - Adds a tab to the window
- MSG_SREQ_DELTAB, // void (TAB Tab) - Closes a tab
-
- MSG_SREQ_NEWDIALOG, // DIALOG (TAB Parent, char[] Name) - Creates a dialog
- MSG_SREQ_DELDIALOG, // void (DIALOG Dialog) - Closes a dialog
-
- MSG_SREQ_SETNAME, // void (ELEMENT Element, char[] Name)
- MSG_SREQ_GETNAME, // char[] (ELEMENT Element)
-
- // - Builtin Elements
- MSG_SREQ_INSERT, // void (ELEMENT Parent, eAxWin_Controls Type, u32 Flags)
-
- // - Drawing
- // All drawing functions take an ELEMENT as their first parameter.
- // This must be either a Tab, Dialog or Canvas control
- MSG_SREQ_SETCOL,
- MSG_SREQ_PSET,
- MSG_SREQ_LINE, MSG_SREQ_CURVE,
- MSG_SREQ_RECT, MSG_SREQ_FILLRECT,
- MSG_SREQ_RIMG, MSG_SREQ_SIMG, // Register/Set Image
- MSG_SREQ_SETFONT, MSG_SREQ_PUTTEXT,
-
- // Server Responses
- MSG_SRSP_VERSION,
- MSG_SRSP_RETURN, // {int RequestID, void[] Return Value} - Returns a value from a server request
-
- NUM_MSG
-};
-
-// --- Server Requests (Requests from the client of the server)
-/**
- * \brief Server Request - Ping (Get Server Version)
- */
-struct sAxWin_SReq_Ping
-{
-};
-
-/**
- * \brief Server Request - New Window
- * \see eAxWin_Messages.MSG_SREQ_NEWWINDOW
- */
-struct sAxWin_SReq_NewWindow
-{
- uint16_t X, Y, W, H;
- uint32_t Flags;
-};
-
-
-// --- Server Responses
-/**
- * \brief Server Response - Pong
- * \see eAxWin_Messages.MSG_SRSP_PONG
- */
-struct sAxWin_SRsp_Version
-{
- uint8_t Major;
- uint8_t Minor;
- uint16_t Build;
-};
-
-/**
- * \brief Server Response - New Window
- * \see eAxWin_Messages.MSG_SRSP_NEWWINDOW
- */
-struct sAxWin_SRsp_NewWindow
-{
- uint32_t Handle;
-};
-
-
-// === Core Message Structure
-/**
- * \brief Overarching Message Structure
- * \note sizeof(tAxWin_Message) is never valid
- */
-struct sAxWin_Message
-{
- uint16_t ID;
- uint16_t Size; //!< Size in DWORDS
- char Data[];
-};
-
-struct sAxWin_RetMsg
-{
- uint16_t ReqID;
- uint16_t Rsvd;
- union
- {
- uint8_t Bool;
- uint32_t Handle;
- int Integer;
- };
-};
-
-#endif
+++ /dev/null
-/**
- * \file axwin2/axwin.h
- * \author John Hodge (thePowersGang)
- * \brief AxWin Core functions
- */
-#ifndef _AXWIN2_AXWIN_H
-#define _AXWIN2_AXWIN_H
-
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <axwin2/messages.h>
-
-// === Core Types ===
-typedef struct sAxWin_Element tAxWin_Element;
-typedef int tAxWin_MessageCallback(tAxWin_Message *);
-
-// === Functions ===
-extern int AxWin_Register(const char *ApplicationName, tAxWin_MessageCallback *DefaultHandler);
-extern tAxWin_Element *AxWin_CreateWindow(const char *TabTitle);
-extern tAxWin_Element *AxWin_AddMenuItem(tAxWin_Element *Parent, const char *Label, int Message);
-
-extern int AxWin_MessageLoop(void);
-extern int AxWin_SendMessage(tAxWin_Message *Message);
-extern tAxWin_Message *AxWin_WaitForMessage(void);
-extern int AxWin_HandleMessage(tAxWin_Message *Message);
-
-// === Window Control ===
-
-extern tAxWin_Element *AxWin_CreateElement(tAxWin_Element *Parent, int ElementType, int Flags, const char *DebugName);
-extern void AxWin_SetFlags(tAxWin_Element *Element, int Flags);
-extern void AxWin_SetText(tAxWin_Element *Element, const char *Text);
-extern void AxWin_SetSize(tAxWin_Element *Element, int Size);
-extern void AxWin_DeleteElement(tAxWin_Element *Element);
-
-// === CONSTANTS ===
-enum eElementFlags
-{
- /**
- * \brief Rendered
- *
- * If set, the element will be ignored in calculating sizes and
- * rendering.
- */
- ELEFLAG_NORENDER = 0x001,
- /**
- * \brief Element visibility
- *
- * If set, the element is not drawn (but still is used for size calculations)
- */
- ELEFLAG_INVISIBLE = 0x002,
-
- /**
- * \brief Position an element absulutely (ignored in size calcs)
- */
- ELEFLAG_ABSOLUTEPOS = 0x004,
-
- /**
- * \brief Fixed size element
- */
- ELEFLAG_FIXEDSIZE = 0x008,
-
- /**
- * \brief Element "orientation"
- *
- * Vertical means that the children of this element are stacked,
- * otherwise they list horizontally
- */
- ELEFLAG_VERTICAL = 0x010,// ELEFLAG_HORIZONTAL = 0x000,
- /**
- * \brief Action for text that overflows
- */
- ELEFLAG_WRAP = 0x020,// ELEFLAG_NOWRAP = 0x000,
- /**
- * \brief Cross size action
- *
- * If this flag is set, the element will only be as large (across
- * its parent) as is needed to encase the contents of the element.
- * Otherwise, the element will expand to fill all avaliable space.
- */
- ELEFLAG_NOEXPAND = 0x040,
-
- /**
- * \brief With (length) size action
- * If this flag is set, the element will only be as large as
- * is required along it's parent
- */
- ELEFLAG_NOSTRETCH = 0x080,
-
- /**
- * \brief Center alignment
- */
- ELEFLAG_ALIGN_CENTER= 0x100,
- /**
- * \brief Right/Bottom alignment
- *
- * If set, the element aligns to the end of avaliable space (instead
- * of the beginning)
- */
- ELEFLAG_ALIGN_END = 0x200
-};
-
-#define ELEFLAG_WINDOW_MAXIMISED 0x10000
-
-/**
- */
-enum eElementTypes
-{
- ELETYPE_NONE,
-
- ELETYPE_WINDOW, //!< Window root element
-
- ELETYPE_BOX, //!< Content box (invisible in itself)
- ELETYPE_TABBAR, //!< Tab Bar
- ELETYPE_TOOLBAR, //!< Tool Bar
-
- ELETYPE_BUTTON, //!< Push Button
-
- ELETYPE_TEXT, //!< Text
- ELETYPE_IMAGE, //!< Image
-
- ELETYPE_SPACER, //!< Visual Spacer (horizontal / vertical rule)
-
- MAX_ELETYPES = 0x100
-};
-
-#endif
+++ /dev/null
-/**
- * \file messages.h
- * \author John Hodge (thePowersGang)
- * \brief AxWin Control Messages and structures
- */
-#ifndef _AXWIN_MESSAGES_H
-#define _AXWIN_MESSAGES_H
-
-#include <stdint.h>
-
-typedef struct sAxWin_Message tAxWin_Message;
-typedef struct sAxWin_RetMsg tAxWin_RetMsg;
-
-// Higherarchy:
-// - HANDLE
-// + ELEMENT
-// > DIALOG
-// > TAB
-
-/**
- * \brief Message IDs
- */
-enum eAxWin_Messages
-{
- // Client->Server Requests
- MSG_SREQ_PING,
- // - Windows
- MSG_SREQ_REGISTER, // bool (char[] Name) - Registers this PID with the Window Manager
-
- MSG_SREQ_ADDWIN, // ELEMENT (char[] Name) - Adds a tab to the window
-
- MSG_SREQ_SETICON, // void (TAB Tab, char[] IconURI) - Set the icon of a tab (or application)
-
- MSG_SREQ_NEWDIALOG, // DIALOG (TAB Parent, char[] Name) - Creates a dialog
- MSG_SREQ_DELDIALOG, // void (DIALOG Dialog) - Closes a dialog
-
- MSG_SREQ_SETNAME, // void (ELEMENT Element, char[] Name)
- MSG_SREQ_GETNAME, // char[] (ELEMENT Element)
-
- // - Builtin Elements
- MSG_SREQ_INSERT, // ELEMENT (ELEMENT Parent, eAxWin_Controls Type, u32 Flags)
- MSG_SREQ_DELETE, // void (ELEMENT Element)
-
- // - Drawing
- // All drawing functions take an ELEMENT as their first parameter.
- // This must be either a Window or Canvas control
- MSG_SREQ_SETCOL,
- MSG_SREQ_PSET,
- MSG_SREQ_LINE, MSG_SREQ_CURVE,
- MSG_SREQ_RECT, MSG_SREQ_FILLRECT,
- MSG_SREQ_RIMG, MSG_SREQ_SIMG, // Register/Set Image
- MSG_SREQ_SETFONT, MSG_SREQ_PUTTEXT,
-
- // - Callback Registration
-
- // - WM Control
- MSG_SREQ_SET_MAXIMIZE_AREA, // void (uint16_t X, Y, W, H)
-
- // Server->Client Responses
- MSG_SRSP_VERSION,
- MSG_SRSP_RETURN, // {int RequestID, void[] Return Value} - Returns a value from a server request
-
- NUM_MSG
-};
-
-// --- Server Requests (Requests from the client of the server)
-/**
- * \brief Server Request - Ping (Get Server Version)
- */
-struct sAxWin_SReq_Ping
-{
-};
-
-/**
- * \brief Server Request - New Window
- * \see eAxWin_Messages.MSG_SREQ_NEWWINDOW
- */
-struct sAxWin_SReq_NewWindow
-{
- uint16_t X, Y, W, H;
- uint32_t Flags;
-};
-
-struct sAxWin_SReq_NewElement
-{
- uint16_t Parent;
- uint16_t Type;
- uint32_t Flags;
-};
-
-
-// --- Server Responses
-/**
- * \brief Server Response - Pong
- * \see eAxWin_Messages.MSG_SRSP_PONG
- */
-struct sAxWin_SRsp_Version
-{
- uint8_t Major;
- uint8_t Minor;
- uint16_t Build;
-};
-
-
-// === Core Message Structure
-/**
- * \brief Overarching Message Structure
- * \note sizeof(tAxWin_Message) is never valid
- */
-struct sAxWin_Message
-{
- uint32_t Source;
- uint16_t ID;
- uint16_t Size; // Size of data
- char Data[];
-};
-
-struct sAxWin_RetMsg
-{
- uint16_t ReqID;
- uint16_t Rsvd;
- uint32_t Value;
-};
-
-#endif
+++ /dev/null
-/*
- * Acess2 GUI Version 3 (AxWin3)
- * - By John Hodge (thePowersGang)
- *
- * axwin.h
- * - Core API Header
- */
-#ifndef _AXWIN3_AXWIN_H_
-#define _AXWIN3_AXWIN_H_
-
-// === CONSTANTS ===
-
-// === TYPES ===
-typedef struct sAxWin3_Window *tHWND;
-typedef unsigned int tAxWin3_Colour; // TODO: Actual 32-bit
-
-typedef void (*tAxWin3_MessageCallback)(int SourceTID, int Length);
-
-typedef int (*tAxWin3_WindowMessageHandler)(tHWND Window, int Message, int Length, void *Data);
-
-// --- Connection management
-extern void AxWin3_Connect(const char *ServerDesc);
-extern tAxWin3_MessageCallback AxWin3_SetMessageCallback(tAxWin3_MessageCallback Callback);
-extern void AxWin3_MainLoop(void);
-
-// --- Non-Window based functions
-extern int AxWin3_GetDisplayCount(void);
-extern int AxWin3_GetDisplayDims(int Display, int *X, int *Y, int *Width, int *Height);
-
-// --- Window creation/deletion
-/**
- * \brief Create a new window (with the required client structures)
- * \param Parent Parent window handle
- * \param Renderer Symbolic name of the renderer to use
- * \param RendererArg Argument to pass to the renderer's initialisation
- * \param DataBytes Number of bytes to allocate for the caller's use
- * \param MessageHandler Function to call when a message arrives for the window
- * \return New window handle
- * \note Usually wrapped by renderer-specific functions
- */
-extern tHWND AxWin3_CreateWindow(
- tHWND Parent,
- const char *Renderer, int RendererArg,
- int DataBytes,
- tAxWin3_WindowMessageHandler MessageHandler
- );
-/**
- * \brief Destroy a window
- * \param Window Handle to a window to destroy
- */
-extern void AxWin3_DestroyWindow(tHWND Window);
-
-// --- Core window management functions
-extern void AxWin3_SendMessage(tHWND Window, tHWND Dest, int Message, int Length, void *Data);
-extern void AxWin3_SetWindowTitle(tHWND Window, const char *Title);
-extern void AxWin3_FocusWindow(tHWND Window);
-extern void AxWin3_ShowWindow(tHWND Window, int bShow);
-extern void AxWin3_DecorateWindow(tHWND Window, int bDecorate);
-extern void AxWin3_SetWindowPos(tHWND Window, short X, short Y, short W, short H);
-extern void AxWin3_MoveWindow(tHWND Window, short X, short Y);
-extern void AxWin3_ResizeWindow(tHWND Window, short W, short H);
-
-#endif
-
+++ /dev/null
-/*
- * Acess2 GUI Version 3 (AxWin3)
- * - By John Hodge (thePowersGang)
- *
- * menu.h
- * - Menu window type
- */
-#ifndef _AXWIN3_MENU_H_
-#define _AXWIN3_MENU_H_
-
-typedef void (*tAxWin3_Menu_Callback)(void *Ptr);
-typedef struct sAxWin3_MenuItem tAxWin3_MenuItem;
-
-extern tHWND AxWin3_Menu_Create(tHWND Parent);
-extern void AxWin3_Menu_ShowAt(tHWND Menu, int X, int Y);
-
-extern tAxWin3_MenuItem *AxWin3_Menu_AddItem(
- tHWND Menu, const char *Label,
- tAxWin3_Menu_Callback Cb, void *Ptr,
- int Flags, tHWND SubMenu
- );
-extern tAxWin3_MenuItem *AxWin3_Menu_GetItem(tHWND Menu, int Index);
-extern void AxWin3_Menu_SetFlags(tAxWin3_MenuItem *Item, int Flags, int Mask);
-
-#endif
-
+++ /dev/null
-/*
- * Acess2 GUI Version 3 (AxWin3)
- * - By John Hodge (thePowersGang)
- *
- * widget.h
- * - Server-side widget library
- */
-#ifndef _AXWIN3_WIDGET_H_
-#define _AXWIN3_WIDGET_H_
-
-#include "axwin.h"
-
-typedef struct sAxWin3_Widget tAxWin3_Widget;
-
-// --- Callback types
-typedef int (*tAxWin3_Widget_FireCb)(tAxWin3_Widget *Widget);
-typedef int (*tAxWin3_Widget_KeyUpDownCb)(tAxWin3_Widget *Widget, int KeySym);
-typedef int (*tAxWin3_Widget_KeyFireCb)(tAxWin3_Widget *Widget, int KeySym, int Character);
-typedef int (*tAxWin3_Widget_MouseMoveCb)(tAxWin3_Widget *Widget, int X, int Y);
-typedef int (*tAxWin3_Widget_MouseBtnCb)(tAxWin3_Widget *Widget, int X, int Y, int Button, int bPressed);
-
-// --- Windows
-extern tHWND AxWin3_Widget_CreateWindow(tHWND Parent, int W, int H, int RootEleFlags);
-extern void AxWin3_Widget_DestroyWindow(tHWND Window);
-extern tAxWin3_Widget *AxWin3_Widget_GetRoot(tHWND Window);
-
-// --- Element Creation
-extern tAxWin3_Widget *AxWin3_Widget_AddWidget(tAxWin3_Widget *Parent, int Type, int Flags, const char *DebugName);
-extern void AxWin3_Widget_DelWidget(tAxWin3_Widget *Widget);
-
-// --- Callbacks
-extern void AxWin3_Widget_SetFireHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_FireCb Callback);
-extern void AxWin3_Widget_SetKeyHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_KeyUpDownCb Callback);
-extern void AxWin3_Widget_SetKeyFireHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_KeyFireCb Callback);
-extern void AxWin3_Widget_SetMouseMoveHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_MouseMoveCb Callback);
-extern void AxWin3_Widget_SetMouseButtonHandler(tAxWin3_Widget *Widget, tAxWin3_Widget_MouseBtnCb Callback);
-// --- Manipulation
-extern void AxWin3_Widget_SetFlags(tAxWin3_Widget *Widget, int FlagSet, int FlagMask);
-extern void AxWin3_Widget_SetSize(tAxWin3_Widget *Widget, int Size);
-extern void AxWin3_Widget_SetText(tAxWin3_Widget *Widget, const char *Text);
-extern void AxWin3_Widget_SetColour(tAxWin3_Widget *Widget, int Index, tAxWin3_Colour Colour);
-// --- Inspection
-extern char *AxWin3_Widget_GetText(tAxWin3_Widget *Widget);
-
-enum eElementTypes
-{
- ELETYPE_NONE,
-
- ELETYPE_BOX, //!< Content box (invisible in itself)
- ELETYPE_TEXT, //!< Text
- ELETYPE_IMAGE, //!< Image
- ELETYPE_BUTTON, //!< Push Button
- ELETYPE_SPACER, //!< Visual Spacer (horizontal / vertical rule)
- ELETYPE_TEXTINPUT, //!< Text Input Field
- ELETYPE_TEXTBOX, //!< Text Box Input
-
- ELETYPE_TABBAR, //!< Tab Bar
- ELETYPE_TOOLBAR, //!< Tool Bar
-
- NUM_ELETYPES
-};
-
-enum eElementFlags
-{
- /**
- * \brief Rendered
- *
- * If set, the element will be ignored in calculating sizes and
- * rendering.
- */
- ELEFLAG_NORENDER = 0x001,
- /**
- * \brief Element visibility
- *
- * If set, the element is not drawn (but still is used for size calculations)
- */
- ELEFLAG_INVISIBLE = 0x002,
-
- /**
- * \brief Position an element absulutely (ignored in size calcs)
- */
- ELEFLAG_ABSOLUTEPOS = 0x004,
-
- /**
- * \brief Fixed size element
- */
- ELEFLAG_FIXEDSIZE = 0x008,
-
- /**
- * \brief Element "orientation"
- *
- * Vertical means that the children of this element are stacked,
- * otherwise they list horizontally
- */
- ELEFLAG_VERTICAL = 0x010,// ELEFLAG_HORIZONTAL = 0x000,
- /**
- * \brief Action for text that overflows
- */
- ELEFLAG_WRAP = 0x020,// ELEFLAG_NOWRAP = 0x000,
- /**
- * \brief Cross size action
- *
- * If this flag is set, the element will only be as large (across
- * its parent) as is needed to encase the contents of the element.
- * Otherwise, the element will expand to fill all avaliable space.
- */
- ELEFLAG_NOEXPAND = 0x040,
-
- /**
- * \brief With (length) size action
- * If this flag is set, the element will only be as large as
- * is required along it's parent
- */
- ELEFLAG_NOSTRETCH = 0x080,
-
- /**
- * \brief Center alignment
- */
- ELEFLAG_ALIGN_CENTER= 0x100,
- /**
- * \brief Right/Bottom alignment
- *
- * If set, the element aligns to the end of avaliable space (instead
- * of the beginning)
- */
- ELEFLAG_ALIGN_END = 0x200
-};
-
-
-#endif
-
+++ /dev/null
-/*
- * Acess2 C Library
- * - By John Hodge (thePowersGang)
- *
- * ctype.h
- * - Type manipulation?
- */
-#ifndef _CTYPE_H_
-#define _CTYPE_H_
-
-static inline int isalpha(int ch) {
- if('A'<=ch&&ch<='Z') return 1;
- if('a'<=ch&&ch<='z') return 1;
- return 0;
-}
-static inline int isdigit(int ch) {
- if('0'<=ch&&ch<='9') return 1;
- return 0;
-}
-
-static inline int isalnum(int ch) {
- return isalpha(ch) || isdigit(ch);
-}
-
-static inline int toupper(int ch) {
- if('a'<=ch && ch <='z')
- return ch - 'a' + 'A';
- return ch;
-}
-
-static inline int isspace(int ch) {
- if(ch == ' ') return 1;
- if(ch == '\t') return 1;
- if(ch == '\r') return 1;
- if(ch == '\n') return 1;
- return 0;
-}
-
-#endif
+++ /dev/null
-#ifndef _ERRNO_H_
-#define _ERRNO_H_
-
-// TODO: Fully implement errno.h, make sure it matches the kernel one
-
-extern int _errno;
-#define errno _errno
-
-#define strerror(_x) "Unimplemented"
-
-enum
-{
- EOK,
- EINVAL,
- ERANGE,
- ENODEV,
- EBADF,
- EINTR,
- EAGAIN,
- ENOMEM,
-
- EADDRNOTAVAIL,
- EINPROGRESS,
-
- E_LAST
-};
-
-#endif
+++ /dev/null
-/*
- * Acess2 C Library (UNIX Emulation)
- * - By John Hodge (thePowersGang)
- *
- * fcntl.h
- * - ??
- */
-
-#ifndef _FCNTL_H_
-#define _FCNTL_H_
-
-#include <sys/sys.h>
-
-// Hacks to handle different behaviors in Acess
-
-// Open doesn't take a chmod
-#define open(_1,_2,...) open(_1, _2)
-
-// Close returns void
-#define close(_1) (close(_1),0)
-
-// Acess doesn't implement lseek
-#define lseek(_1,_2,_3) (seek(_1,_2,_3),tell(_1))
-
-#endif
-
+++ /dev/null
-/*
- */
-#ifndef _IMAGE_H_
-#define _IMAGE_H_
-
-// === TYPES ===
-typedef struct sImage tImage;
-struct sImage
-{
- short Width;
- short Height;
- int Format;
- uint8_t Data[];
-};
-
-// === CONSTANTS ===
-enum eImageFormats
-{
- IMGFMT_BGRA,
- IMGFMT_RGB,
- NUM_IMGFMTS
-};
-
-#endif
+++ /dev/null
-../Libraries/libnet.so_src/net.h
\ No newline at end of file
+++ /dev/null
-/*
- * Acess2 Library Suite
- * - Readline
- *
- * Text mode entry with history
- */
-#ifndef _READLINE_H_
-#define _READLINE_H_
-
-// === TYPES ===
-typedef struct sReadline tReadline;
-
-// === STRUCTURES ===
-
-// === FUNCTIONS ===
-/**
- *
- */
-extern tReadline *Readline_Init(int UseHistory);
-
-/**
- * \brief Read a line from stdin
- * \return Heap string containing the command string (to be free'd by the caller)
- */
-extern char *Readline(tReadline *Info);
-
-/**
- * \brief Read a line from stdin (non-blocking)
- * \return Heap string containing the command string (to be free'd by the caller)
- */
-extern char *Readline_NonBlock(tReadline *Info);
-
-#endif
+++ /dev/null
-/*
- * Acess2 LibC
- * - By John Hodge (thePowersGang)
- *
- * setjmp.h
- * - setjmp/longjmp support
- */
-#ifndef _LIBC_SETJMP_H_
-#define _LIBC_SETJMP_H_
-
-#if ARCHDIR_is_x86
-typedef uint32_t jmp_buf[8];
-#elif ARCHDIR_is_x86_64
-typedef uint64_t jmp_buf[16];
-#else
-# error "Unknown Architecture"
-#endif
-
-extern int setjmp(jmp_buf buf);
-extern void longjmp(jmp_buf buf, int val);
-
-#endif
-
+++ /dev/null
-/*
- * Acess2 C Library
- * - By John Hodge (thePowersGang)
- *
- * signal.h
- * - POSIX Signal Emulation/Interface
- */
-#ifndef _SIGNAL_H_
-#define _SIGNAL_H_
-
-#define SIG_DFL ((void*)0)
-#define SIG_ERR ((void*)-1)
-
-#define SIGABRT 6
-
-#define SIGPIPE 1001
-#define SIGCHLD 1002
-
-#endif
-
+++ /dev/null
-/*
-** 2001 September 15
-**
-** The author disclaims copyright to this source code. In place of
-** a legal notice, here is a blessing:
-**
-** May you do good and not evil.
-** May you find forgiveness for yourself and forgive others.
-** May you share freely, never taking more than you give.
-**
-*************************************************************************
-** This header file defines the interface that the SQLite library
-** presents to client programs. If a C-function, structure, datatype,
-** or constant definition does not appear in this file, then it is
-** not a published API of SQLite, is subject to change without
-** notice, and should not be referenced by programs that use SQLite.
-**
-** Some of the definitions that are in this file are marked as
-** "experimental". Experimental interfaces are normally new
-** features recently added to SQLite. We do not anticipate changes
-** to experimental interfaces but reserve to make minor changes if
-** experience from use "in the wild" suggest such changes are prudent.
-**
-** The official C-language API documentation for SQLite is derived
-** from comments in this file. This file is the authoritative source
-** on how SQLite interfaces are suppose to operate.
-**
-** The name of this file under configuration management is "sqlite.h.in".
-** The makefile makes some minor changes to this file (such as inserting
-** the version number) and changes its name to "sqlite3.h" as
-** part of the build process.
-**
-** @(#) $Id: sqlite.h.in,v 1.284 2008/02/06 14:11:35 drh Exp $
-*/
-#ifndef _SQLITE3_H_
-#define _SQLITE3_H_
-#include <stdarg.h> /* Needed for the definition of va_list */
-
-/*
-** Make sure we can call this stuff from C++.
-*/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
-/*
-** Add the ability to override 'extern'
-*/
-#ifndef SQLITE_EXTERN
-# define SQLITE_EXTERN extern
-#endif
-
-/*
-** Make sure these symbols where not defined by some previous header
-** file.
-*/
-#ifdef SQLITE_VERSION
-# undef SQLITE_VERSION
-#endif
-#ifdef SQLITE_VERSION_NUMBER
-# undef SQLITE_VERSION_NUMBER
-#endif
-
-/*
-** CAPI3REF: Compile-Time Library Version Numbers {F10010}
-**
-** The SQLITE_VERSION and SQLITE_VERSION_NUMBER #defines in
-** the sqlite3.h file specify the version of SQLite with which
-** that header file is associated.
-**
-** The "version" of SQLite is a strong of the form "X.Y.Z".
-** The phrase "alpha" or "beta" might be appended after the Z.
-** The X value is major version number always 3 in SQLite3.
-** The X value only changes when backwards compatibility is
-** broken and we intend to never break
-** backwards compatibility. The Y value is the minor version
-** number and only changes when
-** there are major feature enhancements that are forwards compatible
-** but not backwards compatible. The Z value is release number
-** and is incremented with
-** each release but resets back to 0 when Y is incremented.
-**
-** See also: [sqlite3_libversion()] and [sqlite3_libversion_number()].
-**
-** INVARIANTS:
-**
-** {F10011} The SQLITE_VERSION #define in the sqlite3.h header file
-** evaluates to a string literal that is the SQLite version
-** with which the header file is associated.
-**
-** {F10014} The SQLITE_VERSION_NUMBER #define resolves to an integer
-** with the value (X*1000000 + Y*1000 + Z) where X, Y, and
-** Z are the major version, minor version, and release number.
-*/
-#define SQLITE_VERSION "3.5.6"
-#define SQLITE_VERSION_NUMBER 3005006
-
-/*
-** CAPI3REF: Run-Time Library Version Numbers {F10020}
-** KEYWORDS: sqlite3_version
-**
-** These features provide the same information as the [SQLITE_VERSION]
-** and [SQLITE_VERSION_NUMBER] #defines in the header, but are associated
-** with the library instead of the header file. Cautious programmers might
-** include a check in their application to verify that
-** sqlite3_libversion_number() always returns the value
-** [SQLITE_VERSION_NUMBER].
-**
-** The sqlite3_libversion() function returns the same information as is
-** in the sqlite3_version[] string constant. The function is provided
-** for use in DLLs since DLL users usually do not have direct access to string
-** constants within the DLL.
-**
-** INVARIANTS:
-**
-** {F10021} The [sqlite3_libversion_number()] interface returns an integer
-** equal to [SQLITE_VERSION_NUMBER].
-**
-** {F10022} The [sqlite3_version] string constant contains the text of the
-** [SQLITE_VERSION] string.
-**
-** {F10023} The [sqlite3_libversion()] function returns
-** a pointer to the [sqlite3_version] string constant.
-*/
-SQLITE_EXTERN const char sqlite3_version[];
-const char *sqlite3_libversion(void);
-int sqlite3_libversion_number(void);
-
-/*
-** CAPI3REF: Test To See If The Library Is Threadsafe {F10100}
-**
-** SQLite can be compiled with or without mutexes. When
-** the SQLITE_THREADSAFE C preprocessor macro is true, mutexes
-** are enabled and SQLite is threadsafe. When that macro os false,
-** the mutexes are omitted. Without the mutexes, it is not safe
-** to use SQLite from more than one thread.
-**
-** There is a measurable performance penalty for enabling mutexes.
-** So if speed is of utmost importance, it makes sense to disable
-** the mutexes. But for maximum safety, mutexes should be enabled.
-** The default behavior is for mutexes to be enabled.
-**
-** This interface can be used by a program to make sure that the
-** version of SQLite that it is linking against was compiled with
-** the desired setting of the SQLITE_THREADSAFE macro.
-**
-** INVARIANTS:
-**
-** {F10101} The [sqlite3_threadsafe()] function returns nonzero if
-** SQLite was compiled with its mutexes enabled or zero
-** if SQLite was compiled with mutexes disabled.
-*/
-int sqlite3_threadsafe(void);
-
-/*
-** CAPI3REF: Database Connection Handle {F12000}
-** KEYWORDS: {database connection}
-**
-** Each open SQLite database is represented by pointer to an instance of the
-** opaque structure named "sqlite3". It is useful to think of an sqlite3
-** pointer as an object. The [sqlite3_open()], [sqlite3_open16()], and
-** [sqlite3_open_v2()] interfaces are its constructors
-** and [sqlite3_close()] is its destructor. There are many other interfaces
-** (such as [sqlite3_prepare_v2()], [sqlite3_create_function()], and
-** [sqlite3_busy_timeout()] to name but three) that are methods on this
-** object.
-*/
-typedef struct sqlite3 sqlite3;
-
-
-/*
-** CAPI3REF: 64-Bit Integer Types {F10200}
-** KEYWORDS: sqlite_int64 sqlite_uint64
-**
-** Because there is no cross-platform way to specify 64-bit integer types
-** SQLite includes typedefs for 64-bit signed and unsigned integers.
-**
-** The sqlite3_int64 and sqlite3_uint64 are the preferred type
-** definitions. The sqlite_int64 and sqlite_uint64 types are
-** supported for backwards compatibility only.
-**
-** INVARIANTS:
-**
-** {F10201} The [sqlite_int64] and [sqlite3_int64] types specify a
-** 64-bit signed integer.
-**
-** {F10202} The [sqlite_uint64] and [sqlite3_uint64] types specify
-** a 64-bit unsigned integer.
-*/
-#ifdef SQLITE_INT64_TYPE
- typedef SQLITE_INT64_TYPE sqlite_int64;
- typedef unsigned SQLITE_INT64_TYPE sqlite_uint64;
-#elif defined(_MSC_VER) || defined(__BORLANDC__)
- typedef __int64 sqlite_int64;
- typedef unsigned __int64 sqlite_uint64;
-#else
- typedef long long int sqlite_int64;
- typedef unsigned long long int sqlite_uint64;
-#endif
-typedef sqlite_int64 sqlite3_int64;
-typedef sqlite_uint64 sqlite3_uint64;
-
-/*
-** If compiling for a processor that lacks floating point support,
-** substitute integer for floating-point
-*/
-#ifdef SQLITE_OMIT_FLOATING_POINT
-# define double sqlite3_int64
-#endif
-
-/*
-** CAPI3REF: Closing A Database Connection {F12010}
-**
-** This routine is the destructor for the [sqlite3] object.
-**
-** Applications should [sqlite3_finalize | finalize] all
-** [prepared statements] and
-** [sqlite3_blob_close | close] all [sqlite3_blob | BLOBs]
-** associated with the [sqlite3] object prior
-** to attempting to close the [sqlite3] object.
-**
-** <todo>What happens to pending transactions? Are they
-** rolled back, or abandoned?</todo>
-**
-** INVARIANTS:
-**
-** {F12011} The [sqlite3_close()] interface destroys an [sqlite3] object
-** allocated by a prior call to [sqlite3_open()],
-** [sqlite3_open16()], or [sqlite3_open_v2()].
-**
-** {F12012} The [sqlite3_close()] function releases all memory used by the
-** connection and closes all open files.
-**
-** {F12013} If the database connection contains
-** [prepared statements] that have not been
-** finalized by [sqlite3_finalize()], then [sqlite3_close()]
-** returns [SQLITE_BUSY] and leaves the connection open.
-**
-** {F12014} Giving sqlite3_close() a NULL pointer is a harmless no-op.
-**
-** LIMITATIONS:
-**
-** {U12015} The parameter to [sqlite3_close()] must be an [sqlite3] object
-** pointer previously obtained from [sqlite3_open()] or the
-** equivalent, or NULL.
-**
-** {U12016} The parameter to [sqlite3_close()] must not have been previously
-** closed.
-*/
-int sqlite3_close(sqlite3 *);
-
-/*
-** The type for a callback function.
-** This is legacy and deprecated. It is included for historical
-** compatibility and is not documented.
-*/
-typedef int (*sqlite3_callback)(void*,int,char**, char**);
-
-/*
-** CAPI3REF: One-Step Query Execution Interface {F12100}
-**
-** The sqlite3_exec() interface is a convenient way of running
-** one or more SQL statements without a lot of C code. The
-** SQL statements are passed in as the second parameter to
-** sqlite3_exec(). The statements are evaluated one by one
-** until either an error or an interrupt is encountered or
-** until they are all done. The 3rd parameter is an optional
-** callback that is invoked once for each row of any query results
-** produced by the SQL statements. The 5th parameter tells where
-** to write any error messages.
-**
-** The sqlite3_exec() interface is implemented in terms of
-** [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()].
-** The sqlite3_exec() routine does nothing that cannot be done
-** by [sqlite3_prepare_v2()], [sqlite3_step()], and [sqlite3_finalize()].
-** The sqlite3_exec() is just a convenient wrapper.
-**
-** INVARIANTS:
-**
-** {F12101} The [sqlite3_exec()] interface evaluates zero or more UTF-8
-** encoded, semicolon-separated, SQL statements in the
-** zero-terminated string of its 2nd parameter within the
-** context of the [sqlite3] object given in the 1st parameter.
-**
-** {F12104} The return value of [sqlite3_exec()] is SQLITE_OK if all
-** SQL statements run successfully.
-**
-** {F12105} The return value of [sqlite3_exec()] is an appropriate
-** non-zero error code if any SQL statement fails.
-**
-** {F12107} If one or more of the SQL statements handed to [sqlite3_exec()]
-** return results and the 3rd parameter is not NULL, then
-** the callback function specified by the 3rd parameter is
-** invoked once for each row of result.
-**
-** {F12110} If the callback returns a non-zero value then [sqlite3_exec()]
-** will aborted the SQL statement it is currently evaluating,
-** skip all subsequent SQL statements, and return [SQLITE_ABORT].
-** <todo>What happens to *errmsg here? Does the result code for
-** sqlite3_errcode() get set?</todo>
-**
-** {F12113} The [sqlite3_exec()] routine will pass its 4th parameter through
-** as the 1st parameter of the callback.
-**
-** {F12116} The [sqlite3_exec()] routine sets the 2nd parameter of its
-** callback to be the number of columns in the current row of
-** result.
-**
-** {F12119} The [sqlite3_exec()] routine sets the 3rd parameter of its
-** callback to be an array of pointers to strings holding the
-** values for each column in the current result set row as
-** obtained from [sqlite3_column_text()].
-**
-** {F12122} The [sqlite3_exec()] routine sets the 4th parameter of its
-** callback to be an array of pointers to strings holding the
-** names of result columns as obtained from [sqlite3_column_name()].
-**
-** {F12125} If the 3rd parameter to [sqlite3_exec()] is NULL then
-** [sqlite3_exec()] never invokes a callback. All query
-** results are silently discarded.
-**
-** {F12128} If an error occurs while parsing or evaluating any of the SQL
-** statements handed to [sqlite3_exec()] then [sqlite3_exec()] will
-** return an [error code] other than [SQLITE_OK].
-**
-** {F12131} If an error occurs while parsing or evaluating any of the SQL
-** handed to [sqlite3_exec()] and if the 5th parameter (errmsg)
-** to [sqlite3_exec()] is not NULL, then an error message is
-** allocated using the equivalent of [sqlite3_mprintf()] and
-** *errmsg is made to point to that message.
-**
-** {F12134} The [sqlite3_exec()] routine does not change the value of
-** *errmsg if errmsg is NULL or if there are no errors.
-**
-** {F12137} The [sqlite3_exec()] function sets the error code and message
-** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()].
-**
-** LIMITATIONS:
-**
-** {U12141} The first parameter to [sqlite3_exec()] must be an valid and open
-** [database connection].
-**
-** {U12142} The database connection must not be closed while
-** [sqlite3_exec()] is running.
-**
-** {U12143} The calling function is should use [sqlite3_free()] to free
-** the memory that *errmsg is left pointing at once the error
-** message is no longer needed.
-**
-** {U12145} The SQL statement text in the 2nd parameter to [sqlite3_exec()]
-** must remain unchanged while [sqlite3_exec()] is running.
-*/
-int sqlite3_exec(
- sqlite3*, /* An open database */
- const char *sql, /* SQL to be evaluted */
- int (*callback)(void*,int,char**,char**), /* Callback function */
- void *, /* 1st argument to callback */
- char **errmsg /* Error msg written here */
-);
-
-/*
-** CAPI3REF: Result Codes {F10210}
-** KEYWORDS: SQLITE_OK {error code} {error codes}
-**
-** Many SQLite functions return an integer result code from the set shown
-** here in order to indicates success or failure.
-**
-** See also: [SQLITE_IOERR_READ | extended result codes]
-*/
-#define SQLITE_OK 0 /* Successful result */
-/* beginning-of-error-codes */
-#define SQLITE_ERROR 1 /* SQL error or missing database */
-#define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */
-#define SQLITE_PERM 3 /* Access permission denied */
-#define SQLITE_ABORT 4 /* Callback routine requested an abort */
-#define SQLITE_BUSY 5 /* The database file is locked */
-#define SQLITE_LOCKED 6 /* A table in the database is locked */
-#define SQLITE_NOMEM 7 /* A malloc() failed */
-#define SQLITE_READONLY 8 /* Attempt to write a readonly database */
-#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite3_interrupt()*/
-#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */
-#define SQLITE_CORRUPT 11 /* The database disk image is malformed */
-#define SQLITE_NOTFOUND 12 /* NOT USED. Table or record not found */
-#define SQLITE_FULL 13 /* Insertion failed because database is full */
-#define SQLITE_CANTOPEN 14 /* Unable to open the database file */
-#define SQLITE_PROTOCOL 15 /* NOT USED. Database lock protocol error */
-#define SQLITE_EMPTY 16 /* Database is empty */
-#define SQLITE_SCHEMA 17 /* The database schema changed */
-#define SQLITE_TOOBIG 18 /* String or BLOB exceeds size limit */
-#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */
-#define SQLITE_MISMATCH 20 /* Data type mismatch */
-#define SQLITE_MISUSE 21 /* Library used incorrectly */
-#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
-#define SQLITE_AUTH 23 /* Authorization denied */
-#define SQLITE_FORMAT 24 /* Auxiliary database format error */
-#define SQLITE_RANGE 25 /* 2nd parameter to sqlite3_bind out of range */
-#define SQLITE_NOTADB 26 /* File opened that is not a database file */
-#define SQLITE_ROW 100 /* sqlite3_step() has another row ready */
-#define SQLITE_DONE 101 /* sqlite3_step() has finished executing */
-/* end-of-error-codes */
-
-/*
-** CAPI3REF: Extended Result Codes {F10220}
-** KEYWORDS: {extended error code} {extended error codes}
-** KEYWORDS: {extended result codes}
-**
-** In its default configuration, SQLite API routines return one of 26 integer
-** [SQLITE_OK | result codes]. However, experience has shown that
-** many of these result codes are too course-grained. They do not provide as
-** much information about problems as programmers might like. In an effort to
-** address this, newer versions of SQLite (version 3.3.8 and later) include
-** support for additional result codes that provide more detailed information
-** about errors. The extended result codes are enabled or disabled
-** for each database connection using the [sqlite3_extended_result_codes()]
-** API.
-**
-** Some of the available extended result codes are listed here.
-** One may expect the number of extended result codes will be expand
-** over time. Software that uses extended result codes should expect
-** to see new result codes in future releases of SQLite.
-**
-** The SQLITE_OK result code will never be extended. It will always
-** be exactly zero.
-**
-** INVARIANTS:
-**
-** {F10223} The symbolic name for an extended result code always contains
-** a related primary result code as a prefix.
-**
-** {F10224} Primary result code names contain a single "_" character.
-**
-** {F10225} Extended result code names contain two or more "_" characters.
-**
-** {F10226} The numeric value of an extended result code contains the
-** numeric value of its corresponding primary result code it
-** its least significant 8 bits.
-*/
-#define SQLITE_IOERR_READ (SQLITE_IOERR | (1<<8))
-#define SQLITE_IOERR_SHORT_READ (SQLITE_IOERR | (2<<8))
-#define SQLITE_IOERR_WRITE (SQLITE_IOERR | (3<<8))
-#define SQLITE_IOERR_FSYNC (SQLITE_IOERR | (4<<8))
-#define SQLITE_IOERR_DIR_FSYNC (SQLITE_IOERR | (5<<8))
-#define SQLITE_IOERR_TRUNCATE (SQLITE_IOERR | (6<<8))
-#define SQLITE_IOERR_FSTAT (SQLITE_IOERR | (7<<8))
-#define SQLITE_IOERR_UNLOCK (SQLITE_IOERR | (8<<8))
-#define SQLITE_IOERR_RDLOCK (SQLITE_IOERR | (9<<8))
-#define SQLITE_IOERR_DELETE (SQLITE_IOERR | (10<<8))
-#define SQLITE_IOERR_BLOCKED (SQLITE_IOERR | (11<<8))
-#define SQLITE_IOERR_NOMEM (SQLITE_IOERR | (12<<8))
-
-/*
-** CAPI3REF: Flags For File Open Operations {F10230}
-**
-** These bit values are intended for use in then
-** 3rd parameter to the [sqlite3_open_v2()] interface and
-** in the 4th parameter to the xOpen method of the
-** [sqlite3_vfs] object.
-*/
-#define SQLITE_OPEN_READONLY 0x00000001
-#define SQLITE_OPEN_READWRITE 0x00000002
-#define SQLITE_OPEN_CREATE 0x00000004
-#define SQLITE_OPEN_DELETEONCLOSE 0x00000008
-#define SQLITE_OPEN_EXCLUSIVE 0x00000010
-#define SQLITE_OPEN_MAIN_DB 0x00000100
-#define SQLITE_OPEN_TEMP_DB 0x00000200
-#define SQLITE_OPEN_TRANSIENT_DB 0x00000400
-#define SQLITE_OPEN_MAIN_JOURNAL 0x00000800
-#define SQLITE_OPEN_TEMP_JOURNAL 0x00001000
-#define SQLITE_OPEN_SUBJOURNAL 0x00002000
-#define SQLITE_OPEN_MASTER_JOURNAL 0x00004000
-
-/*
-** CAPI3REF: Device Characteristics {F10240}
-**
-** The xDeviceCapabilities method of the [sqlite3_io_methods]
-** object returns an integer which is a vector of the these
-** bit values expressing I/O characteristics of the mass storage
-** device that holds the file that the [sqlite3_io_methods]
-** refers to.
-**
-** The SQLITE_IOCAP_ATOMIC property means that all writes of
-** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
-** mean that writes of blocks that are nnn bytes in size and
-** are aligned to an address which is an integer multiple of
-** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means
-** that when data is appended to a file, the data is appended
-** first then the size of the file is extended, never the other
-** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
-** information is written to disk in the same order as calls
-** to xWrite().
-*/
-#define SQLITE_IOCAP_ATOMIC 0x00000001
-#define SQLITE_IOCAP_ATOMIC512 0x00000002
-#define SQLITE_IOCAP_ATOMIC1K 0x00000004
-#define SQLITE_IOCAP_ATOMIC2K 0x00000008
-#define SQLITE_IOCAP_ATOMIC4K 0x00000010
-#define SQLITE_IOCAP_ATOMIC8K 0x00000020
-#define SQLITE_IOCAP_ATOMIC16K 0x00000040
-#define SQLITE_IOCAP_ATOMIC32K 0x00000080
-#define SQLITE_IOCAP_ATOMIC64K 0x00000100
-#define SQLITE_IOCAP_SAFE_APPEND 0x00000200
-#define SQLITE_IOCAP_SEQUENTIAL 0x00000400
-
-/*
-** CAPI3REF: File Locking Levels {F10250}
-**
-** SQLite uses one of these integer values as the second
-** argument to calls it makes to the xLock() and xUnlock() methods
-** of an [sqlite3_io_methods] object.
-*/
-#define SQLITE_LOCK_NONE 0
-#define SQLITE_LOCK_SHARED 1
-#define SQLITE_LOCK_RESERVED 2
-#define SQLITE_LOCK_PENDING 3
-#define SQLITE_LOCK_EXCLUSIVE 4
-
-/*
-** CAPI3REF: Synchronization Type Flags {F10260}
-**
-** When SQLite invokes the xSync() method of an
-** [sqlite3_io_methods] object it uses a combination of the
-** these integer values as the second argument.
-**
-** When the SQLITE_SYNC_DATAONLY flag is used, it means that the
-** sync operation only needs to flush data to mass storage. Inode
-** information need not be flushed. The SQLITE_SYNC_NORMAL means
-** to use normal fsync() semantics. The SQLITE_SYNC_FULL flag means
-** to use Mac OS-X style fullsync instead of fsync().
-*/
-#define SQLITE_SYNC_NORMAL 0x00002
-#define SQLITE_SYNC_FULL 0x00003
-#define SQLITE_SYNC_DATAONLY 0x00010
-
-
-/*
-** CAPI3REF: OS Interface Open File Handle {F11110}
-**
-** An [sqlite3_file] object represents an open file in the OS
-** interface layer. Individual OS interface implementations will
-** want to subclass this object by appending additional fields
-** for their own use. The pMethods entry is a pointer to an
-** [sqlite3_io_methods] object that defines methods for performing
-** I/O operations on the open file.
-*/
-typedef struct sqlite3_file sqlite3_file;
-struct sqlite3_file {
- const struct sqlite3_io_methods *pMethods; /* Methods for an open file */
-};
-
-/*
-** CAPI3REF: OS Interface File Virtual Methods Object {F11120}
-**
-** Every file opened by the [sqlite3_vfs] xOpen method contains a pointer to
-** an instance of the this object. This object defines the
-** methods used to perform various operations against the open file.
-**
-** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or
-** [SQLITE_SYNC_FULL]. The first choice is the normal fsync().
-* The second choice is an
-** OS-X style fullsync. The SQLITE_SYNC_DATA flag may be ORed in to
-** indicate that only the data of the file and not its inode needs to be
-** synced.
-**
-** The integer values to xLock() and xUnlock() are one of
-** <ul>
-** <li> [SQLITE_LOCK_NONE],
-** <li> [SQLITE_LOCK_SHARED],
-** <li> [SQLITE_LOCK_RESERVED],
-** <li> [SQLITE_LOCK_PENDING], or
-** <li> [SQLITE_LOCK_EXCLUSIVE].
-** </ul>
-** xLock() increases the lock. xUnlock() decreases the lock.
-** The xCheckReservedLock() method looks
-** to see if any database connection, either in this
-** process or in some other process, is holding an RESERVED,
-** PENDING, or EXCLUSIVE lock on the file. It returns true
-** if such a lock exists and false if not.
-**
-** The xFileControl() method is a generic interface that allows custom
-** VFS implementations to directly control an open file using the
-** [sqlite3_file_control()] interface. The second "op" argument
-** is an integer opcode. The third
-** argument is a generic pointer which is intended to be a pointer
-** to a structure that may contain arguments or space in which to
-** write return values. Potential uses for xFileControl() might be
-** functions to enable blocking locks with timeouts, to change the
-** locking strategy (for example to use dot-file locks), to inquire
-** about the status of a lock, or to break stale locks. The SQLite
-** core reserves opcodes less than 100 for its own use.
-** A [SQLITE_FCNTL_LOCKSTATE | list of opcodes] less than 100 is available.
-** Applications that define a custom xFileControl method should use opcodes
-** greater than 100 to avoid conflicts.
-**
-** The xSectorSize() method returns the sector size of the
-** device that underlies the file. The sector size is the
-** minimum write that can be performed without disturbing
-** other bytes in the file. The xDeviceCharacteristics()
-** method returns a bit vector describing behaviors of the
-** underlying device:
-**
-** <ul>
-** <li> [SQLITE_IOCAP_ATOMIC]
-** <li> [SQLITE_IOCAP_ATOMIC512]
-** <li> [SQLITE_IOCAP_ATOMIC1K]
-** <li> [SQLITE_IOCAP_ATOMIC2K]
-** <li> [SQLITE_IOCAP_ATOMIC4K]
-** <li> [SQLITE_IOCAP_ATOMIC8K]
-** <li> [SQLITE_IOCAP_ATOMIC16K]
-** <li> [SQLITE_IOCAP_ATOMIC32K]
-** <li> [SQLITE_IOCAP_ATOMIC64K]
-** <li> [SQLITE_IOCAP_SAFE_APPEND]
-** <li> [SQLITE_IOCAP_SEQUENTIAL]
-** </ul>
-**
-** The SQLITE_IOCAP_ATOMIC property means that all writes of
-** any size are atomic. The SQLITE_IOCAP_ATOMICnnn values
-** mean that writes of blocks that are nnn bytes in size and
-** are aligned to an address which is an integer multiple of
-** nnn are atomic. The SQLITE_IOCAP_SAFE_APPEND value means
-** that when data is appended to a file, the data is appended
-** first then the size of the file is extended, never the other
-** way around. The SQLITE_IOCAP_SEQUENTIAL property means that
-** information is written to disk in the same order as calls
-** to xWrite().
-*/
-typedef struct sqlite3_io_methods sqlite3_io_methods;
-struct sqlite3_io_methods {
- int iVersion;
- int (*xClose)(sqlite3_file*);
- int (*xRead)(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst);
- int (*xWrite)(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst);
- int (*xTruncate)(sqlite3_file*, sqlite3_int64 size);
- int (*xSync)(sqlite3_file*, int flags);
- int (*xFileSize)(sqlite3_file*, sqlite3_int64 *pSize);
- int (*xLock)(sqlite3_file*, int);
- int (*xUnlock)(sqlite3_file*, int);
- int (*xCheckReservedLock)(sqlite3_file*);
- int (*xFileControl)(sqlite3_file*, int op, void *pArg);
- int (*xSectorSize)(sqlite3_file*);
- int (*xDeviceCharacteristics)(sqlite3_file*);
- /* Additional methods may be added in future releases */
-};
-
-/*
-** CAPI3REF: Standard File Control Opcodes {F11310}
-**
-** These integer constants are opcodes for the xFileControl method
-** of the [sqlite3_io_methods] object and to the [sqlite3_file_control()]
-** interface.
-**
-** The [SQLITE_FCNTL_LOCKSTATE] opcode is used for debugging. This
-** opcode cases the xFileControl method to write the current state of
-** the lock (one of [SQLITE_LOCK_NONE], [SQLITE_LOCK_SHARED],
-** [SQLITE_LOCK_RESERVED], [SQLITE_LOCK_PENDING], or [SQLITE_LOCK_EXCLUSIVE])
-** into an integer that the pArg argument points to. This capability
-** is used during testing and only needs to be supported when SQLITE_TEST
-** is defined.
-*/
-#define SQLITE_FCNTL_LOCKSTATE 1
-
-/*
-** CAPI3REF: Mutex Handle {F17110}
-**
-** The mutex module within SQLite defines [sqlite3_mutex] to be an
-** abstract type for a mutex object. The SQLite core never looks
-** at the internal representation of an [sqlite3_mutex]. It only
-** deals with pointers to the [sqlite3_mutex] object.
-**
-** Mutexes are created using [sqlite3_mutex_alloc()].
-*/
-typedef struct sqlite3_mutex sqlite3_mutex;
-
-/*
-** CAPI3REF: OS Interface Object {F11140}
-**
-** An instance of this object defines the interface between the
-** SQLite core and the underlying operating system. The "vfs"
-** in the name of the object stands for "virtual file system".
-**
-** The iVersion field is initially 1 but may be larger for future
-** versions of SQLite. Additional fields may be appended to this
-** object when the iVersion value is increased.
-**
-** The szOsFile field is the size of the subclassed [sqlite3_file]
-** structure used by this VFS. mxPathname is the maximum length of
-** a pathname in this VFS.
-**
-** Registered vfs modules are kept on a linked list formed by
-** the pNext pointer. The [sqlite3_vfs_register()]
-** and [sqlite3_vfs_unregister()] interfaces manage this list
-** in a thread-safe way. The [sqlite3_vfs_find()] interface
-** searches the list.
-**
-** The pNext field is the only fields in the sqlite3_vfs
-** structure that SQLite will ever modify. SQLite will only access
-** or modify this field while holding a particular static mutex.
-** The application should never modify anything within the sqlite3_vfs
-** object once the object has been registered.
-**
-** The zName field holds the name of the VFS module. The name must
-** be unique across all VFS modules.
-**
-** {F11141} SQLite will guarantee that the zFilename string passed to
-** xOpen() is a full pathname as generated by xFullPathname() and
-** that the string will be valid and unchanged until xClose() is
-** called. {END} So the [sqlite3_file] can store a pointer to the
-** filename if it needs to remember the filename for some reason.
-**
-** {F11142} The flags argument to xOpen() includes all bits set in
-** the flags argument to [sqlite3_open_v2()]. Or if [sqlite3_open()]
-** or [sqlite3_open16()] is used, then flags includes at least
-** [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]. {END}
-** If xOpen() opens a file read-only then it sets *pOutFlags to
-** include [SQLITE_OPEN_READONLY]. Other bits in *pOutFlags may be
-** set.
-**
-** {F11143} SQLite will also add one of the following flags to the xOpen()
-** call, depending on the object being opened:
-**
-** <ul>
-** <li> [SQLITE_OPEN_MAIN_DB]
-** <li> [SQLITE_OPEN_MAIN_JOURNAL]
-** <li> [SQLITE_OPEN_TEMP_DB]
-** <li> [SQLITE_OPEN_TEMP_JOURNAL]
-** <li> [SQLITE_OPEN_TRANSIENT_DB]
-** <li> [SQLITE_OPEN_SUBJOURNAL]
-** <li> [SQLITE_OPEN_MASTER_JOURNAL]
-** </ul> {END}
-**
-** The file I/O implementation can use the object type flags to
-** changes the way it deals with files. For example, an application
-** that does not care about crash recovery or rollback, might make
-** the open of a journal file a no-op. Writes to this journal are
-** also a no-op. Any attempt to read the journal return SQLITE_IOERR.
-** Or the implementation might recognize the a database file will
-** be doing page-aligned sector reads and writes in a random order
-** and set up its I/O subsystem accordingly.
-**
-** SQLite might also add one of the following flags to the xOpen
-** method:
-**
-** <ul>
-** <li> [SQLITE_OPEN_DELETEONCLOSE]
-** <li> [SQLITE_OPEN_EXCLUSIVE]
-** </ul>
-**
-** {F11145} The [SQLITE_OPEN_DELETEONCLOSE] flag means the file should be
-** deleted when it is closed. {F11146} The [SQLITE_OPEN_DELETEONCLOSE]
-** will be set for TEMP databases, journals and for subjournals.
-** {F11147} The [SQLITE_OPEN_EXCLUSIVE] flag means the file should be opened
-** for exclusive access. This flag is set for all files except
-** for the main database file. {END}
-**
-** {F11148} At least szOsFile bytes of memory is allocated by SQLite
-** to hold the [sqlite3_file] structure passed as the third
-** argument to xOpen. {END} The xOpen method does not have to
-** allocate the structure; it should just fill it in.
-**
-** {F11149} The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS]
-** to test for the existance of a file,
-** or [SQLITE_ACCESS_READWRITE] to test to see
-** if a file is readable and writable, or [SQLITE_ACCESS_READ]
-** to test to see if a file is at least readable. {END} The file can be a
-** directory.
-**
-** {F11150} SQLite will always allocate at least mxPathname+1 byte for
-** the output buffers for xGetTempname and xFullPathname. {F11151} The exact
-** size of the output buffer is also passed as a parameter to both
-** methods. {END} If the output buffer is not large enough, SQLITE_CANTOPEN
-** should be returned. As this is handled as a fatal error by SQLite,
-** vfs implementations should endeavor to prevent this by setting
-** mxPathname to a sufficiently large value.
-**
-** The xRandomness(), xSleep(), and xCurrentTime() interfaces
-** are not strictly a part of the filesystem, but they are
-** included in the VFS structure for completeness.
-** The xRandomness() function attempts to return nBytes bytes
-** of good-quality randomness into zOut. The return value is
-** the actual number of bytes of randomness obtained. The
-** xSleep() method cause the calling thread to sleep for at
-** least the number of microseconds given. The xCurrentTime()
-** method returns a Julian Day Number for the current date and
-** time.
-*/
-typedef struct sqlite3_vfs sqlite3_vfs;
-struct sqlite3_vfs {
- int iVersion; /* Structure version number */
- int szOsFile; /* Size of subclassed sqlite3_file */
- int mxPathname; /* Maximum file pathname length */
- sqlite3_vfs *pNext; /* Next registered VFS */
- const char *zName; /* Name of this virtual file system */
- void *pAppData; /* Pointer to application-specific data */
- int (*xOpen)(sqlite3_vfs*, const char *zName, sqlite3_file*,
- int flags, int *pOutFlags);
- int (*xDelete)(sqlite3_vfs*, const char *zName, int syncDir);
- int (*xAccess)(sqlite3_vfs*, const char *zName, int flags);
- int (*xGetTempname)(sqlite3_vfs*, int nOut, char *zOut);
- int (*xFullPathname)(sqlite3_vfs*, const char *zName, int nOut, char *zOut);
- void *(*xDlOpen)(sqlite3_vfs*, const char *zFilename);
- void (*xDlError)(sqlite3_vfs*, int nByte, char *zErrMsg);
- void *(*xDlSym)(sqlite3_vfs*,void*, const char *zSymbol);
- void (*xDlClose)(sqlite3_vfs*, void*);
- int (*xRandomness)(sqlite3_vfs*, int nByte, char *zOut);
- int (*xSleep)(sqlite3_vfs*, int microseconds);
- int (*xCurrentTime)(sqlite3_vfs*, double*);
- /* New fields may be appended in figure versions. The iVersion
- ** value will increment whenever this happens. */
-};
-
-/*
-** CAPI3REF: Flags for the xAccess VFS method {F11190}
-**
-** {F11191} These integer constants can be used as the third parameter to
-** the xAccess method of an [sqlite3_vfs] object. {END} They determine
-** the kind of what kind of permissions the xAccess method is
-** looking for. {F11192} With SQLITE_ACCESS_EXISTS, the xAccess method
-** simply checks to see if the file exists. {F11193} With
-** SQLITE_ACCESS_READWRITE, the xAccess method checks to see
-** if the file is both readable and writable. {F11194} With
-** SQLITE_ACCESS_READ the xAccess method
-** checks to see if the file is readable.
-*/
-#define SQLITE_ACCESS_EXISTS 0
-#define SQLITE_ACCESS_READWRITE 1
-#define SQLITE_ACCESS_READ 2
-
-/*
-** CAPI3REF: Enable Or Disable Extended Result Codes {F12200}
-**
-** The sqlite3_extended_result_codes() routine enables or disables the
-** [SQLITE_IOERR_READ | extended result codes] feature of SQLite.
-** The extended result codes are disabled by default for historical
-** compatibility.
-**
-** INVARIANTS:
-**
-** {F12201} Each new [database connection] has the
-** [extended result codes] feature
-** disabled by default.
-**
-** {F12202} The [sqlite3_extended_result_codes(D,F)] interface will enable
-** [extended result codes] for the
-** [database connection] D if the F parameter
-** is true, or disable them if F is false.
-*/
-int sqlite3_extended_result_codes(sqlite3*, int onoff);
-
-/*
-** CAPI3REF: Last Insert Rowid {F12220}
-**
-** Each entry in an SQLite table has a unique 64-bit signed
-** integer key called the "rowid". The rowid is always available
-** as an undeclared column named ROWID, OID, or _ROWID_ as long as those
-** names are not also used by explicitly declared columns. If
-** the table has a column of type INTEGER PRIMARY KEY then that column
-** is another an alias for the rowid.
-**
-** This routine returns the rowid of the most recent
-** successful INSERT into the database from the database connection
-** shown in the first argument. If no successful inserts
-** have ever occurred on this database connection, zero is returned.
-**
-** If an INSERT occurs within a trigger, then the rowid of the
-** inserted row is returned by this routine as long as the trigger
-** is running. But once the trigger terminates, the value returned
-** by this routine reverts to the last value inserted before the
-** trigger fired.
-**
-** An INSERT that fails due to a constraint violation is not a
-** successful insert and does not change the value returned by this
-** routine. Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK,
-** and INSERT OR ABORT make no changes to the return value of this
-** routine when their insertion fails. When INSERT OR REPLACE
-** encounters a constraint violation, it does not fail. The
-** INSERT continues to completion after deleting rows that caused
-** the constraint problem so INSERT OR REPLACE will always change
-** the return value of this interface.
-**
-** For the purposes of this routine, an insert is considered to
-** be successful even if it is subsequently rolled back.
-**
-** INVARIANTS:
-**
-** {F12221} The [sqlite3_last_insert_rowid()] function returns the
-** rowid of the most recent successful insert done
-** on the same database connection and within the same
-** trigger context, or zero if there have
-** been no qualifying inserts on that connection.
-**
-** {F12223} The [sqlite3_last_insert_rowid()] function returns
-** same value when called from the same trigger context
-** immediately before and after a ROLLBACK.
-**
-** LIMITATIONS:
-**
-** {U12232} If separate thread does a new insert on the same
-** database connection while the [sqlite3_last_insert_rowid()]
-** function is running and thus changes the last insert rowid,
-** then the value returned by [sqlite3_last_insert_rowid()] is
-** unpredictable and might not equal either the old or the new
-** last insert rowid.
-*/
-sqlite3_int64 sqlite3_last_insert_rowid(sqlite3*);
-
-/*
-** CAPI3REF: Count The Number Of Rows Modified {F12240}
-**
-** This function returns the number of database rows that were changed
-** or inserted or deleted by the most recently completed SQL statement
-** on the connection specified by the first parameter. Only
-** changes that are directly specified by the INSERT, UPDATE, or
-** DELETE statement are counted. Auxiliary changes caused by
-** triggers are not counted. Use the [sqlite3_total_changes()] function
-** to find the total number of changes including changes caused by triggers.
-**
-** A "row changes" is a change to a single row of a single table
-** caused by an INSERT, DELETE, or UPDATE statement. Rows that
-** are changed as side effects of REPLACE constraint resolution,
-** rollback, ABORT processing, DROP TABLE, or by any other
-** mechanisms do not count as direct row changes.
-**
-** A "trigger context" is a scope of execution that begins and
-** ends with the script of a trigger. Most SQL statements are
-** evaluated outside of any trigger. This is the "top level"
-** trigger context. If a trigger fires from the top level, a
-** new trigger context is entered for the duration of that one
-** trigger. Subtriggers create subcontexts for their duration.
-**
-** Calling [sqlite3_exec()] or [sqlite3_step()] recursively does
-** not create a new trigger context.
-**
-** This function returns the number of direct row changes in the
-** most recent INSERT, UPDATE, or DELETE statement within the same
-** trigger context.
-**
-** So when called from the top level, this function returns the
-** number of changes in the most recent INSERT, UPDATE, or DELETE
-** that also occurred at the top level.
-** Within the body of a trigger, the sqlite3_changes() interface
-** can be called to find the number of
-** changes in the most recently completed INSERT, UPDATE, or DELETE
-** statement within the body of the same trigger.
-** However, the number returned does not include in changes
-** caused by subtriggers since they have their own context.
-**
-** SQLite implements the command "DELETE FROM table" without
-** a WHERE clause by dropping and recreating the table. (This is much
-** faster than going through and deleting individual elements from the
-** table.) Because of this optimization, the deletions in
-** "DELETE FROM table" are not row changes and will not be counted
-** by the sqlite3_changes() or [sqlite3_total_changes()] functions.
-** To get an accurate count of the number of rows deleted, use
-** "DELETE FROM table WHERE 1" instead.
-**
-** INVARIANTS:
-**
-** {F12241} The [sqlite3_changes()] function returns the number of
-** row changes caused by the most recent INSERT, UPDATE,
-** or DELETE statement on the same database connection and
-** within the same trigger context, or zero if there have
-** not been any qualifying row changes.
-**
-** LIMITATIONS:
-**
-** {U12252} If a separate thread makes changes on the same database connection
-** while [sqlite3_changes()] is running then the value returned
-** is unpredictable and unmeaningful.
-*/
-int sqlite3_changes(sqlite3*);
-
-/*
-** CAPI3REF: Total Number Of Rows Modified {F12260}
-***
-** This function returns the number of row changes caused
-** by INSERT, UPDATE or DELETE statements since the database handle
-** was opened. The count includes all changes from all trigger
-** contexts. But the count does not include changes used to
-** implement REPLACE constraints, do rollbacks or ABORT processing,
-** or DROP table processing.
-** The changes
-** are counted as soon as the statement that makes them is completed
-** (when the statement handle is passed to [sqlite3_reset()] or
-** [sqlite3_finalize()]).
-**
-** SQLite implements the command "DELETE FROM table" without
-** a WHERE clause by dropping and recreating the table. (This is much
-** faster than going
-** through and deleting individual elements form the table.) Because of
-** this optimization, the change count for "DELETE FROM table" will be
-** zero regardless of the number of elements that were originally in the
-** table. To get an accurate count of the number of rows deleted, use
-** "DELETE FROM table WHERE 1" instead.
-**
-** See also the [sqlite3_changes()] interface.
-**
-** INVARIANTS:
-**
-** {F12261} The [sqlite3_total_changes()] returns the total number
-** of row changes caused by INSERT, UPDATE, and/or DELETE
-** statements on the same [database connection], in any
-** trigger context, since the database connection was
-** created.
-**
-** LIMITATIONS:
-**
-** {U12264} If a separate thread makes changes on the same database connection
-** while [sqlite3_total_changes()] is running then the value
-** returned is unpredictable and unmeaningful.
-*/
-int sqlite3_total_changes(sqlite3*);
-
-/*
-** CAPI3REF: Interrupt A Long-Running Query {F12270}
-**
-** This function causes any pending database operation to abort and
-** return at its earliest opportunity. This routine is typically
-** called in response to a user action such as pressing "Cancel"
-** or Ctrl-C where the user wants a long query operation to halt
-** immediately.
-**
-** It is safe to call this routine from a thread different from the
-** thread that is currently running the database operation. But it
-** is not safe to call this routine with a database connection that
-** is closed or might close before sqlite3_interrupt() returns.
-**
-** If an SQL is very nearly finished at the time when sqlite3_interrupt()
-** is called, then it might not have an opportunity to be interrupted.
-** It might continue to completion.
-** An SQL operation that is interrupted will return
-** [SQLITE_INTERRUPT]. If the interrupted SQL operation is an
-** INSERT, UPDATE, or DELETE that is inside an explicit transaction,
-** then the entire transaction will be rolled back automatically.
-** A call to sqlite3_interrupt() has no effect on SQL statements
-** that are started after sqlite3_interrupt() returns.
-**
-** INVARIANTS:
-**
-** {F12271} The [sqlite3_interrupt()] interface will force all running
-** SQL statements associated with the same database connection
-** to halt after processing at most one additional row of
-** data.
-**
-** {F12272} Any SQL statement that is interrupted by [sqlite3_interrupt()]
-** will return [SQLITE_INTERRUPT].
-**
-** LIMITATIONS:
-**
-** {U12279} If the database connection closes while [sqlite3_interrupt()]
-** is running then bad things will likely happen.
-*/
-void sqlite3_interrupt(sqlite3*);
-
-/*
-** CAPI3REF: Determine If An SQL Statement Is Complete {F10510}
-**
-** These routines are useful for command-line input to determine if the
-** currently entered text seems to form complete a SQL statement or
-** if additional input is needed before sending the text into
-** SQLite for parsing. These routines return true if the input string
-** appears to be a complete SQL statement. A statement is judged to be
-** complete if it ends with a semicolon token and is not a fragment of a
-** CREATE TRIGGER statement. Semicolons that are embedded within
-** string literals or quoted identifier names or comments are not
-** independent tokens (they are part of the token in which they are
-** embedded) and thus do not count as a statement terminator.
-**
-** These routines do not parse the SQL and
-** so will not detect syntactically incorrect SQL.
-**
-** INVARIANTS:
-**
-** {F10511} The sqlite3_complete() and sqlite3_complete16() functions
-** return true (non-zero) if and only if the last
-** non-whitespace token in their input is a semicolon that
-** is not in between the BEGIN and END of a CREATE TRIGGER
-** statement.
-**
-** LIMITATIONS:
-**
-** {U10512} The input to sqlite3_complete() must be a zero-terminated
-** UTF-8 string.
-**
-** {U10513} The input to sqlite3_complete16() must be a zero-terminated
-** UTF-16 string in native byte order.
-*/
-int sqlite3_complete(const char *sql);
-int sqlite3_complete16(const void *sql);
-
-/*
-** CAPI3REF: Register A Callback To Handle SQLITE_BUSY Errors {F12310}
-**
-** This routine identifies a callback function that might be
-** invoked whenever an attempt is made to open a database table
-** that another thread or process has locked.
-** If the busy callback is NULL, then [SQLITE_BUSY]
-** or [SQLITE_IOERR_BLOCKED]
-** is returned immediately upon encountering the lock.
-** If the busy callback is not NULL, then the
-** callback will be invoked with two arguments. The
-** first argument to the handler is a copy of the void* pointer which
-** is the third argument to this routine. The second argument to
-** the handler is the number of times that the busy handler has
-** been invoked for this locking event. If the
-** busy callback returns 0, then no additional attempts are made to
-** access the database and [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED] is returned.
-** If the callback returns non-zero, then another attempt
-** is made to open the database for reading and the cycle repeats.
-**
-** The presence of a busy handler does not guarantee that
-** it will be invoked when there is lock contention.
-** If SQLite determines that invoking the busy handler could result in
-** a deadlock, it will go ahead and return [SQLITE_BUSY] or
-** [SQLITE_IOERR_BLOCKED] instead of invoking the
-** busy handler.
-** Consider a scenario where one process is holding a read lock that
-** it is trying to promote to a reserved lock and
-** a second process is holding a reserved lock that it is trying
-** to promote to an exclusive lock. The first process cannot proceed
-** because it is blocked by the second and the second process cannot
-** proceed because it is blocked by the first. If both processes
-** invoke the busy handlers, neither will make any progress. Therefore,
-** SQLite returns [SQLITE_BUSY] for the first process, hoping that this
-** will induce the first process to release its read lock and allow
-** the second process to proceed.
-**
-** The default busy callback is NULL.
-**
-** The [SQLITE_BUSY] error is converted to [SQLITE_IOERR_BLOCKED]
-** when SQLite is in the middle of a large transaction where all the
-** changes will not fit into the in-memory cache. SQLite will
-** already hold a RESERVED lock on the database file, but it needs
-** to promote this lock to EXCLUSIVE so that it can spill cache
-** pages into the database file without harm to concurrent
-** readers. If it is unable to promote the lock, then the in-memory
-** cache will be left in an inconsistent state and so the error
-** code is promoted from the relatively benign [SQLITE_BUSY] to
-** the more severe [SQLITE_IOERR_BLOCKED]. This error code promotion
-** forces an automatic rollback of the changes. See the
-** <a href="http://www.sqlite.org/cvstrac/wiki?p=CorruptionFollowingBusyError">
-** CorruptionFollowingBusyError</a> wiki page for a discussion of why
-** this is important.
-**
-** There can only be a single busy handler defined for each database
-** connection. Setting a new busy handler clears any previous one.
-** Note that calling [sqlite3_busy_timeout()] will also set or clear
-** the busy handler.
-**
-** INVARIANTS:
-**
-** {F12311} The [sqlite3_busy_handler()] function replaces the busy handler
-** callback in the database connection identified by the 1st
-** parameter with a new busy handler identified by the 2nd and 3rd
-** parameters.
-**
-** {F12312} The default busy handler for new database connections is NULL.
-**
-** {F12314} When two or more database connection share a common cache,
-** the busy handler for the database connection currently using
-** the cache is invoked when the cache encounters a lock.
-**
-** {F12316} If a busy handler callback returns zero, then the SQLite
-** interface that provoked the locking event will return
-** [SQLITE_BUSY].
-**
-** {F12318} SQLite will invokes the busy handler with two argument which
-** are a copy of the pointer supplied by the 3rd parameter to
-** [sqlite3_busy_handler()] and a count of the number of prior
-** invocations of the busy handler for the same locking event.
-**
-** LIMITATIONS:
-**
-** {U12319} A busy handler should not call close the database connection
-** or prepared statement that invoked the busy handler.
-*/
-int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*);
-
-/*
-** CAPI3REF: Set A Busy Timeout {F12340}
-**
-** This routine sets a [sqlite3_busy_handler | busy handler]
-** that sleeps for a while when a
-** table is locked. The handler will sleep multiple times until
-** at least "ms" milliseconds of sleeping have been done. {F12343} After
-** "ms" milliseconds of sleeping, the handler returns 0 which
-** causes [sqlite3_step()] to return [SQLITE_BUSY] or [SQLITE_IOERR_BLOCKED].
-**
-** Calling this routine with an argument less than or equal to zero
-** turns off all busy handlers.
-**
-** There can only be a single busy handler for a particular database
-** connection. If another busy handler was defined
-** (using [sqlite3_busy_handler()]) prior to calling
-** this routine, that other busy handler is cleared.
-**
-** INVARIANTS:
-**
-** {F12341} The [sqlite3_busy_timeout()] function overrides any prior
-** [sqlite3_busy_timeout()] or [sqlite3_busy_handler()] setting
-** on the same database connection.
-**
-** {F12343} If the 2nd parameter to [sqlite3_busy_timeout()] is less than
-** or equal to zero, then the busy handler is cleared so that
-** all subsequent locking events immediately return [SQLITE_BUSY].
-**
-** {F12344} If the 2nd parameter to [sqlite3_busy_timeout()] is a positive
-** number N, then a busy handler is set that repeatedly calls
-** the xSleep() method in the VFS interface until either the
-** lock clears or until the cumulative sleep time reported back
-** by xSleep() exceeds N milliseconds.
-*/
-int sqlite3_busy_timeout(sqlite3*, int ms);
-
-/*
-** CAPI3REF: Convenience Routines For Running Queries {F12370}
-**
-** Definition: A <b>result table</b> is memory data structure created by the
-** [sqlite3_get_table()] interface. A result table records the
-** complete query results from one or more queries.
-**
-** The table conceptually has a number of rows and columns. But
-** these numbers are not part of the result table itself. These
-** numbers are obtained separately. Let N be the number of rows
-** and M be the number of columns.
-**
-** A result table is an array of pointers to zero-terminated
-** UTF-8 strings. There are (N+1)*M elements in the array.
-** The first M pointers point to zero-terminated strings that
-** contain the names of the columns.
-** The remaining entries all point to query results. NULL
-** values are give a NULL pointer. All other values are in
-** their UTF-8 zero-terminated string representation as returned by
-** [sqlite3_column_text()].
-**
-** A result table might consists of one or more memory allocations.
-** It is not safe to pass a result table directly to [sqlite3_free()].
-** A result table should be deallocated using [sqlite3_free_table()].
-**
-** As an example of the result table format, suppose a query result
-** is as follows:
-**
-** <blockquote><pre>
-** Name | Age
-** -----------------------
-** Alice | 43
-** Bob | 28
-** Cindy | 21
-** </pre></blockquote>
-**
-** There are two column (M==2) and three rows (N==3). Thus the
-** result table has 8 entries. Suppose the result table is stored
-** in an array names azResult. Then azResult holds this content:
-**
-** <blockquote><pre>
-** azResult[0] = "Name";
-** azResult[1] = "Age";
-** azResult[2] = "Alice";
-** azResult[3] = "43";
-** azResult[4] = "Bob";
-** azResult[5] = "28";
-** azResult[6] = "Cindy";
-** azResult[7] = "21";
-** </pre></blockquote>
-**
-** The sqlite3_get_table() function evaluates one or more
-** semicolon-separated SQL statements in the zero-terminated UTF-8
-** string of its 2nd parameter. It returns a result table to the
-** pointer given in its 3rd parameter.
-**
-** After the calling function has finished using the result, it should
-** pass the pointer to the result table to sqlite3_free_table() in order to
-** release the memory that was malloc-ed. Because of the way the
-** [sqlite3_malloc()] happens within sqlite3_get_table(), the calling
-** function must not try to call [sqlite3_free()] directly. Only
-** [sqlite3_free_table()] is able to release the memory properly and safely.
-**
-** The sqlite3_get_table() interface is implemented as a wrapper around
-** [sqlite3_exec()]. The sqlite3_get_table() routine does not have access
-** to any internal data structures of SQLite. It uses only the public
-** interface defined here. As a consequence, errors that occur in the
-** wrapper layer outside of the internal [sqlite3_exec()] call are not
-** reflected in subsequent calls to [sqlite3_errcode()] or
-** [sqlite3_errmsg()].
-**
-** INVARIANTS:
-**
-** {F12371} If a [sqlite3_get_table()] fails a memory allocation, then
-** it frees the result table under construction, aborts the
-** query in process, skips any subsequent queries, sets the
-** *resultp output pointer to NULL and returns [SQLITE_NOMEM].
-**
-** {F12373} If the ncolumn parameter to [sqlite3_get_table()] is not NULL
-** then [sqlite3_get_table()] write the number of columns in the
-** result set of the query into *ncolumn if the query is
-** successful (if the function returns SQLITE_OK).
-**
-** {F12374} If the nrow parameter to [sqlite3_get_table()] is not NULL
-** then [sqlite3_get_table()] write the number of rows in the
-** result set of the query into *nrow if the query is
-** successful (if the function returns SQLITE_OK).
-**
-** {F12376} The [sqlite3_get_table()] function sets its *ncolumn value
-** to the number of columns in the result set of the query in the
-** sql parameter, or to zero if the query in sql has an empty
-** result set.
-*/
-int sqlite3_get_table(
- sqlite3*, /* An open database */
- const char *sql, /* SQL to be evaluated */
- char ***pResult, /* Results of the query */
- int *nrow, /* Number of result rows written here */
- int *ncolumn, /* Number of result columns written here */
- char **errmsg /* Error msg written here */
-);
-void sqlite3_free_table(char **result);
-
-/*
-** CAPI3REF: Formatted String Printing Functions {F17400}
-**
-** These routines are workalikes of the "printf()" family of functions
-** from the standard C library.
-**
-** The sqlite3_mprintf() and sqlite3_vmprintf() routines write their
-** results into memory obtained from [sqlite3_malloc()].
-** The strings returned by these two routines should be
-** released by [sqlite3_free()]. Both routines return a
-** NULL pointer if [sqlite3_malloc()] is unable to allocate enough
-** memory to hold the resulting string.
-**
-** In sqlite3_snprintf() routine is similar to "snprintf()" from
-** the standard C library. The result is written into the
-** buffer supplied as the second parameter whose size is given by
-** the first parameter. Note that the order of the
-** first two parameters is reversed from snprintf(). This is an
-** historical accident that cannot be fixed without breaking
-** backwards compatibility. Note also that sqlite3_snprintf()
-** returns a pointer to its buffer instead of the number of
-** characters actually written into the buffer. We admit that
-** the number of characters written would be a more useful return
-** value but we cannot change the implementation of sqlite3_snprintf()
-** now without breaking compatibility.
-**
-** As long as the buffer size is greater than zero, sqlite3_snprintf()
-** guarantees that the buffer is always zero-terminated. The first
-** parameter "n" is the total size of the buffer, including space for
-** the zero terminator. So the longest string that can be completely
-** written will be n-1 characters.
-**
-** These routines all implement some additional formatting
-** options that are useful for constructing SQL statements.
-** All of the usual printf formatting options apply. In addition, there
-** is are "%q", "%Q", and "%z" options.
-**
-** The %q option works like %s in that it substitutes a null-terminated
-** string from the argument list. But %q also doubles every '\'' character.
-** %q is designed for use inside a string literal. By doubling each '\''
-** character it escapes that character and allows it to be inserted into
-** the string.
-**
-** For example, so some string variable contains text as follows:
-**
-** <blockquote><pre>
-** char *zText = "It's a happy day!";
-** </pre></blockquote>
-**
-** One can use this text in an SQL statement as follows:
-**
-** <blockquote><pre>
-** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES('%q')", zText);
-** sqlite3_exec(db, zSQL, 0, 0, 0);
-** sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** Because the %q format string is used, the '\'' character in zText
-** is escaped and the SQL generated is as follows:
-**
-** <blockquote><pre>
-** INSERT INTO table1 VALUES('It''s a happy day!')
-** </pre></blockquote>
-**
-** This is correct. Had we used %s instead of %q, the generated SQL
-** would have looked like this:
-**
-** <blockquote><pre>
-** INSERT INTO table1 VALUES('It's a happy day!');
-** </pre></blockquote>
-**
-** This second example is an SQL syntax error. As a general rule you
-** should always use %q instead of %s when inserting text into a string
-** literal.
-**
-** The %Q option works like %q except it also adds single quotes around
-** the outside of the total string. Or if the parameter in the argument
-** list is a NULL pointer, %Q substitutes the text "NULL" (without single
-** quotes) in place of the %Q option. {END} So, for example, one could say:
-**
-** <blockquote><pre>
-** char *zSQL = sqlite3_mprintf("INSERT INTO table VALUES(%Q)", zText);
-** sqlite3_exec(db, zSQL, 0, 0, 0);
-** sqlite3_free(zSQL);
-** </pre></blockquote>
-**
-** The code above will render a correct SQL statement in the zSQL
-** variable even if the zText variable is a NULL pointer.
-**
-** The "%z" formatting option works exactly like "%s" with the
-** addition that after the string has been read and copied into
-** the result, [sqlite3_free()] is called on the input string. {END}
-**
-** INVARIANTS:
-**
-** {F17403} The [sqlite3_mprintf()] and [sqlite3_vmprintf()] interfaces
-** return either pointers to zero-terminated UTF-8 strings held in
-** memory obtained from [sqlite3_malloc()] or NULL pointers if
-** a call to [sqlite3_malloc()] fails.
-**
-** {F17406} The [sqlite3_snprintf()] interface writes a zero-terminated
-** UTF-8 string into the buffer pointed to by the second parameter
-** provided that the first parameter is greater than zero.
-**
-** {F17407} The [sqlite3_snprintf()] interface does not writes slots of
-** its output buffer (the second parameter) outside the range
-** of 0 through N-1 (where N is the first parameter)
-** regardless of the length of the string
-** requested by the format specification.
-**
-*/
-char *sqlite3_mprintf(const char*,...);
-char *sqlite3_vmprintf(const char*, va_list);
-char *sqlite3_snprintf(int,char*,const char*, ...);
-
-/*
-** CAPI3REF: Memory Allocation Subsystem {F17300}
-**
-** The SQLite core uses these three routines for all of its own
-** internal memory allocation needs. "Core" in the previous sentence
-** does not include operating-system specific VFS implementation. The
-** windows VFS uses native malloc and free for some operations.
-**
-** The sqlite3_malloc() routine returns a pointer to a block
-** of memory at least N bytes in length, where N is the parameter.
-** If sqlite3_malloc() is unable to obtain sufficient free
-** memory, it returns a NULL pointer. If the parameter N to
-** sqlite3_malloc() is zero or negative then sqlite3_malloc() returns
-** a NULL pointer.
-**
-** Calling sqlite3_free() with a pointer previously returned
-** by sqlite3_malloc() or sqlite3_realloc() releases that memory so
-** that it might be reused. The sqlite3_free() routine is
-** a no-op if is called with a NULL pointer. Passing a NULL pointer
-** to sqlite3_free() is harmless. After being freed, memory
-** should neither be read nor written. Even reading previously freed
-** memory might result in a segmentation fault or other severe error.
-** Memory corruption, a segmentation fault, or other severe error
-** might result if sqlite3_free() is called with a non-NULL pointer that
-** was not obtained from sqlite3_malloc() or sqlite3_free().
-**
-** The sqlite3_realloc() interface attempts to resize a
-** prior memory allocation to be at least N bytes, where N is the
-** second parameter. The memory allocation to be resized is the first
-** parameter. If the first parameter to sqlite3_realloc()
-** is a NULL pointer then its behavior is identical to calling
-** sqlite3_malloc(N) where N is the second parameter to sqlite3_realloc().
-** If the second parameter to sqlite3_realloc() is zero or
-** negative then the behavior is exactly the same as calling
-** sqlite3_free(P) where P is the first parameter to sqlite3_realloc().
-** Sqlite3_realloc() returns a pointer to a memory allocation
-** of at least N bytes in size or NULL if sufficient memory is unavailable.
-** If M is the size of the prior allocation, then min(N,M) bytes
-** of the prior allocation are copied into the beginning of buffer returned
-** by sqlite3_realloc() and the prior allocation is freed.
-** If sqlite3_realloc() returns NULL, then the prior allocation
-** is not freed.
-**
-** The memory returned by sqlite3_malloc() and sqlite3_realloc()
-** is always aligned to at least an 8 byte boundary. {END}
-**
-** The default implementation
-** of the memory allocation subsystem uses the malloc(), realloc()
-** and free() provided by the standard C library. {F17382} However, if
-** SQLite is compiled with the following C preprocessor macro
-**
-** <blockquote> SQLITE_MEMORY_SIZE=<i>NNN</i> </blockquote>
-**
-** where <i>NNN</i> is an integer, then SQLite create a static
-** array of at least <i>NNN</i> bytes in size and use that array
-** for all of its dynamic memory allocation needs. {END} Additional
-** memory allocator options may be added in future releases.
-**
-** In SQLite version 3.5.0 and 3.5.1, it was possible to define
-** the SQLITE_OMIT_MEMORY_ALLOCATION which would cause the built-in
-** implementation of these routines to be omitted. That capability
-** is no longer provided. Only built-in memory allocators can be
-** used.
-**
-** The windows OS interface layer calls
-** the system malloc() and free() directly when converting
-** filenames between the UTF-8 encoding used by SQLite
-** and whatever filename encoding is used by the particular windows
-** installation. Memory allocation errors are detected, but
-** they are reported back as [SQLITE_CANTOPEN] or
-** [SQLITE_IOERR] rather than [SQLITE_NOMEM].
-**
-** INVARIANTS:
-**
-** {F17303} The [sqlite3_malloc(N)] interface returns either a pointer to
-** newly checked-out block of at least N bytes of memory
-** that is 8-byte aligned,
-** or it returns NULL if it is unable to fulfill the request.
-**
-** {F17304} The [sqlite3_malloc(N)] interface returns a NULL pointer if
-** N is less than or equal to zero.
-**
-** {F17305} The [sqlite3_free(P)] interface releases memory previously
-** returned from [sqlite3_malloc()] or [sqlite3_realloc()],
-** making it available for reuse.
-**
-** {F17306} A call to [sqlite3_free(NULL)] is a harmless no-op.
-**
-** {F17310} A call to [sqlite3_realloc(0,N)] is equivalent to a call
-** to [sqlite3_malloc(N)].
-**
-** {F17312} A call to [sqlite3_realloc(P,0)] is equivalent to a call
-** to [sqlite3_free(P)].
-**
-** {F17315} The SQLite core uses [sqlite3_malloc()], [sqlite3_realloc()],
-** and [sqlite3_free()] for all of its memory allocation and
-** deallocation needs.
-**
-** {F17318} The [sqlite3_realloc(P,N)] interface returns either a pointer
-** to a block of checked-out memory of at least N bytes in size
-** that is 8-byte aligned, or a NULL pointer.
-**
-** {F17321} When [sqlite3_realloc(P,N)] returns a non-NULL pointer, it first
-** copies the first K bytes of content from P into the newly allocated
-** where K is the lessor of N and the size of the buffer P.
-**
-** {F17322} When [sqlite3_realloc(P,N)] returns a non-NULL pointer, it first
-** releases the buffer P.
-**
-** {F17323} When [sqlite3_realloc(P,N)] returns NULL, the buffer P is
-** not modified or released.
-**
-** LIMITATIONS:
-**
-** {U17350} The pointer arguments to [sqlite3_free()] and [sqlite3_realloc()]
-** must be either NULL or else a pointer obtained from a prior
-** invocation of [sqlite3_malloc()] or [sqlite3_realloc()] that has
-** not been released.
-**
-** {U17351} The application must not read or write any part of
-** a block of memory after it has been released using
-** [sqlite3_free()] or [sqlite3_realloc()].
-**
-*/
-void *sqlite3_malloc(int);
-void *sqlite3_realloc(void*, int);
-void sqlite3_free(void*);
-
-/*
-** CAPI3REF: Memory Allocator Statistics {F17370}
-**
-** SQLite provides these two interfaces for reporting on the status
-** of the [sqlite3_malloc()], [sqlite3_free()], and [sqlite3_realloc()]
-** the memory allocation subsystem included within the SQLite.
-**
-** INVARIANTS:
-**
-** {F17371} The [sqlite3_memory_used()] routine returns the
-** number of bytes of memory currently outstanding
-** (malloced but not freed).
-**
-** {F17373} The [sqlite3_memory_highwater()] routine returns the maximum
-** value of [sqlite3_memory_used()]
-** since the highwater mark was last reset.
-**
-** {F17374} The values returned by [sqlite3_memory_used()] and
-** [sqlite3_memory_highwater()] include any overhead
-** added by SQLite in its implementation of [sqlite3_malloc()],
-** but not overhead added by the any underlying system library
-** routines that [sqlite3_malloc()] may call.
-**
-** {F17375} The memory highwater mark is reset to the current value of
-** [sqlite3_memory_used()] if and only if the parameter to
-** [sqlite3_memory_highwater()] is true. The value returned
-** by [sqlite3_memory_highwater(1)] is the highwater mark
-** prior to the reset.
-*/
-sqlite3_int64 sqlite3_memory_used(void);
-sqlite3_int64 sqlite3_memory_highwater(int resetFlag);
-
-/*
-** CAPI3REF: Compile-Time Authorization Callbacks {F12500}
-**
-** This routine registers a authorizer callback with a particular
-** database connection, supplied in the first argument.
-** The authorizer callback is invoked as SQL statements are being compiled
-** by [sqlite3_prepare()] or its variants [sqlite3_prepare_v2()],
-** [sqlite3_prepare16()] and [sqlite3_prepare16_v2()]. At various
-** points during the compilation process, as logic is being created
-** to perform various actions, the authorizer callback is invoked to
-** see if those actions are allowed. The authorizer callback should
-** return SQLITE_OK to allow the action, [SQLITE_IGNORE] to disallow the
-** specific action but allow the SQL statement to continue to be
-** compiled, or [SQLITE_DENY] to cause the entire SQL statement to be
-** rejected with an error. If the authorizer callback returns
-** any value other than [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY]
-** then [sqlite3_prepare_v2()] or equivalent call that triggered
-** the authorizer will fail with an error message.
-**
-** When the callback returns [SQLITE_OK], that means the operation
-** requested is ok. When the callback returns [SQLITE_DENY], the
-** [sqlite3_prepare_v2()] or equivalent call that triggered the
-** authorizer will fail with an error message explaining that
-** access is denied. If the authorizer code is [SQLITE_READ]
-** and the callback returns [SQLITE_IGNORE] then the prepared
-** statement is constructed to insert a NULL value in place of
-** the table column that would have
-** been read if [SQLITE_OK] had been returned. The [SQLITE_IGNORE]
-** return can be used to deny an untrusted user access to individual
-** columns of a table.
-**
-** The first parameter to the authorizer callback is a copy of
-** the third parameter to the sqlite3_set_authorizer() interface.
-** The second parameter to the callback is an integer
-** [SQLITE_COPY | action code] that specifies the particular action
-** to be authorized. The third through sixth
-** parameters to the callback are zero-terminated strings that contain
-** additional details about the action to be authorized.
-**
-** An authorizer is used when preparing SQL statements from an untrusted
-** source, to ensure that the SQL statements do not try to access data
-** that they are not allowed to see, or that they do not try to
-** execute malicious statements that damage the database. For
-** example, an application may allow a user to enter arbitrary
-** SQL queries for evaluation by a database. But the application does
-** not want the user to be able to make arbitrary changes to the
-** database. An authorizer could then be put in place while the
-** user-entered SQL is being prepared that disallows everything
-** except SELECT statements.
-**
-** Only a single authorizer can be in place on a database connection
-** at a time. Each call to sqlite3_set_authorizer overrides the
-** previous call. Disable the authorizer by installing a NULL callback.
-** The authorizer is disabled by default.
-**
-** Note that the authorizer callback is invoked only during
-** [sqlite3_prepare()] or its variants. Authorization is not
-** performed during statement evaluation in [sqlite3_step()].
-**
-** INVARIANTS:
-**
-** {F12501} The [sqlite3_set_authorizer(D,...)] interface registers a
-** authorizer callback with database connection D.
-**
-** {F12502} The authorizer callback is invoked as SQL statements are
-** being compiled
-**
-** {F12503} If the authorizer callback returns any value other than
-** [SQLITE_IGNORE], [SQLITE_OK], or [SQLITE_DENY] then
-** the [sqlite3_prepare_v2()] or equivalent call that caused
-** the authorizer callback to run shall fail with an
-** [SQLITE_ERROR] error code and an appropriate error message.
-**
-** {F12504} When the authorizer callback returns [SQLITE_OK], the operation
-** described is coded normally.
-**
-** {F12505} When the authorizer callback returns [SQLITE_DENY], the
-** [sqlite3_prepare_v2()] or equivalent call that caused the
-** authorizer callback to run shall fail
-** with an [SQLITE_ERROR] error code and an error message
-** explaining that access is denied.
-**
-** {F12506} If the authorizer code (the 2nd parameter to the authorizer
-** callback) is [SQLITE_READ] and the authorizer callback returns
-** [SQLITE_IGNORE] then the prepared statement is constructed to
-** insert a NULL value in place of the table column that would have
-** been read if [SQLITE_OK] had been returned.
-**
-** {F12507} If the authorizer code (the 2nd parameter to the authorizer
-** callback) is anything other than [SQLITE_READ], then
-** a return of [SQLITE_IGNORE] has the same effect as [SQLITE_DENY].
-**
-** {F12510} The first parameter to the authorizer callback is a copy of
-** the third parameter to the [sqlite3_set_authorizer()] interface.
-**
-** {F12511} The second parameter to the callback is an integer
-** [SQLITE_COPY | action code] that specifies the particular action
-** to be authorized.
-**
-** {F12512} The third through sixth parameters to the callback are
-** zero-terminated strings that contain
-** additional details about the action to be authorized.
-**
-** {F12520} Each call to [sqlite3_set_authorizer()] overrides the
-** any previously installed authorizer.
-**
-** {F12521} A NULL authorizer means that no authorization
-** callback is invoked.
-**
-** {F12522} The default authorizer is NULL.
-*/
-int sqlite3_set_authorizer(
- sqlite3*,
- int (*xAuth)(void*,int,const char*,const char*,const char*,const char*),
- void *pUserData
-);
-
-/*
-** CAPI3REF: Authorizer Return Codes {F12590}
-**
-** The [sqlite3_set_authorizer | authorizer callback function] must
-** return either [SQLITE_OK] or one of these two constants in order
-** to signal SQLite whether or not the action is permitted. See the
-** [sqlite3_set_authorizer | authorizer documentation] for additional
-** information.
-*/
-#define SQLITE_DENY 1 /* Abort the SQL statement with an error */
-#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */
-
-/*
-** CAPI3REF: Authorizer Action Codes {F12550}
-**
-** The [sqlite3_set_authorizer()] interface registers a callback function
-** that is invoked to authorizer certain SQL statement actions. The
-** second parameter to the callback is an integer code that specifies
-** what action is being authorized. These are the integer action codes that
-** the authorizer callback may be passed.
-**
-** These action code values signify what kind of operation is to be
-** authorized. The 3rd and 4th parameters to the authorization
-** callback function will be parameters or NULL depending on which of these
-** codes is used as the second parameter. The 5th parameter to the
-** authorizer callback is the name of the database ("main", "temp",
-** etc.) if applicable. The 6th parameter to the authorizer callback
-** is the name of the inner-most trigger or view that is responsible for
-** the access attempt or NULL if this access attempt is directly from
-** top-level SQL code.
-**
-** INVARIANTS:
-**
-** {F12551} The second parameter to an
-** [sqlite3_set_authorizer | authorizer callback is always an integer
-** [SQLITE_COPY | authorizer code] that specifies what action
-** is being authorized.
-**
-** {F12552} The 3rd and 4th parameters to the
-** [sqlite3_set_authorizer | authorization callback function]
-** will be parameters or NULL depending on which
-** [SQLITE_COPY | authorizer code] is used as the second parameter.
-**
-** {F12553} The 5th parameter to the
-** [sqlite3_set_authorizer | authorizer callback] is the name
-** of the database (example: "main", "temp", etc.) if applicable.
-**
-** {F12554} The 6th parameter to the
-** [sqlite3_set_authorizer | authorizer callback] is the name
-** of the inner-most trigger or view that is responsible for
-** the access attempt or NULL if this access attempt is directly from
-** top-level SQL code.
-*/
-/******************************************* 3rd ************ 4th ***********/
-#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */
-#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */
-#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */
-#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */
-#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */
-#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */
-#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */
-#define SQLITE_CREATE_VIEW 8 /* View Name NULL */
-#define SQLITE_DELETE 9 /* Table Name NULL */
-#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */
-#define SQLITE_DROP_TABLE 11 /* Table Name NULL */
-#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */
-#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */
-#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */
-#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */
-#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */
-#define SQLITE_DROP_VIEW 17 /* View Name NULL */
-#define SQLITE_INSERT 18 /* Table Name NULL */
-#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */
-#define SQLITE_READ 20 /* Table Name Column Name */
-#define SQLITE_SELECT 21 /* NULL NULL */
-#define SQLITE_TRANSACTION 22 /* NULL NULL */
-#define SQLITE_UPDATE 23 /* Table Name Column Name */
-#define SQLITE_ATTACH 24 /* Filename NULL */
-#define SQLITE_DETACH 25 /* Database Name NULL */
-#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */
-#define SQLITE_REINDEX 27 /* Index Name NULL */
-#define SQLITE_ANALYZE 28 /* Table Name NULL */
-#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */
-#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */
-#define SQLITE_FUNCTION 31 /* Function Name NULL */
-#define SQLITE_COPY 0 /* No longer used */
-
-/*
-** CAPI3REF: Tracing And Profiling Functions {F12280}
-**
-** These routines register callback functions that can be used for
-** tracing and profiling the execution of SQL statements.
-**
-** The callback function registered by sqlite3_trace() is invoked at
-** various times when an SQL statement is being run by [sqlite3_step()].
-** The callback returns a UTF-8 rendering of the SQL statement text
-** as the statement first begins executing. Additional callbacks occur
-** as each triggersubprogram is entered. The callbacks for triggers
-** contain a UTF-8 SQL comment that identifies the trigger.
-**
-** The callback function registered by sqlite3_profile() is invoked
-** as each SQL statement finishes. The profile callback contains
-** the original statement text and an estimate of wall-clock time
-** of how long that statement took to run.
-**
-** The sqlite3_profile() API is currently considered experimental and
-** is subject to change or removal in a future release.
-**
-** The trigger reporting feature of the trace callback is considered
-** experimental and is subject to change or removal in future releases.
-** Future versions of SQLite might also add new trace callback
-** invocations.
-**
-** INVARIANTS:
-**
-** {F12281} The callback function registered by [sqlite3_trace()] is
-** whenever an SQL statement first begins to execute and
-** whenever a trigger subprogram first begins to run.
-**
-** {F12282} Each call to [sqlite3_trace()] overrides the previously
-** registered trace callback.
-**
-** {F12283} A NULL trace callback disables tracing.
-**
-** {F12284} The first argument to the trace callback is a copy of
-** the pointer which was the 3rd argument to [sqlite3_trace()].
-**
-** {F12285} The second argument to the trace callback is a
-** zero-terminated UTF8 string containing the original text
-** of the SQL statement as it was passed into [sqlite3_prepare_v2()]
-** or the equivalent, or an SQL comment indicating the beginning
-** of a trigger subprogram.
-**
-** {F12287} The callback function registered by [sqlite3_profile()] is invoked
-** as each SQL statement finishes.
-**
-** {F12288} The first parameter to the profile callback is a copy of
-** the 3rd parameter to [sqlite3_profile()].
-**
-** {F12289} The second parameter to the profile callback is a
-** zero-terminated UTF-8 string that contains the complete text of
-** the SQL statement as it was processed by [sqlite3_prepare_v2()]
-** or the equivalent.
-**
-** {F12290} The third parameter to the profile callback is an estimate
-** of the number of nanoseconds of wall-clock time required to
-** run the SQL statement from start to finish.
-*/
-void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*);
-void *sqlite3_profile(sqlite3*,
- void(*xProfile)(void*,const char*,sqlite3_uint64), void*);
-
-/*
-** CAPI3REF: Query Progress Callbacks {F12910}
-**
-** This routine configures a callback function - the
-** progress callback - that is invoked periodically during long
-** running calls to [sqlite3_exec()], [sqlite3_step()] and
-** [sqlite3_get_table()]. An example use for this
-** interface is to keep a GUI updated during a large query.
-**
-** If the progress callback returns non-zero, the opertion is
-** interrupted. This feature can be used to implement a
-** "Cancel" button on a GUI dialog box.
-**
-** INVARIANTS:
-**
-** {F12911} The callback function registered by [sqlite3_progress_handler()]
-** is invoked periodically during long running calls to
-** [sqlite3_step()].
-**
-** {F12912} The progress callback is invoked once for every N virtual
-** machine opcodes, where N is the second argument to
-** the [sqlite3_progress_handler()] call that registered
-** the callback. <todo>What if N is less than 1?</todo>
-**
-** {F12913} The progress callback itself is identified by the third
-** argument to [sqlite3_progress_handler()].
-**
-** {F12914} The fourth argument [sqlite3_progress_handler()] is a
-*** void pointer passed to the progress callback
-** function each time it is invoked.
-**
-** {F12915} If a call to [sqlite3_step()] results in fewer than
-** N opcodes being executed,
-** then the progress callback is never invoked. {END}
-**
-** {F12916} Every call to [sqlite3_progress_handler()]
-** overwrites any previously registere progress handler.
-**
-** {F12917} If the progress handler callback is NULL then no progress
-** handler is invoked.
-**
-** {F12918} If the progress callback returns a result other than 0, then
-** the behavior is a if [sqlite3_interrupt()] had been called.
-*/
-void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
-
-/*
-** CAPI3REF: Opening A New Database Connection {F12700}
-**
-** These routines open an SQLite database file whose name
-** is given by the filename argument.
-** The filename argument is interpreted as UTF-8
-** for [sqlite3_open()] and [sqlite3_open_v2()] and as UTF-16
-** in the native byte order for [sqlite3_open16()].
-** An [sqlite3*] handle is usually returned in *ppDb, even
-** if an error occurs. The only exception is if SQLite is unable
-** to allocate memory to hold the [sqlite3] object, a NULL will
-** be written into *ppDb instead of a pointer to the [sqlite3] object.
-** If the database is opened (and/or created)
-** successfully, then [SQLITE_OK] is returned. Otherwise an
-** error code is returned. The
-** [sqlite3_errmsg()] or [sqlite3_errmsg16()] routines can be used to obtain
-** an English language description of the error.
-**
-** The default encoding for the database will be UTF-8 if
-** [sqlite3_open()] or [sqlite3_open_v2()] is called and
-** UTF-16 in the native byte order if [sqlite3_open16()] is used.
-**
-** Whether or not an error occurs when it is opened, resources
-** associated with the [sqlite3*] handle should be released by passing it
-** to [sqlite3_close()] when it is no longer required.
-**
-** The [sqlite3_open_v2()] interface works like [sqlite3_open()]
-** except that it acccepts two additional parameters for additional control
-** over the new database connection. The flags parameter can be
-** one of:
-**
-** <ol>
-** <li> [SQLITE_OPEN_READONLY]
-** <li> [SQLITE_OPEN_READWRITE]
-** <li> [SQLITE_OPEN_READWRITE] | [SQLITE_OPEN_CREATE]
-** </ol>
-**
-** The first value opens the database read-only.
-** If the database does not previously exist, an error is returned.
-** The second option opens
-** the database for reading and writing if possible, or reading only if
-** if the file is write protected. In either case the database
-** must already exist or an error is returned. The third option
-** opens the database for reading and writing and creates it if it does
-** not already exist.
-** The third options is behavior that is always used for [sqlite3_open()]
-** and [sqlite3_open16()].
-**
-** If the filename is ":memory:", then an private
-** in-memory database is created for the connection. This in-memory
-** database will vanish when the database connection is closed. Future
-** version of SQLite might make use of additional special filenames
-** that begin with the ":" character. It is recommended that
-** when a database filename really does begin with
-** ":" that you prefix the filename with a pathname like "./" to
-** avoid ambiguity.
-**
-** If the filename is an empty string, then a private temporary
-** on-disk database will be created. This private database will be
-** automatically deleted as soon as the database connection is closed.
-**
-** The fourth parameter to sqlite3_open_v2() is the name of the
-** [sqlite3_vfs] object that defines the operating system
-** interface that the new database connection should use. If the
-** fourth parameter is a NULL pointer then the default [sqlite3_vfs]
-** object is used.
-**
-** <b>Note to windows users:</b> The encoding used for the filename argument
-** of [sqlite3_open()] and [sqlite3_open_v2()] must be UTF-8, not whatever
-** codepage is currently defined. Filenames containing international
-** characters must be converted to UTF-8 prior to passing them into
-** [sqlite3_open()] or [sqlite3_open_v2()].
-**
-** INVARIANTS:
-**
-** {F12701} The [sqlite3_open()], [sqlite3_open16()], and
-** [sqlite3_open_v2()] interfaces create a new
-** [database connection] associated with
-** the database file given in their first parameter.
-**
-** {F12702} The filename argument is interpreted as UTF-8
-** for [sqlite3_open()] and [sqlite3_open_v2()] and as UTF-16
-** in the native byte order for [sqlite3_open16()].
-**
-** {F12703} A successful invocation of [sqlite3_open()], [sqlite3_open16()],
-** or [sqlite3_open_v2()] writes a pointer to a new
-** [database connection] into *ppDb.
-**
-** {F12704} The [sqlite3_open()], [sqlite3_open16()], and
-** [sqlite3_open_v2()] interfaces return [SQLITE_OK] upon success,
-** or an appropriate [error code] on failure.
-**
-** {F12706} The default text encoding for a new database created using
-** [sqlite3_open()] or [sqlite3_open_v2()] will be UTF-8.
-**
-** {F12707} The default text encoding for a new database created using
-** [sqlite3_open16()] will be UTF-16.
-**
-** {F12709} The [sqlite3_open(F,D)] interface is equivalent to
-** [sqlite3_open_v2(F,D,G,0)] where the G parameter is
-** [SQLITE_OPEN_READWRITE]|[SQLITE_OPEN_CREATE].
-**
-** {F12711} If the G parameter to [sqlite3_open_v2(F,D,G,V)] contains the
-** bit value [SQLITE_OPEN_READONLY] then the database is opened
-** for reading only.
-**
-** {F12712} If the G parameter to [sqlite3_open_v2(F,D,G,V)] contains the
-** bit value [SQLITE_OPEN_READWRITE] then the database is opened
-** reading and writing if possible, or for reading only if the
-** file is write protected by the operating system.
-**
-** {F12713} If the G parameter to [sqlite3_open(v2(F,D,G,V)] omits the
-** bit value [SQLITE_OPEN_CREATE] and the database does not
-** previously exist, an error is returned.
-**
-** {F12714} If the G parameter to [sqlite3_open(v2(F,D,G,V)] contains the
-** bit value [SQLITE_OPEN_CREATE] and the database does not
-** previously exist, then an attempt is made to create and
-** initialize the database.
-**
-** {F12717} If the filename argument to [sqlite3_open()], [sqlite3_open16()],
-** or [sqlite3_open_v2()] is ":memory:", then an private,
-** ephemeral, in-memory database is created for the connection.
-** <todo>Is SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE required
-** in sqlite3_open_v2()?</todo>
-**
-** {F12719} If the filename is an empty string, then a private, ephermeral
-** on-disk database will be created.
-** <todo>Is SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE required
-** in sqlite3_open_v2()?</todo>
-**
-** {F12721} The [database connection] created by
-** [sqlite3_open_v2(F,D,G,V)] will use the
-** [sqlite3_vfs] object identified by the V parameter, or
-** the default [sqlite3_vfs] object is V is a NULL pointer.
-*/
-int sqlite3_open(
- const char *filename, /* Database filename (UTF-8) */
- sqlite3 **ppDb /* OUT: SQLite db handle */
-);
-int sqlite3_open16(
- const void *filename, /* Database filename (UTF-16) */
- sqlite3 **ppDb /* OUT: SQLite db handle */
-);
-int sqlite3_open_v2(
- const char *filename, /* Database filename (UTF-8) */
- sqlite3 **ppDb, /* OUT: SQLite db handle */
- int flags, /* Flags */
- const char *zVfs /* Name of VFS module to use */
-);
-
-/*
-** CAPI3REF: Error Codes And Messages {F12800}
-**
-** The sqlite3_errcode() interface returns the numeric
-** [SQLITE_OK | result code] or [SQLITE_IOERR_READ | extended result code]
-** for the most recent failed sqlite3_* API call associated
-** with [sqlite3] handle 'db'. If a prior API call failed but the
-** most recent API call succeeded, the return value from sqlite3_errcode()
-** is undefined.
-**
-** The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
-** text that describes the error, as either UTF8 or UTF16 respectively.
-** Memory to hold the error message string is managed internally.
-** The application does not need to worry with freeing the result.
-** However, the error string might be overwritten or deallocated b
-** subsequent calls to other SQLite interface functions.
-**
-** INVARIANTS:
-**
-** {F12801} The [sqlite3_errcode(D)] interface returns the numeric
-** [SQLITE_OK | result code] or
-** [SQLITE_IOERR_READ | extended result code]
-** for the most recent failed interface call associated
-** with [sqlite3] handle D.
-**
-** {U12802} If a prior API call failed but the most recent API call
-** succeeded, the return value from [sqlite3_errcode()],
-** [sqlite3_errmsg()], and [sqlite3_errmsg16()] are undefined.
-**
-** {F12803} The [sqlite3_errmsg(D)] and [sqlite3_errmsg16(D)]
-** interfaces return English-language text that describes
-** the error in the mostly recently failed interface call,
-** encoded as either UTF8 or UTF16 respectively.
-**
-** {U12804} The strings returned by [sqlite3_errmsg()] and [sqlite3_errmsg16()]
-** are only valid until the next SQLite interface call.
-**
-** {F12807} Calls to [sqlite3_errcode()], [sqlite3_errmsg()], and
-** [sqlite3_errmsg16()] themselves do not affect the
-** results of future invocations of these routines.
-**
-** {F12808} Calls to API routines that do not return an error code
-** (example: [sqlite3_data_count()]) do not
-** change the error code or message returned by
-** [sqlite3_errcode()], [sqlite3_errmsg()], or [sqlite3_errmsg16()].
-**
-** {F12809} Interfaces that are not associated with a specific
-** [database connection] (examples:
-** [sqlite3_mprintf()] or [sqlite3_enable_shared_cache()]
-** do not change the values returned by
-** [sqlite3_errcode()], [sqlite3_errmsg()], or [sqlite3_errmsg16()].
-*/
-int sqlite3_errcode(sqlite3 *db);
-const char *sqlite3_errmsg(sqlite3*);
-const void *sqlite3_errmsg16(sqlite3*);
-
-/*
-** CAPI3REF: SQL Statement Object {F13000}
-** KEYWORDS: {prepared statement} {prepared statements}
-**
-** An instance of this object represent single SQL statements. This
-** object is variously known as a "prepared statement" or a
-** "compiled SQL statement" or simply as a "statement".
-**
-** The life of a statement object goes something like this:
-**
-** <ol>
-** <li> Create the object using [sqlite3_prepare_v2()] or a related
-** function.
-** <li> Bind values to host parameters using
-** [sqlite3_bind_blob | sqlite3_bind_* interfaces].
-** <li> Run the SQL by calling [sqlite3_step()] one or more times.
-** <li> Reset the statement using [sqlite3_reset()] then go back
-** to step 2. Do this zero or more times.
-** <li> Destroy the object using [sqlite3_finalize()].
-** </ol>
-**
-** Refer to documentation on individual methods above for additional
-** information.
-*/
-typedef struct sqlite3_stmt sqlite3_stmt;
-
-/*
-** CAPI3REF: Compiling An SQL Statement {F13010}
-**
-** To execute an SQL query, it must first be compiled into a byte-code
-** program using one of these routines.
-**
-** The first argument "db" is an [database connection]
-** obtained from a prior call to [sqlite3_open()], [sqlite3_open_v2()]
-** or [sqlite3_open16()].
-** The second argument "zSql" is the statement to be compiled, encoded
-** as either UTF-8 or UTF-16. The sqlite3_prepare() and sqlite3_prepare_v2()
-** interfaces uses UTF-8 and sqlite3_prepare16() and sqlite3_prepare16_v2()
-** use UTF-16. {END}
-**
-** If the nByte argument is less
-** than zero, then zSql is read up to the first zero terminator.
-** If nByte is non-negative, then it is the maximum number of
-** bytes read from zSql. When nByte is non-negative, the
-** zSql string ends at either the first '\000' or '\u0000' character or
-** until the nByte-th byte, whichever comes first. {END}
-**
-** *pzTail is made to point to the first byte past the end of the
-** first SQL statement in zSql. These routines only compiles the first
-** statement in zSql, so *pzTail is left pointing to what remains
-** uncompiled.
-**
-** *ppStmt is left pointing to a compiled [prepared statement] that can be
-** executed using [sqlite3_step()]. Or if there is an error, *ppStmt may be
-** set to NULL. If the input text contains no SQL (if the input
-** is and empty string or a comment) then *ppStmt is set to NULL.
-** {U13018} The calling procedure is responsible for deleting the
-** compiled SQL statement
-** using [sqlite3_finalize()] after it has finished with it.
-**
-** On success, [SQLITE_OK] is returned. Otherwise an
-** [error code] is returned.
-**
-** The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are
-** recommended for all new programs. The two older interfaces are retained
-** for backwards compatibility, but their use is discouraged.
-** In the "v2" interfaces, the prepared statement
-** that is returned (the [sqlite3_stmt] object) contains a copy of the
-** original SQL text. {END} This causes the [sqlite3_step()] interface to
-** behave a differently in two ways:
-**
-** <ol>
-** <li>
-** If the database schema changes, instead of returning [SQLITE_SCHEMA] as it
-** always used to do, [sqlite3_step()] will automatically recompile the SQL
-** statement and try to run it again. If the schema has changed in
-** a way that makes the statement no longer valid, [sqlite3_step()] will still
-** return [SQLITE_SCHEMA]. But unlike the legacy behavior,
-** [SQLITE_SCHEMA] is now a fatal error. Calling
-** [sqlite3_prepare_v2()] again will not make the
-** error go away. Note: use [sqlite3_errmsg()] to find the text
-** of the parsing error that results in an [SQLITE_SCHEMA] return. {END}
-** </li>
-**
-** <li>
-** When an error occurs,
-** [sqlite3_step()] will return one of the detailed
-** [error codes] or [extended error codes].
-** The legacy behavior was that [sqlite3_step()] would only return a generic
-** [SQLITE_ERROR] result code and you would have to make a second call to
-** [sqlite3_reset()] in order to find the underlying cause of the problem.
-** With the "v2" prepare interfaces, the underlying reason for the error is
-** returned immediately.
-** </li>
-** </ol>
-**
-** INVARIANTS:
-**
-** {F13011} The [sqlite3_prepare(db,zSql,...)] and
-** [sqlite3_prepare_v2(db,zSql,...)] interfaces interpret the
-** text in their zSql parameter as UTF-8.
-**
-** {F13012} The [sqlite3_prepare16(db,zSql,...)] and
-** [sqlite3_prepare16_v2(db,zSql,...)] interfaces interpret the
-** text in their zSql parameter as UTF-16 in the native byte order.
-**
-** {F13013} If the nByte argument to [sqlite3_prepare_v2(db,zSql,nByte,...)]
-** and its variants is less than zero, then SQL text is
-** read from zSql is read up to the first zero terminator.
-**
-** {F13014} If the nByte argument to [sqlite3_prepare_v2(db,zSql,nByte,...)]
-** and its variants is non-negative, then nBytes bytes
-** SQL text is read from zSql.
-**
-** {F13015} In [sqlite3_prepare_v2(db,zSql,N,P,pzTail)] and its variants
-** if the zSql input text contains more than one SQL statement
-** and pzTail is not NULL, then *pzTail is made to point to the
-** first byte past the end of the first SQL statement in zSql.
-** <todo>What does *pzTail point to if there is one statement?</todo>
-**
-** {F13016} A successful call to [sqlite3_prepare_v2(db,zSql,N,ppStmt,...)]
-** or one of its variants writes into *ppStmt a pointer to a new
-** [prepared statement] or a pointer to NULL
-** if zSql contains nothing other than whitespace or comments.
-**
-** {F13019} The [sqlite3_prepare_v2()] interface and its variants return
-** [SQLITE_OK] or an appropriate [error code] upon failure.
-*/
-int sqlite3_prepare(
- sqlite3 *db, /* Database handle */
- const char *zSql, /* SQL statement, UTF-8 encoded */
- int nByte, /* Maximum length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const char **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-int sqlite3_prepare_v2(
- sqlite3 *db, /* Database handle */
- const char *zSql, /* SQL statement, UTF-8 encoded */
- int nByte, /* Maximum length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const char **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-int sqlite3_prepare16(
- sqlite3 *db, /* Database handle */
- const void *zSql, /* SQL statement, UTF-16 encoded */
- int nByte, /* Maximum length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const void **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-int sqlite3_prepare16_v2(
- sqlite3 *db, /* Database handle */
- const void *zSql, /* SQL statement, UTF-16 encoded */
- int nByte, /* Maximum length of zSql in bytes. */
- sqlite3_stmt **ppStmt, /* OUT: Statement handle */
- const void **pzTail /* OUT: Pointer to unused portion of zSql */
-);
-
-/*
-** CAPIREF: Retrieving Statement SQL {F13100}
-**
-** This intereface can be used to retrieve a saved copy of the original
-** SQL text used to create a [prepared statement].
-**
-** INVARIANTS:
-**
-** {F13101} If the [prepared statement] passed as
-** the an argument to [sqlite3_sql()] was compiled
-** compiled using either [sqlite3_prepare_v2()] or
-** [sqlite3_prepare16_v2()],
-** then [sqlite3_sql()] function returns a pointer to a
-** zero-terminated string containing a UTF-8 rendering
-** of the original SQL statement.
-**
-** {F13102} If the [prepared statement] passed as
-** the an argument to [sqlite3_sql()] was compiled
-** compiled using either [sqlite3_prepare()] or
-** [sqlite3_prepare16()],
-** then [sqlite3_sql()] function returns a NULL pointer.
-**
-** {F13103} The string returned by [sqlite3_sql(S)] is valid until the
-** [prepared statement] S is deleted using [sqlite3_finalize(S)].
-*/
-const char *sqlite3_sql(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Dynamically Typed Value Object {F15000}
-**
-** SQLite uses the sqlite3_value object to represent all values
-** that are or can be stored in a database table.
-** SQLite uses dynamic typing for the values it stores.
-** Values stored in sqlite3_value objects can be
-** be integers, floating point values, strings, BLOBs, or NULL.
-*/
-typedef struct Mem sqlite3_value;
-
-/*
-** CAPI3REF: SQL Function Context Object {F16001}
-**
-** The context in which an SQL function executes is stored in an
-** sqlite3_context object. A pointer to an sqlite3_context
-** object is always first parameter to application-defined SQL functions.
-*/
-typedef struct sqlite3_context sqlite3_context;
-
-/*
-** CAPI3REF: Binding Values To Prepared Statements {F13500}
-**
-** In the SQL strings input to [sqlite3_prepare_v2()] and its
-** variants, literals may be replace by a parameter in one
-** of these forms:
-**
-** <ul>
-** <li> ?
-** <li> ?NNN
-** <li> :VVV
-** <li> @VVV
-** <li> $VVV
-** </ul>
-**
-** In the parameter forms shown above NNN is an integer literal,
-** VVV alpha-numeric parameter name.
-** The values of these parameters (also called "host parameter names"
-** or "SQL parameters")
-** can be set using the sqlite3_bind_*() routines defined here.
-**
-** The first argument to the sqlite3_bind_*() routines always
-** is a pointer to the [sqlite3_stmt] object returned from
-** [sqlite3_prepare_v2()] or its variants. The second
-** argument is the index of the parameter to be set. The
-** first parameter has an index of 1. When the same named
-** parameter is used more than once, second and subsequent
-** occurrences have the same index as the first occurrence.
-** The index for named parameters can be looked up using the
-** [sqlite3_bind_parameter_name()] API if desired. The index
-** for "?NNN" parameters is the value of NNN.
-** The NNN value must be between 1 and the compile-time
-** parameter SQLITE_MAX_VARIABLE_NUMBER (default value: 999).
-**
-** The third argument is the value to bind to the parameter.
-**
-** In those
-** routines that have a fourth argument, its value is the number of bytes
-** in the parameter. To be clear: the value is the number of <u>bytes</u>
-** in the value, not the number of characters. The number
-** of bytes does not include the zero-terminator at the end of strings.
-** If the fourth parameter is negative, the length of the string is
-** number of bytes up to the first zero terminator.
-**
-** The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and
-** sqlite3_bind_text16() is a destructor used to dispose of the BLOB or
-** string after SQLite has finished with it. If the fifth argument is
-** the special value [SQLITE_STATIC], then SQLite assumes that the
-** information is in static, unmanaged space and does not need to be freed.
-** If the fifth argument has the value [SQLITE_TRANSIENT], then
-** SQLite makes its own private copy of the data immediately, before
-** the sqlite3_bind_*() routine returns.
-**
-** The sqlite3_bind_zeroblob() routine binds a BLOB of length N that
-** is filled with zeros. A zeroblob uses a fixed amount of memory
-** (just an integer to hold it size) while it is being processed.
-** Zeroblobs are intended to serve as place-holders for BLOBs whose
-** content is later written using
-** [sqlite3_blob_open | increment BLOB I/O] routines. A negative
-** value for the zeroblob results in a zero-length BLOB.
-**
-** The sqlite3_bind_*() routines must be called after
-** [sqlite3_prepare_v2()] (and its variants) or [sqlite3_reset()] and
-** before [sqlite3_step()].
-** Bindings are not cleared by the [sqlite3_reset()] routine.
-** Unbound parameters are interpreted as NULL.
-**
-** These routines return [SQLITE_OK] on success or an error code if
-** anything goes wrong. [SQLITE_RANGE] is returned if the parameter
-** index is out of range. [SQLITE_NOMEM] is returned if malloc fails.
-** [SQLITE_MISUSE] might be returned if these routines are called on a
-** virtual machine that is the wrong state or which has already been finalized.
-** Detection of misuse is unreliable. Applications should not depend
-** on SQLITE_MISUSE returns. SQLITE_MISUSE is intended to indicate a
-** a logic error in the application. Future versions of SQLite might
-** panic rather than return SQLITE_MISUSE.
-**
-** See also: [sqlite3_bind_parameter_count()],
-** [sqlite3_bind_parameter_name()], and
-** [sqlite3_bind_parameter_index()].
-**
-** INVARIANTS:
-**
-** {F13506} The [sqlite3_prepare | SQL statement compiler] recognizes
-** tokens of the forms "?", "?NNN", "$VVV", ":VVV", and "@VVV"
-** as SQL parameters, where NNN is any sequence of one or more
-** digits and where VVV is any sequence of one or more
-** alphanumeric characters or "::" optionally followed by
-** a string containing no spaces and contained within parentheses.
-**
-** {F13509} The initial value of an SQL parameter is NULL.
-**
-** {F13512} The index of an "?" SQL parameter is one larger than the
-** largest index of SQL parameter to the left, or 1 if
-** the "?" is the leftmost SQL parameter.
-**
-** {F13515} The index of an "?NNN" SQL parameter is the integer NNN.
-**
-** {F13518} The index of an ":VVV", "$VVV", or "@VVV" SQL parameter is
-** the same as the index of leftmost occurances of the same
-** parameter, or one more than the largest index over all
-** parameters to the left if this is the first occurrance
-** of this parameter, or 1 if this is the leftmost parameter.
-**
-** {F13521} The [sqlite3_prepare | SQL statement compiler] fail with
-** an [SQLITE_RANGE] error if the index of an SQL parameter
-** is less than 1 or greater than SQLITE_MAX_VARIABLE_NUMBER.
-**
-** {F13524} Calls to [sqlite3_bind_text | sqlite3_bind(S,N,V,...)]
-** associate the value V with all SQL parameters having an
-** index of N in the [prepared statement] S.
-**
-** {F13527} Calls to [sqlite3_bind_text | sqlite3_bind(S,N,...)]
-** override prior calls with the same values of S and N.
-**
-** {F13530} Bindings established by [sqlite3_bind_text | sqlite3_bind(S,...)]
-** persist across calls to [sqlite3_reset(S)].
-**
-** {F13533} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
-** [sqlite3_bind_text(S,N,V,L,D)], or
-** [sqlite3_bind_text16(S,N,V,L,D)] SQLite binds the first L
-** bytes of the blob or string pointed to by V, when L
-** is non-negative.
-**
-** {F13536} In calls to [sqlite3_bind_text(S,N,V,L,D)] or
-** [sqlite3_bind_text16(S,N,V,L,D)] SQLite binds characters
-** from V through the first zero character when L is negative.
-**
-** {F13539} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
-** [sqlite3_bind_text(S,N,V,L,D)], or
-** [sqlite3_bind_text16(S,N,V,L,D)] when D is the special
-** constant [SQLITE_STATIC], SQLite assumes that the value V
-** is held in static unmanaged space that will not change
-** during the lifetime of the binding.
-**
-** {F13542} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
-** [sqlite3_bind_text(S,N,V,L,D)], or
-** [sqlite3_bind_text16(S,N,V,L,D)] when D is the special
-** constant [SQLITE_TRANSIENT], the routine makes a
-** private copy of V value before it returns.
-**
-** {F13545} In calls to [sqlite3_bind_blob(S,N,V,L,D)],
-** [sqlite3_bind_text(S,N,V,L,D)], or
-** [sqlite3_bind_text16(S,N,V,L,D)] when D is a pointer to
-** a function, SQLite invokes that function to destroy the
-** V value after it has finished using the V value.
-**
-** {F13548} In calls to [sqlite3_bind_zeroblob(S,N,V,L)] the value bound
-** is a blob of L bytes, or a zero-length blob if L is negative.
-*/
-int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));
-int sqlite3_bind_double(sqlite3_stmt*, int, double);
-int sqlite3_bind_int(sqlite3_stmt*, int, int);
-int sqlite3_bind_int64(sqlite3_stmt*, int, sqlite3_int64);
-int sqlite3_bind_null(sqlite3_stmt*, int);
-int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
-int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int, void(*)(void*));
-int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
-int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
-
-/*
-** CAPI3REF: Number Of SQL Parameters {F13600}
-**
-** This routine can be used to find the number of SQL parameters
-** in a prepared statement. SQL parameters are tokens of the
-** form "?", "?NNN", ":AAA", "$AAA", or "@AAA" that serve as
-** place-holders for values that are [sqlite3_bind_blob | bound]
-** to the parameters at a later time.
-**
-** This routine actually returns the index of the largest parameter.
-** For all forms except ?NNN, this will correspond to the number of
-** unique parameters. If parameters of the ?NNN are used, there may
-** be gaps in the list.
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_name()], and
-** [sqlite3_bind_parameter_index()].
-**
-** INVARIANTS:
-**
-** {F13601} The [sqlite3_bind_parameter_count(S)] interface returns
-** the largest index of all SQL parameters in the
-** [prepared statement] S, or 0 if S
-** contains no SQL parameters.
-*/
-int sqlite3_bind_parameter_count(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Name Of A Host Parameter {F13620}
-**
-** This routine returns a pointer to the name of the n-th
-** SQL parameter in a [prepared statement].
-** SQL parameters of the form ":AAA" or "@AAA" or "$AAA" have a name
-** which is the string ":AAA" or "@AAA" or "$VVV".
-** In other words, the initial ":" or "$" or "@"
-** is included as part of the name.
-** Parameters of the form "?" or "?NNN" have no name.
-**
-** The first host parameter has an index of 1, not 0.
-**
-** If the value n is out of range or if the n-th parameter is
-** nameless, then NULL is returned. The returned string is
-** always in the UTF-8 encoding even if the named parameter was
-** originally specified as UTF-16 in [sqlite3_prepare16()] or
-** [sqlite3_prepare16_v2()].
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_index()].
-**
-** INVARIANTS:
-**
-** {F13621} The [sqlite3_bind_parameter_name(S,N)] interface returns
-** a UTF-8 rendering of the name of the SQL parameter in
-** [prepared statement] S having index N, or
-** NULL if there is no SQL parameter with index N or if the
-** parameter with index N is an anonymous parameter "?" or
-** a numbered parameter "?NNN".
-*/
-const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
-
-/*
-** CAPI3REF: Index Of A Parameter With A Given Name {F13640}
-**
-** Return the index of an SQL parameter given its name. The
-** index value returned is suitable for use as the second
-** parameter to [sqlite3_bind_blob|sqlite3_bind()]. A zero
-** is returned if no matching parameter is found. The parameter
-** name must be given in UTF-8 even if the original statement
-** was prepared from UTF-16 text using [sqlite3_prepare16_v2()].
-**
-** See also: [sqlite3_bind_blob|sqlite3_bind()],
-** [sqlite3_bind_parameter_count()], and
-** [sqlite3_bind_parameter_index()].
-**
-** INVARIANTS:
-**
-** {F13641} The [sqlite3_bind_parameter_index(S,N)] interface returns
-** the index of SQL parameter in [prepared statement]
-** S whose name matches the UTF-8 string N, or 0 if there is
-** no match.
-*/
-int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
-
-/*
-** CAPI3REF: Reset All Bindings On A Prepared Statement {F13660}
-**
-** Contrary to the intuition of many, [sqlite3_reset()] does not
-** reset the [sqlite3_bind_blob | bindings] on a
-** [prepared statement]. Use this routine to
-** reset all host parameters to NULL.
-**
-** INVARIANTS:
-**
-** {F13661} The [sqlite3_clear_bindings(S)] interface resets all
-** SQL parameter bindings in [prepared statement] S
-** back to NULL.
-*/
-int sqlite3_clear_bindings(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Number Of Columns In A Result Set {F13710}
-**
-** Return the number of columns in the result set returned by the
-** [prepared statement]. This routine returns 0
-** if pStmt is an SQL statement that does not return data (for
-** example an UPDATE).
-**
-** INVARIANTS:
-**
-** {F13711} The [sqlite3_column_count(S)] interface returns the number of
-** columns in the result set generated by the
-** [prepared statement] S, or 0 if S does not generate
-** a result set.
-*/
-int sqlite3_column_count(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Column Names In A Result Set {F13720}
-**
-** These routines return the name assigned to a particular column
-** in the result set of a SELECT statement. The sqlite3_column_name()
-** interface returns a pointer to a zero-terminated UTF8 string
-** and sqlite3_column_name16() returns a pointer to a zero-terminated
-** UTF16 string. The first parameter is the
-** [prepared statement] that implements the SELECT statement.
-** The second parameter is the column number. The left-most column is
-** number 0.
-**
-** The returned string pointer is valid until either the
-** [prepared statement] is destroyed by [sqlite3_finalize()]
-** or until the next call sqlite3_column_name() or sqlite3_column_name16()
-** on the same column.
-**
-** If sqlite3_malloc() fails during the processing of either routine
-** (for example during a conversion from UTF-8 to UTF-16) then a
-** NULL pointer is returned.
-**
-** The name of a result column is the value of the "AS" clause for
-** that column, if there is an AS clause. If there is no AS clause
-** then the name of the column is unspecified and may change from
-** one release of SQLite to the next.
-**
-** INVARIANTS:
-**
-** {F13721} A successful invocation of the [sqlite3_column_name(S,N)]
-** interface returns the name
-** of the Nth column (where 0 is the left-most column) for the
-** result set of [prepared statement] S as a
-** zero-terminated UTF-8 string.
-**
-** {F13723} A successful invocation of the [sqlite3_column_name16(S,N)]
-** interface returns the name
-** of the Nth column (where 0 is the left-most column) for the
-** result set of [prepared statement] S as a
-** zero-terminated UTF-16 string in the native byte order.
-**
-** {F13724} The [sqlite3_column_name()] and [sqlite3_column_name16()]
-** interfaces return a NULL pointer if they are unable to
-** allocate memory memory to hold there normal return strings.
-**
-** {F13725} If the N parameter to [sqlite3_column_name(S,N)] or
-** [sqlite3_column_name16(S,N)] is out of range, then the
-** interfaces returns a NULL pointer.
-**
-** {F13726} The strings returned by [sqlite3_column_name(S,N)] and
-** [sqlite3_column_name16(S,N)] are valid until the next
-** call to either routine with the same S and N parameters
-** or until [sqlite3_finalize(S)] is called.
-**
-** {F13727} When a result column of a [SELECT] statement contains
-** an AS clause, the name of that column is the indentifier
-** to the right of the AS keyword.
-*/
-const char *sqlite3_column_name(sqlite3_stmt*, int N);
-const void *sqlite3_column_name16(sqlite3_stmt*, int N);
-
-/*
-** CAPI3REF: Source Of Data In A Query Result {F13740}
-**
-** These routines provide a means to determine what column of what
-** table in which database a result of a SELECT statement comes from.
-** The name of the database or table or column can be returned as
-** either a UTF8 or UTF16 string. The _database_ routines return
-** the database name, the _table_ routines return the table name, and
-** the origin_ routines return the column name.
-** The returned string is valid until
-** the [prepared statement] is destroyed using
-** [sqlite3_finalize()] or until the same information is requested
-** again in a different encoding.
-**
-** The names returned are the original un-aliased names of the
-** database, table, and column.
-**
-** The first argument to the following calls is a [prepared statement].
-** These functions return information about the Nth column returned by
-** the statement, where N is the second function argument.
-**
-** If the Nth column returned by the statement is an expression
-** or subquery and is not a column value, then all of these functions
-** return NULL. These routine might also return NULL if a memory
-** allocation error occurs. Otherwise, they return the
-** name of the attached database, table and column that query result
-** column was extracted from.
-**
-** As with all other SQLite APIs, those postfixed with "16" return
-** UTF-16 encoded strings, the other functions return UTF-8. {END}
-**
-** These APIs are only available if the library was compiled with the
-** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
-**
-** {U13751}
-** If two or more threads call one or more of these routines against the same
-** prepared statement and column at the same time then the results are
-** undefined.
-**
-** INVARIANTS:
-**
-** {F13741} The [sqlite3_column_database_name(S,N)] interface returns either
-** the UTF-8 zero-terminated name of the database from which the
-** Nth result column of [prepared statement] S
-** is extracted, or NULL if the the Nth column of S is a
-** general expression or if unable to allocate memory
-** to store the name.
-**
-** {F13742} The [sqlite3_column_database_name16(S,N)] interface returns either
-** the UTF-16 native byte order
-** zero-terminated name of the database from which the
-** Nth result column of [prepared statement] S
-** is extracted, or NULL if the the Nth column of S is a
-** general expression or if unable to allocate memory
-** to store the name.
-**
-** {F13743} The [sqlite3_column_table_name(S,N)] interface returns either
-** the UTF-8 zero-terminated name of the table from which the
-** Nth result column of [prepared statement] S
-** is extracted, or NULL if the the Nth column of S is a
-** general expression or if unable to allocate memory
-** to store the name.
-**
-** {F13744} The [sqlite3_column_table_name16(S,N)] interface returns either
-** the UTF-16 native byte order
-** zero-terminated name of the table from which the
-** Nth result column of [prepared statement] S
-** is extracted, or NULL if the the Nth column of S is a
-** general expression or if unable to allocate memory
-** to store the name.
-**
-** {F13745} The [sqlite3_column_origin_name(S,N)] interface returns either
-** the UTF-8 zero-terminated name of the table column from which the
-** Nth result column of [prepared statement] S
-** is extracted, or NULL if the the Nth column of S is a
-** general expression or if unable to allocate memory
-** to store the name.
-**
-** {F13746} The [sqlite3_column_origin_name16(S,N)] interface returns either
-** the UTF-16 native byte order
-** zero-terminated name of the table column from which the
-** Nth result column of [prepared statement] S
-** is extracted, or NULL if the the Nth column of S is a
-** general expression or if unable to allocate memory
-** to store the name.
-**
-** {F13748} The return values from
-** [sqlite3_column_database_name|column metadata interfaces]
-** are valid
-** for the lifetime of the [prepared statement]
-** or until the encoding is changed by another metadata
-** interface call for the same prepared statement and column.
-**
-** LIMITATIONS:
-**
-** {U13751} If two or more threads call one or more
-** [sqlite3_column_database_name|column metadata interfaces]
-** the same [prepared statement] and result column
-** at the same time then the results are undefined.
-*/
-const char *sqlite3_column_database_name(sqlite3_stmt*,int);
-const void *sqlite3_column_database_name16(sqlite3_stmt*,int);
-const char *sqlite3_column_table_name(sqlite3_stmt*,int);
-const void *sqlite3_column_table_name16(sqlite3_stmt*,int);
-const char *sqlite3_column_origin_name(sqlite3_stmt*,int);
-const void *sqlite3_column_origin_name16(sqlite3_stmt*,int);
-
-/*
-** CAPI3REF: Declared Datatype Of A Query Result {F13760}
-**
-** The first parameter is a [prepared statement].
-** If this statement is a SELECT statement and the Nth column of the
-** returned result set of that SELECT is a table column (not an
-** expression or subquery) then the declared type of the table
-** column is returned. If the Nth column of the result set is an
-** expression or subquery, then a NULL pointer is returned.
-** The returned string is always UTF-8 encoded. {END}
-** For example, in the database schema:
-**
-** CREATE TABLE t1(c1 VARIANT);
-**
-** And the following statement compiled:
-**
-** SELECT c1 + 1, c1 FROM t1;
-**
-** Then this routine would return the string "VARIANT" for the second
-** result column (i==1), and a NULL pointer for the first result column
-** (i==0).
-**
-** SQLite uses dynamic run-time typing. So just because a column
-** is declared to contain a particular type does not mean that the
-** data stored in that column is of the declared type. SQLite is
-** strongly typed, but the typing is dynamic not static. Type
-** is associated with individual values, not with the containers
-** used to hold those values.
-**
-** INVARIANTS:
-**
-** {F13761} A successful call to [sqlite3_column_decltype(S,N)]
-** returns a zero-terminated UTF-8 string containing the
-** the declared datatype of the table column that appears
-** as the Nth column (numbered from 0) of the result set to the
-** [prepared statement] S.
-**
-** {F13762} A successful call to [sqlite3_column_decltype16(S,N)]
-** returns a zero-terminated UTF-16 native byte order string
-** containing the declared datatype of the table column that appears
-** as the Nth column (numbered from 0) of the result set to the
-** [prepared statement] S.
-**
-** {F13763} If N is less than 0 or N is greater than or equal to
-** the number of columns in [prepared statement] S
-** or if the Nth column of S is an expression or subquery rather
-** than a table column or if a memory allocation failure
-** occurs during encoding conversions, then
-** calls to [sqlite3_column_decltype(S,N)] or
-** [sqlite3_column_decltype16(S,N)] return NULL.
-*/
-const char *sqlite3_column_decltype(sqlite3_stmt*,int);
-const void *sqlite3_column_decltype16(sqlite3_stmt*,int);
-
-/*
-** CAPI3REF: Evaluate An SQL Statement {F13200}
-**
-** After an [prepared statement] has been prepared with a call
-** to either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] or to one of
-** the legacy interfaces [sqlite3_prepare()] or [sqlite3_prepare16()],
-** then this function must be called one or more times to evaluate the
-** statement.
-**
-** The details of the behavior of this sqlite3_step() interface depend
-** on whether the statement was prepared using the newer "v2" interface
-** [sqlite3_prepare_v2()] and [sqlite3_prepare16_v2()] or the older legacy
-** interface [sqlite3_prepare()] and [sqlite3_prepare16()]. The use of the
-** new "v2" interface is recommended for new applications but the legacy
-** interface will continue to be supported.
-**
-** In the lagacy interface, the return value will be either [SQLITE_BUSY],
-** [SQLITE_DONE], [SQLITE_ROW], [SQLITE_ERROR], or [SQLITE_MISUSE].
-** With the "v2" interface, any of the other [SQLITE_OK | result code]
-** or [SQLITE_IOERR_READ | extended result code] might be returned as
-** well.
-**
-** [SQLITE_BUSY] means that the database engine was unable to acquire the
-** database locks it needs to do its job. If the statement is a COMMIT
-** or occurs outside of an explicit transaction, then you can retry the
-** statement. If the statement is not a COMMIT and occurs within a
-** explicit transaction then you should rollback the transaction before
-** continuing.
-**
-** [SQLITE_DONE] means that the statement has finished executing
-** successfully. sqlite3_step() should not be called again on this virtual
-** machine without first calling [sqlite3_reset()] to reset the virtual
-** machine back to its initial state.
-**
-** If the SQL statement being executed returns any data, then
-** [SQLITE_ROW] is returned each time a new row of data is ready
-** for processing by the caller. The values may be accessed using
-** the [sqlite3_column_int | column access functions].
-** sqlite3_step() is called again to retrieve the next row of data.
-**
-** [SQLITE_ERROR] means that a run-time error (such as a constraint
-** violation) has occurred. sqlite3_step() should not be called again on
-** the VM. More information may be found by calling [sqlite3_errmsg()].
-** With the legacy interface, a more specific error code (example:
-** [SQLITE_INTERRUPT], [SQLITE_SCHEMA], [SQLITE_CORRUPT], and so forth)
-** can be obtained by calling [sqlite3_reset()] on the
-** [prepared statement]. In the "v2" interface,
-** the more specific error code is returned directly by sqlite3_step().
-**
-** [SQLITE_MISUSE] means that the this routine was called inappropriately.
-** Perhaps it was called on a [prepared statement] that has
-** already been [sqlite3_finalize | finalized] or on one that had
-** previously returned [SQLITE_ERROR] or [SQLITE_DONE]. Or it could
-** be the case that the same database connection is being used by two or
-** more threads at the same moment in time.
-**
-** <b>Goofy Interface Alert:</b>
-** In the legacy interface,
-** the sqlite3_step() API always returns a generic error code,
-** [SQLITE_ERROR], following any error other than [SQLITE_BUSY]
-** and [SQLITE_MISUSE]. You must call [sqlite3_reset()] or
-** [sqlite3_finalize()] in order to find one of the specific
-** [error codes] that better describes the error.
-** We admit that this is a goofy design. The problem has been fixed
-** with the "v2" interface. If you prepare all of your SQL statements
-** using either [sqlite3_prepare_v2()] or [sqlite3_prepare16_v2()] instead
-** of the legacy [sqlite3_prepare()] and [sqlite3_prepare16()], then the
-** more specific [error codes] are returned directly
-** by sqlite3_step(). The use of the "v2" interface is recommended.
-**
-** INVARIANTS:
-**
-** {F13202} If [prepared statement] S is ready to be
-** run, then [sqlite3_step(S)] advances that prepared statement
-** until to completion or until it is ready to return another
-** row of the result set or an interrupt or run-time error occurs.
-**
-** {F15304} When a call to [sqlite3_step(S)] causes the
-** [prepared statement] S to run to completion,
-** the function returns [SQLITE_DONE].
-**
-** {F15306} When a call to [sqlite3_step(S)] stops because it is ready
-** to return another row of the result set, it returns
-** [SQLITE_ROW].
-**
-** {F15308} If a call to [sqlite3_step(S)] encounters an
-** [sqlite3_interrupt|interrupt] or a run-time error,
-** it returns an appropraite error code that is not one of
-** [SQLITE_OK], [SQLITE_ROW], or [SQLITE_DONE].
-**
-** {F15310} If an [sqlite3_interrupt|interrupt] or run-time error
-** occurs during a call to [sqlite3_step(S)]
-** for a [prepared statement] S created using
-** legacy interfaces [sqlite3_prepare()] or
-** [sqlite3_prepare16()] then the function returns either
-** [SQLITE_ERROR], [SQLITE_BUSY], or [SQLITE_MISUSE].
-*/
-int sqlite3_step(sqlite3_stmt*);
-
-/*
-** CAPI3REF: Number of columns in a result set {F13770}
-**
-** Return the number of values in the current row of the result set.
-**
-** INVARIANTS:
-**
-** {F13771} After a call to [sqlite3_step(S)] that returns
-** [SQLITE_ROW], the [sqlite3_data_count(S)] routine
-** will return the same value as the
-** [sqlite3_column_count(S)] function.
-**
-** {F13772} After [sqlite3_step(S)] has returned any value other than
-** [SQLITE_ROW] or before [sqlite3_step(S)] has been
-** called on the [prepared statement] for
-** the first time since it was [sqlite3_prepare|prepared]
-** or [sqlite3_reset|reset], the [sqlite3_data_count(S)]
-** routine returns zero.
-*/
-int sqlite3_data_count(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Fundamental Datatypes {F10265}
-** KEYWORDS: SQLITE_TEXT
-**
-** {F10266}Every value in SQLite has one of five fundamental datatypes:
-**
-** <ul>
-** <li> 64-bit signed integer
-** <li> 64-bit IEEE floating point number
-** <li> string
-** <li> BLOB
-** <li> NULL
-** </ul> {END}
-**
-** These constants are codes for each of those types.
-**
-** Note that the SQLITE_TEXT constant was also used in SQLite version 2
-** for a completely different meaning. Software that links against both
-** SQLite version 2 and SQLite version 3 should use SQLITE3_TEXT not
-** SQLITE_TEXT.
-*/
-#define SQLITE_INTEGER 1
-#define SQLITE_FLOAT 2
-#define SQLITE_BLOB 4
-#define SQLITE_NULL 5
-#ifdef SQLITE_TEXT
-# undef SQLITE_TEXT
-#else
-# define SQLITE_TEXT 3
-#endif
-#define SQLITE3_TEXT 3
-
-/*
-** CAPI3REF: Results Values From A Query {F13800}
-**
-** These routines form the "result set query" interface.
-**
-** These routines return information about
-** a single column of the current result row of a query. In every
-** case the first argument is a pointer to the
-** [prepared statement] that is being
-** evaluated (the [sqlite3_stmt*] that was returned from
-** [sqlite3_prepare_v2()] or one of its variants) and
-** the second argument is the index of the column for which information
-** should be returned. The left-most column of the result set
-** has an index of 0.
-**
-** If the SQL statement is not currently point to a valid row, or if the
-** the column index is out of range, the result is undefined.
-** These routines may only be called when the most recent call to
-** [sqlite3_step()] has returned [SQLITE_ROW] and neither
-** [sqlite3_reset()] nor [sqlite3_finalize()] has been call subsequently.
-** If any of these routines are called after [sqlite3_reset()] or
-** [sqlite3_finalize()] or after [sqlite3_step()] has returned
-** something other than [SQLITE_ROW], the results are undefined.
-** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()]
-** are called from a different thread while any of these routines
-** are pending, then the results are undefined.
-**
-** The sqlite3_column_type() routine returns
-** [SQLITE_INTEGER | datatype code] for the initial data type
-** of the result column. The returned value is one of [SQLITE_INTEGER],
-** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. The value
-** returned by sqlite3_column_type() is only meaningful if no type
-** conversions have occurred as described below. After a type conversion,
-** the value returned by sqlite3_column_type() is undefined. Future
-** versions of SQLite may change the behavior of sqlite3_column_type()
-** following a type conversion.
-**
-** If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
-** routine returns the number of bytes in that BLOB or string.
-** If the result is a UTF-16 string, then sqlite3_column_bytes() converts
-** the string to UTF-8 and then returns the number of bytes.
-** If the result is a numeric value then sqlite3_column_bytes() uses
-** [sqlite3_snprintf()] to convert that value to a UTF-8 string and returns
-** the number of bytes in that string.
-** The value returned does not include the zero terminator at the end
-** of the string. For clarity: the value returned is the number of
-** bytes in the string, not the number of characters.
-**
-** Strings returned by sqlite3_column_text() and sqlite3_column_text16(),
-** even empty strings, are always zero terminated. The return
-** value from sqlite3_column_blob() for a zero-length blob is an arbitrary
-** pointer, possibly even a NULL pointer.
-**
-** The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes()
-** but leaves the result in UTF-16 in native byte order instead of UTF-8.
-** The zero terminator is not included in this count.
-**
-** These routines attempt to convert the value where appropriate. For
-** example, if the internal representation is FLOAT and a text result
-** is requested, [sqlite3_snprintf()] is used internally to do the conversion
-** automatically. The following table details the conversions that
-** are applied:
-**
-** <blockquote>
-** <table border="1">
-** <tr><th> Internal<br>Type <th> Requested<br>Type <th> Conversion
-**
-** <tr><td> NULL <td> INTEGER <td> Result is 0
-** <tr><td> NULL <td> FLOAT <td> Result is 0.0
-** <tr><td> NULL <td> TEXT <td> Result is NULL pointer
-** <tr><td> NULL <td> BLOB <td> Result is NULL pointer
-** <tr><td> INTEGER <td> FLOAT <td> Convert from integer to float
-** <tr><td> INTEGER <td> TEXT <td> ASCII rendering of the integer
-** <tr><td> INTEGER <td> BLOB <td> Same as for INTEGER->TEXT
-** <tr><td> FLOAT <td> INTEGER <td> Convert from float to integer
-** <tr><td> FLOAT <td> TEXT <td> ASCII rendering of the float
-** <tr><td> FLOAT <td> BLOB <td> Same as FLOAT->TEXT
-** <tr><td> TEXT <td> INTEGER <td> Use atoi()
-** <tr><td> TEXT <td> FLOAT <td> Use atof()
-** <tr><td> TEXT <td> BLOB <td> No change
-** <tr><td> BLOB <td> INTEGER <td> Convert to TEXT then use atoi()
-** <tr><td> BLOB <td> FLOAT <td> Convert to TEXT then use atof()
-** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
-** </table>
-** </blockquote>
-**
-** The table above makes reference to standard C library functions atoi()
-** and atof(). SQLite does not really use these functions. It has its
-** on equavalent internal routines. The atoi() and atof() names are
-** used in the table for brevity and because they are familiar to most
-** C programmers.
-**
-** Note that when type conversions occur, pointers returned by prior
-** calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
-** sqlite3_column_text16() may be invalidated.
-** Type conversions and pointer invalidations might occur
-** in the following cases:
-**
-** <ul>
-** <li><p> The initial content is a BLOB and sqlite3_column_text()
-** or sqlite3_column_text16() is called. A zero-terminator might
-** need to be added to the string.</p></li>
-**
-** <li><p> The initial content is UTF-8 text and sqlite3_column_bytes16() or
-** sqlite3_column_text16() is called. The content must be converted
-** to UTF-16.</p></li>
-**
-** <li><p> The initial content is UTF-16 text and sqlite3_column_bytes() or
-** sqlite3_column_text() is called. The content must be converted
-** to UTF-8.</p></li>
-** </ul>
-**
-** Conversions between UTF-16be and UTF-16le are always done in place and do
-** not invalidate a prior pointer, though of course the content of the buffer
-** that the prior pointer points to will have been modified. Other kinds
-** of conversion are done in place when it is possible, but sometime it is
-** not possible and in those cases prior pointers are invalidated.
-**
-** The safest and easiest to remember policy is to invoke these routines
-** in one of the following ways:
-**
-** <ul>
-** <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
-** <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
-** <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
-** </ul>
-**
-** In other words, you should call sqlite3_column_text(), sqlite3_column_blob(),
-** or sqlite3_column_text16() first to force the result into the desired
-** format, then invoke sqlite3_column_bytes() or sqlite3_column_bytes16() to
-** find the size of the result. Do not mix call to sqlite3_column_text() or
-** sqlite3_column_blob() with calls to sqlite3_column_bytes16(). And do not
-** mix calls to sqlite3_column_text16() with calls to sqlite3_column_bytes().
-**
-** The pointers returned are valid until a type conversion occurs as
-** described above, or until [sqlite3_step()] or [sqlite3_reset()] or
-** [sqlite3_finalize()] is called. The memory space used to hold strings
-** and blobs is freed automatically. Do <b>not</b> pass the pointers returned
-** [sqlite3_column_blob()], [sqlite3_column_text()], etc. into
-** [sqlite3_free()].
-**
-** If a memory allocation error occurs during the evaluation of any
-** of these routines, a default value is returned. The default value
-** is either the integer 0, the floating point number 0.0, or a NULL
-** pointer. Subsequent calls to [sqlite3_errcode()] will return
-** [SQLITE_NOMEM].
-**
-** INVARIANTS:
-**
-** {F13803} The [sqlite3_column_blob(S,N)] interface converts the
-** Nth column in the current row of the result set for
-** [prepared statement] S into a blob and then returns a
-** pointer to the converted value.
-**
-** {F13806} The [sqlite3_column_bytes(S,N)] interface returns the
-** number of bytes in the blob or string (exclusive of the
-** zero terminator on the string) that was returned by the
-** most recent call to [sqlite3_column_blob(S,N)] or
-** [sqlite3_column_text(S,N)].
-**
-** {F13809} The [sqlite3_column_bytes16(S,N)] interface returns the
-** number of bytes in the string (exclusive of the
-** zero terminator on the string) that was returned by the
-** most recent call to [sqlite3_column_text16(S,N)].
-**
-** {F13812} The [sqlite3_column_double(S,N)] interface converts the
-** Nth column in the current row of the result set for
-** [prepared statement] S into a floating point value and
-** returns a copy of that value.
-**
-** {F13815} The [sqlite3_column_int(S,N)] interface converts the
-** Nth column in the current row of the result set for
-** [prepared statement] S into a 32-bit signed integer and
-** returns a copy of that integer.
-**
-** {F13818} The [sqlite3_column_int64(S,N)] interface converts the
-** Nth column in the current row of the result set for
-** [prepared statement] S into a 64-bit signed integer and
-** returns a copy of that integer.
-**
-** {F13821} The [sqlite3_column_text(S,N)] interface converts the
-** Nth column in the current row of the result set for
-** [prepared statement] S into a zero-terminated UTF-8
-** string and returns a pointer to that string.
-**
-** {F13824} The [sqlite3_column_text16(S,N)] interface converts the
-** Nth column in the current row of the result set for
-** [prepared statement] S into a zero-terminated 2-byte
-** aligned UTF-16 native byte order
-** string and returns a pointer to that string.
-**
-** {F13827} The [sqlite3_column_type(S,N)] interface returns
-** one of [SQLITE_NULL], [SQLITE_INTEGER], [SQLITE_FLOAT],
-** [SQLITE_TEXT], or [SQLITE_BLOB] as appropriate for
-** the Nth column in the current row of the result set for
-** [prepared statement] S.
-**
-** {F13830} The [sqlite3_column_value(S,N)] interface returns a
-** pointer to the [sqlite3_value] object that for the
-** Nth column in the current row of the result set for
-** [prepared statement] S.
-*/
-const void *sqlite3_column_blob(sqlite3_stmt*, int iCol);
-int sqlite3_column_bytes(sqlite3_stmt*, int iCol);
-int sqlite3_column_bytes16(sqlite3_stmt*, int iCol);
-double sqlite3_column_double(sqlite3_stmt*, int iCol);
-int sqlite3_column_int(sqlite3_stmt*, int iCol);
-sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol);
-const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
-const void *sqlite3_column_text16(sqlite3_stmt*, int iCol);
-int sqlite3_column_type(sqlite3_stmt*, int iCol);
-sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol);
-
-/*
-** CAPI3REF: Destroy A Prepared Statement Object {F13300}
-**
-** The sqlite3_finalize() function is called to delete a
-** [prepared statement]. If the statement was
-** executed successfully, or not executed at all, then SQLITE_OK is returned.
-** If execution of the statement failed then an
-** [error code] or [extended error code]
-** is returned.
-**
-** This routine can be called at any point during the execution of the
-** [prepared statement]. If the virtual machine has not
-** completed execution when this routine is called, that is like
-** encountering an error or an interrupt. (See [sqlite3_interrupt()].)
-** Incomplete updates may be rolled back and transactions cancelled,
-** depending on the circumstances, and the
-** [error code] returned will be [SQLITE_ABORT].
-**
-** INVARIANTS:
-**
-** {F11302} The [sqlite3_finalize(S)] interface destroys the
-** [prepared statement] S and releases all
-** memory and file resources held by that object.
-**
-** {F11304} If the most recent call to [sqlite3_step(S)] for the
-** [prepared statement] S returned an error,
-** then [sqlite3_finalize(S)] returns that same error.
-*/
-int sqlite3_finalize(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Reset A Prepared Statement Object {F13330}
-**
-** The sqlite3_reset() function is called to reset a
-** [prepared statement] object.
-** back to its initial state, ready to be re-executed.
-** Any SQL statement variables that had values bound to them using
-** the [sqlite3_bind_blob | sqlite3_bind_*() API] retain their values.
-** Use [sqlite3_clear_bindings()] to reset the bindings.
-**
-** {F11332} The [sqlite3_reset(S)] interface resets the [prepared statement] S
-** back to the beginning of its program.
-**
-** {F11334} If the most recent call to [sqlite3_step(S)] for
-** [prepared statement] S returned [SQLITE_ROW] or [SQLITE_DONE],
-** or if [sqlite3_step(S)] has never before been called on S,
-** then [sqlite3_reset(S)] returns [SQLITE_OK].
-**
-** {F11336} If the most recent call to [sqlite3_step(S)] for
-** [prepared statement] S indicated an error, then
-** [sqlite3_reset(S)] returns an appropriate [error code].
-**
-** {F11338} The [sqlite3_reset(S)] interface does not change the values
-** of any [sqlite3_bind_blob|bindings] on [prepared statement] S.
-*/
-int sqlite3_reset(sqlite3_stmt *pStmt);
-
-/*
-** CAPI3REF: Create Or Redefine SQL Functions {F16100}
-** KEYWORDS: {function creation routines}
-**
-** These two functions (collectively known as
-** "function creation routines") are used to add SQL functions or aggregates
-** or to redefine the behavior of existing SQL functions or aggregates. The
-** difference only between the two is that the second parameter, the
-** name of the (scalar) function or aggregate, is encoded in UTF-8 for
-** sqlite3_create_function() and UTF-16 for sqlite3_create_function16().
-**
-** The first argument is the [database connection] that holds the
-** SQL function or aggregate is to be added or redefined. If a single
-** program uses more than one database handle internally, then SQL
-** functions or aggregates must be added individually to each database
-** handle with which they will be used.
-**
-** The second parameter is the name of the SQL function to be created
-** or redefined.
-** The length of the name is limited to 255 bytes, exclusive of the
-** zero-terminator. Note that the name length limit is in bytes, not
-** characters. Any attempt to create a function with a longer name
-** will result in an SQLITE_ERROR error.
-**
-** The third parameter is the number of arguments that the SQL function or
-** aggregate takes. If this parameter is negative, then the SQL function or
-** aggregate may take any number of arguments.
-**
-** The fourth parameter, eTextRep, specifies what
-** [SQLITE_UTF8 | text encoding] this SQL function prefers for
-** its parameters. Any SQL function implementation should be able to work
-** work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be
-** more efficient with one encoding than another. It is allowed to
-** invoke sqlite3_create_function() or sqlite3_create_function16() multiple
-** times with the same function but with different values of eTextRep.
-** When multiple implementations of the same function are available, SQLite
-** will pick the one that involves the least amount of data conversion.
-** If there is only a single implementation which does not care what
-** text encoding is used, then the fourth argument should be
-** [SQLITE_ANY].
-**
-** The fifth parameter is an arbitrary pointer. The implementation
-** of the function can gain access to this pointer using
-** [sqlite3_user_data()].
-**
-** The seventh, eighth and ninth parameters, xFunc, xStep and xFinal, are
-** pointers to C-language functions that implement the SQL
-** function or aggregate. A scalar SQL function requires an implementation of
-** the xFunc callback only, NULL pointers should be passed as the xStep
-** and xFinal parameters. An aggregate SQL function requires an implementation
-** of xStep and xFinal and NULL should be passed for xFunc. To delete an
-** existing SQL function or aggregate, pass NULL for all three function
-** callback.
-**
-** It is permitted to register multiple implementations of the same
-** functions with the same name but with either differing numbers of
-** arguments or differing perferred text encodings. SQLite will use
-** the implementation most closely matches the way in which the
-** SQL function is used.
-**
-** INVARIANTS:
-**
-** {F16103} The [sqlite3_create_function16()] interface behaves exactly
-** like [sqlite3_create_function()] in every way except that it
-** interprets the zFunctionName argument as
-** zero-terminated UTF-16 native byte order instead of as a
-** zero-terminated UTF-8.
-**
-** {F16106}
-*/
-int sqlite3_create_function(
- sqlite3 *db,
- const char *zFunctionName,
- int nArg,
- int eTextRep,
- void *pApp,
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
- void (*xStep)(sqlite3_context*,int,sqlite3_value**),
- void (*xFinal)(sqlite3_context*)
-);
-int sqlite3_create_function16(
- sqlite3 *db,
- const void *zFunctionName,
- int nArg,
- int eTextRep,
- void *pApp,
- void (*xFunc)(sqlite3_context*,int,sqlite3_value**),
- void (*xStep)(sqlite3_context*,int,sqlite3_value**),
- void (*xFinal)(sqlite3_context*)
-);
-
-/*
-** CAPI3REF: Text Encodings {F10267}
-**
-** These constant define integer codes that represent the various
-** text encodings supported by SQLite.
-*/
-#define SQLITE_UTF8 1
-#define SQLITE_UTF16LE 2
-#define SQLITE_UTF16BE 3
-#define SQLITE_UTF16 4 /* Use native byte order */
-#define SQLITE_ANY 5 /* sqlite3_create_function only */
-#define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */
-
-/*
-** CAPI3REF: Obsolete Functions
-**
-** These functions are all now obsolete. In order to maintain
-** backwards compatibility with older code, we continue to support
-** these functions. However, new development projects should avoid
-** the use of these functions. To help encourage people to avoid
-** using these functions, we are not going to tell you want they do.
-*/
-int sqlite3_aggregate_count(sqlite3_context*);
-int sqlite3_expired(sqlite3_stmt*);
-int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
-int sqlite3_global_recover(void);
-void sqlite3_thread_cleanup(void);
-int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64);
-
-/*
-** CAPI3REF: Obtaining SQL Function Parameter Values {F15100}
-**
-** The C-language implementation of SQL functions and aggregates uses
-** this set of interface routines to access the parameter values on
-** the function or aggregate.
-**
-** The xFunc (for scalar functions) or xStep (for aggregates) parameters
-** to [sqlite3_create_function()] and [sqlite3_create_function16()]
-** define callbacks that implement the SQL functions and aggregates.
-** The 4th parameter to these callbacks is an array of pointers to
-** [sqlite3_value] objects. There is one [sqlite3_value] object for
-** each parameter to the SQL function. These routines are used to
-** extract values from the [sqlite3_value] objects.
-**
-** These routines work just like the corresponding
-** [sqlite3_column_blob | sqlite3_column_* routines] except that
-** these routines take a single [sqlite3_value*] pointer instead
-** of an [sqlite3_stmt*] pointer and an integer column number.
-**
-** The sqlite3_value_text16() interface extracts a UTF16 string
-** in the native byte-order of the host machine. The
-** sqlite3_value_text16be() and sqlite3_value_text16le() interfaces
-** extract UTF16 strings as big-endian and little-endian respectively.
-**
-** The sqlite3_value_numeric_type() interface attempts to apply
-** numeric affinity to the value. This means that an attempt is
-** made to convert the value to an integer or floating point. If
-** such a conversion is possible without loss of information (in other
-** words if the value is a string that looks like a number)
-** then the conversion is done. Otherwise no conversion occurs. The
-** [SQLITE_INTEGER | datatype] after conversion is returned.
-**
-** Please pay particular attention to the fact that the pointer that
-** is returned from [sqlite3_value_blob()], [sqlite3_value_text()], or
-** [sqlite3_value_text16()] can be invalidated by a subsequent call to
-** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()],
-** or [sqlite3_value_text16()].
-**
-** These routines must be called from the same thread as
-** the SQL function that supplied the sqlite3_value* parameters.
-** Or, if the sqlite3_value* argument comes from the [sqlite3_column_value()]
-** interface, then these routines should be called from the same thread
-** that ran [sqlite3_column_value()].
-**
-*/
-const void *sqlite3_value_blob(sqlite3_value*);
-int sqlite3_value_bytes(sqlite3_value*);
-int sqlite3_value_bytes16(sqlite3_value*);
-double sqlite3_value_double(sqlite3_value*);
-int sqlite3_value_int(sqlite3_value*);
-sqlite3_int64 sqlite3_value_int64(sqlite3_value*);
-const unsigned char *sqlite3_value_text(sqlite3_value*);
-const void *sqlite3_value_text16(sqlite3_value*);
-const void *sqlite3_value_text16le(sqlite3_value*);
-const void *sqlite3_value_text16be(sqlite3_value*);
-int sqlite3_value_type(sqlite3_value*);
-int sqlite3_value_numeric_type(sqlite3_value*);
-
-/*
-** CAPI3REF: Obtain Aggregate Function Context {F16210}
-**
-** The implementation of aggregate SQL functions use this routine to allocate
-** a structure for storing their state.
-** {F16211} The first time the sqlite3_aggregate_context() routine is
-** is called for a particular aggregate, SQLite allocates nBytes of memory
-** zeros that memory, and returns a pointer to it.
-** {F16212} On second and subsequent calls to sqlite3_aggregate_context()
-** for the same aggregate function index, the same buffer is returned. {END}
-** The implementation
-** of the aggregate can use the returned buffer to accumulate data.
-**
-** {F16213} SQLite automatically frees the allocated buffer when the aggregate
-** query concludes. {END}
-**
-** The first parameter should be a copy of the
-** [sqlite3_context | SQL function context] that is the first
-** parameter to the callback routine that implements the aggregate
-** function.
-**
-** This routine must be called from the same thread in which
-** the aggregate SQL function is running.
-*/
-void *sqlite3_aggregate_context(sqlite3_context*, int nBytes);
-
-/*
-** CAPI3REF: User Data For Functions {F16240}
-**
-** {F16241} The sqlite3_user_data() interface returns a copy of
-** the pointer that was the pUserData parameter (the 5th parameter)
-** of the the [sqlite3_create_function()]
-** and [sqlite3_create_function16()] routines that originally
-** registered the application defined function. {END}
-**
-** {U16243} This routine must be called from the same thread in which
-** the application-defined function is running.
-*/
-void *sqlite3_user_data(sqlite3_context*);
-
-/*
-** CAPI3REF: Function Auxiliary Data {F16270}
-**
-** The following two functions may be used by scalar SQL functions to
-** associate meta-data with argument values. If the same value is passed to
-** multiple invocations of the same SQL function during query execution, under
-** some circumstances the associated meta-data may be preserved. This may
-** be used, for example, to add a regular-expression matching scalar
-** function. The compiled version of the regular expression is stored as
-** meta-data associated with the SQL value passed as the regular expression
-** pattern. The compiled regular expression can be reused on multiple
-** invocations of the same function so that the original pattern string
-** does not need to be recompiled on each invocation.
-**
-** {F16271}
-** The sqlite3_get_auxdata() interface returns a pointer to the meta-data
-** associated by the sqlite3_set_auxdata() function with the Nth argument
-** value to the application-defined function.
-** {F16272} If no meta-data has been ever been set for the Nth
-** argument of the function, or if the cooresponding function parameter
-** has changed since the meta-data was set, then sqlite3_get_auxdata()
-** returns a NULL pointer.
-**
-** {F16275} The sqlite3_set_auxdata() interface saves the meta-data
-** pointed to by its 3rd parameter as the meta-data for the N-th
-** argument of the application-defined function. {END} Subsequent
-** calls to sqlite3_get_auxdata() might return this data, if it has
-** not been destroyed.
-** {F16277} If it is not NULL, SQLite will invoke the destructor
-** function given by the 4th parameter to sqlite3_set_auxdata() on
-** the meta-data when the corresponding function parameter changes
-** or when the SQL statement completes, whichever comes first. {END}
-**
-** In practice, meta-data is preserved between function calls for
-** expressions that are constant at compile time. This includes literal
-** values and SQL variables.
-**
-** These routines must be called from the same thread in which
-** the SQL function is running.
-*/
-void *sqlite3_get_auxdata(sqlite3_context*, int N);
-void sqlite3_set_auxdata(sqlite3_context*, int N, void*, void (*)(void*));
-
-
-/*
-** CAPI3REF: Constants Defining Special Destructor Behavior {F10280}
-**
-** These are special value for the destructor that is passed in as the
-** final argument to routines like [sqlite3_result_blob()]. If the destructor
-** argument is SQLITE_STATIC, it means that the content pointer is constant
-** and will never change. It does not need to be destroyed. The
-** SQLITE_TRANSIENT value means that the content will likely change in
-** the near future and that SQLite should make its own private copy of
-** the content before returning.
-**
-** The typedef is necessary to work around problems in certain
-** C++ compilers. See ticket #2191.
-*/
-typedef void (*sqlite3_destructor_type)(void*);
-#define SQLITE_STATIC ((sqlite3_destructor_type)0)
-#define SQLITE_TRANSIENT ((sqlite3_destructor_type)-1)
-
-/*
-** CAPI3REF: Setting The Result Of An SQL Function {F16400}
-**
-** These routines are used by the xFunc or xFinal callbacks that
-** implement SQL functions and aggregates. See
-** [sqlite3_create_function()] and [sqlite3_create_function16()]
-** for additional information.
-**
-** These functions work very much like the
-** [sqlite3_bind_blob | sqlite3_bind_*] family of functions used
-** to bind values to host parameters in prepared statements.
-** Refer to the
-** [sqlite3_bind_blob | sqlite3_bind_* documentation] for
-** additional information.
-**
-** {F16402} The sqlite3_result_blob() interface sets the result from
-** an application defined function to be the BLOB whose content is pointed
-** to by the second parameter and which is N bytes long where N is the
-** third parameter.
-** {F16403} The sqlite3_result_zeroblob() inerfaces set the result of
-** the application defined function to be a BLOB containing all zero
-** bytes and N bytes in size, where N is the value of the 2nd parameter.
-**
-** {F16407} The sqlite3_result_double() interface sets the result from
-** an application defined function to be a floating point value specified
-** by its 2nd argument.
-**
-** {F16409} The sqlite3_result_error() and sqlite3_result_error16() functions
-** cause the implemented SQL function to throw an exception.
-** {F16411} SQLite uses the string pointed to by the
-** 2nd parameter of sqlite3_result_error() or sqlite3_result_error16()
-** as the text of an error message. {F16412} SQLite interprets the error
-** message string from sqlite3_result_error() as UTF8. {F16413} SQLite
-** interprets the string from sqlite3_result_error16() as UTF16 in native
-** byte order. {F16414} If the third parameter to sqlite3_result_error()
-** or sqlite3_result_error16() is negative then SQLite takes as the error
-** message all text up through the first zero character.
-** {F16415} If the third parameter to sqlite3_result_error() or
-** sqlite3_result_error16() is non-negative then SQLite takes that many
-** bytes (not characters) from the 2nd parameter as the error message.
-** {F16417} The sqlite3_result_error() and sqlite3_result_error16()
-** routines make a copy private copy of the error message text before
-** they return. {END} Hence, the calling function can deallocate or
-** modify the text after they return without harm.
-** The sqlite3_result_error_code() function changes the error code
-** returned by SQLite as a result of an error in a function. By default,
-** the error code is SQLITE_ERROR.
-**
-** {F16421} The sqlite3_result_toobig() interface causes SQLite
-** to throw an error indicating that a string or BLOB is to long
-** to represent. {F16422} The sqlite3_result_nomem() interface
-** causes SQLite to throw an exception indicating that the a
-** memory allocation failed.
-**
-** {F16431} The sqlite3_result_int() interface sets the return value
-** of the application-defined function to be the 32-bit signed integer
-** value given in the 2nd argument.
-** {F16432} The sqlite3_result_int64() interface sets the return value
-** of the application-defined function to be the 64-bit signed integer
-** value given in the 2nd argument.
-**
-** {F16437} The sqlite3_result_null() interface sets the return value
-** of the application-defined function to be NULL.
-**
-** {F16441} The sqlite3_result_text(), sqlite3_result_text16(),
-** sqlite3_result_text16le(), and sqlite3_result_text16be() interfaces
-** set the return value of the application-defined function to be
-** a text string which is represented as UTF-8, UTF-16 native byte order,
-** UTF-16 little endian, or UTF-16 big endian, respectively.
-** {F16442} SQLite takes the text result from the application from
-** the 2nd parameter of the sqlite3_result_text* interfaces.
-** {F16444} If the 3rd parameter to the sqlite3_result_text* interfaces
-** is negative, then SQLite takes result text from the 2nd parameter
-** through the first zero character.
-** {F16447} If the 3rd parameter to the sqlite3_result_text* interfaces
-** is non-negative, then as many bytes (not characters) of the text
-** pointed to by the 2nd parameter are taken as the application-defined
-** function result.
-** {F16451} If the 4th parameter to the sqlite3_result_text* interfaces
-** or sqlite3_result_blob is a non-NULL pointer, then SQLite calls that
-** function as the destructor on the text or blob result when it has
-** finished using that result.
-** {F16453} If the 4th parameter to the sqlite3_result_text* interfaces
-** or sqlite3_result_blob is the special constant SQLITE_STATIC, then
-** SQLite assumes that the text or blob result is constant space and
-** does not copy the space or call a destructor when it has
-** finished using that result.
-** {F16454} If the 4th parameter to the sqlite3_result_text* interfaces
-** or sqlite3_result_blob is the special constant SQLITE_TRANSIENT
-** then SQLite makes a copy of the result into space obtained from
-** from [sqlite3_malloc()] before it returns.
-**
-** {F16461} The sqlite3_result_value() interface sets the result of
-** the application-defined function to be a copy the [sqlite3_value]
-** object specified by the 2nd parameter. {F16463} The
-** sqlite3_result_value() interface makes a copy of the [sqlite3_value]
-** so that [sqlite3_value] specified in the parameter may change or
-** be deallocated after sqlite3_result_value() returns without harm.
-**
-** {U16491} These routines are called from within the different thread
-** than the one containing the application-defined function that recieved
-** the [sqlite3_context] pointer, the results are undefined.
-*/
-void sqlite3_result_blob(sqlite3_context*, const void*, int, void(*)(void*));
-void sqlite3_result_double(sqlite3_context*, double);
-void sqlite3_result_error(sqlite3_context*, const char*, int);
-void sqlite3_result_error16(sqlite3_context*, const void*, int);
-void sqlite3_result_error_toobig(sqlite3_context*);
-void sqlite3_result_error_nomem(sqlite3_context*);
-void sqlite3_result_error_code(sqlite3_context*, int);
-void sqlite3_result_int(sqlite3_context*, int);
-void sqlite3_result_int64(sqlite3_context*, sqlite3_int64);
-void sqlite3_result_null(sqlite3_context*);
-void sqlite3_result_text(sqlite3_context*, const char*, int, void(*)(void*));
-void sqlite3_result_text16(sqlite3_context*, const void*, int, void(*)(void*));
-void sqlite3_result_text16le(sqlite3_context*, const void*, int,void(*)(void*));
-void sqlite3_result_text16be(sqlite3_context*, const void*, int,void(*)(void*));
-void sqlite3_result_value(sqlite3_context*, sqlite3_value*);
-void sqlite3_result_zeroblob(sqlite3_context*, int n);
-
-/*
-** CAPI3REF: Define New Collating Sequences {F16600}
-**
-** {F16601}
-** These functions are used to add new collation sequences to the
-** [sqlite3*] handle specified as the first argument.
-**
-** {F16602}
-** The name of the new collation sequence is specified as a UTF-8 string
-** for sqlite3_create_collation() and sqlite3_create_collation_v2()
-** and a UTF-16 string for sqlite3_create_collation16(). {F16603} In all cases
-** the name is passed as the second function argument.
-**
-** {F16604}
-** The third argument may be one of the constants [SQLITE_UTF8],
-** [SQLITE_UTF16LE] or [SQLITE_UTF16BE], indicating that the user-supplied
-** routine expects to be passed pointers to strings encoded using UTF-8,
-** UTF-16 little-endian or UTF-16 big-endian respectively. {F16605} The
-** third argument might also be [SQLITE_UTF16_ALIGNED] to indicate that
-** the routine expects pointers to 16-bit word aligned strings
-** of UTF16 in the native byte order of the host computer.
-**
-** {F16607}
-** A pointer to the user supplied routine must be passed as the fifth
-** argument. {F16609} If it is NULL, this is the same as deleting the collation
-** sequence (so that SQLite cannot call it anymore).
-** {F16611} Each time the application
-** supplied function is invoked, it is passed a copy of the void* passed as
-** the fourth argument to sqlite3_create_collation() or
-** sqlite3_create_collation16() as its first parameter.
-**
-** {F16612}
-** The remaining arguments to the application-supplied routine are two strings,
-** each represented by a (length, data) pair and encoded in the encoding
-** that was passed as the third argument when the collation sequence was
-** registered. {END} The application defined collation routine should
-** return negative, zero or positive if
-** the first string is less than, equal to, or greater than the second
-** string. i.e. (STRING1 - STRING2).
-**
-** {F16615}
-** The sqlite3_create_collation_v2() works like sqlite3_create_collation()
-** excapt that it takes an extra argument which is a destructor for
-** the collation. {F16617} The destructor is called when the collation is
-** destroyed and is passed a copy of the fourth parameter void* pointer
-** of the sqlite3_create_collation_v2().
-** {F16618} Collations are destroyed when
-** they are overridden by later calls to the collation creation functions
-** or when the [sqlite3*] database handle is closed using [sqlite3_close()].
-*/
-int sqlite3_create_collation(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
- int(*xCompare)(void*,int,const void*,int,const void*)
-);
-int sqlite3_create_collation_v2(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
- int(*xCompare)(void*,int,const void*,int,const void*),
- void(*xDestroy)(void*)
-);
-int sqlite3_create_collation16(
- sqlite3*,
- const char *zName,
- int eTextRep,
- void*,
- int(*xCompare)(void*,int,const void*,int,const void*)
-);
-
-/*
-** CAPI3REF: Collation Needed Callbacks {F16700}
-**
-** {F16701}
-** To avoid having to register all collation sequences before a database
-** can be used, a single callback function may be registered with the
-** database handle to be called whenever an undefined collation sequence is
-** required.
-**
-** {F16702}
-** If the function is registered using the sqlite3_collation_needed() API,
-** then it is passed the names of undefined collation sequences as strings
-** encoded in UTF-8. {F16703} If sqlite3_collation_needed16() is used, the names
-** are passed as UTF-16 in machine native byte order. {F16704} A call to either
-** function replaces any existing callback.
-**
-** {F16705} When the callback is invoked, the first argument passed is a copy
-** of the second argument to sqlite3_collation_needed() or
-** sqlite3_collation_needed16(). {F16706} The second argument is the database
-** handle. {F16707} The third argument is one of [SQLITE_UTF8],
-** [SQLITE_UTF16BE], or [SQLITE_UTF16LE], indicating the most
-** desirable form of the collation sequence function required.
-** {F16708} The fourth parameter is the name of the
-** required collation sequence. {END}
-**
-** The callback function should register the desired collation using
-** [sqlite3_create_collation()], [sqlite3_create_collation16()], or
-** [sqlite3_create_collation_v2()].
-*/
-int sqlite3_collation_needed(
- sqlite3*,
- void*,
- void(*)(void*,sqlite3*,int eTextRep,const char*)
-);
-int sqlite3_collation_needed16(
- sqlite3*,
- void*,
- void(*)(void*,sqlite3*,int eTextRep,const void*)
-);
-
-/*
-** Specify the key for an encrypted database. This routine should be
-** called right after sqlite3_open().
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-int sqlite3_key(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The key */
-);
-
-/*
-** Change the key on an open database. If the current database is not
-** encrypted, this routine will encrypt it. If pNew==0 or nNew==0, the
-** database is decrypted.
-**
-** The code to implement this API is not available in the public release
-** of SQLite.
-*/
-int sqlite3_rekey(
- sqlite3 *db, /* Database to be rekeyed */
- const void *pKey, int nKey /* The new key */
-);
-
-/*
-** CAPI3REF: Suspend Execution For A Short Time {F10530}
-**
-** {F10531} The sqlite3_sleep() function
-** causes the current thread to suspend execution
-** for at least a number of milliseconds specified in its parameter.
-**
-** {F10532} If the operating system does not support sleep requests with
-** millisecond time resolution, then the time will be rounded up to
-** the nearest second. {F10533} The number of milliseconds of sleep actually
-** requested from the operating system is returned.
-**
-** {F10534} SQLite implements this interface by calling the xSleep()
-** method of the default [sqlite3_vfs] object. {END}
-*/
-int sqlite3_sleep(int);
-
-/*
-** CAPI3REF: Name Of The Folder Holding Temporary Files {F10310}
-**
-** If this global variable is made to point to a string which is
-** the name of a folder (a.ka. directory), then all temporary files
-** created by SQLite will be placed in that directory. If this variable
-** is NULL pointer, then SQLite does a search for an appropriate temporary
-** file directory.
-**
-** It is not safe to modify this variable once a database connection
-** has been opened. It is intended that this variable be set once
-** as part of process initialization and before any SQLite interface
-** routines have been call and remain unchanged thereafter.
-*/
-SQLITE_EXTERN char *sqlite3_temp_directory;
-
-/*
-** CAPI3REF: Test To See If The Database Is In Auto-Commit Mode {F12930}
-**
-** The sqlite3_get_autocommit() interfaces returns non-zero or
-** zero if the given database connection is or is not in autocommit mode,
-** respectively. Autocommit mode is on
-** by default. Autocommit mode is disabled by a [BEGIN] statement.
-** Autocommit mode is reenabled by a [COMMIT] or [ROLLBACK].
-**
-** If certain kinds of errors occur on a statement within a multi-statement
-** transactions (errors including [SQLITE_FULL], [SQLITE_IOERR],
-** [SQLITE_NOMEM], [SQLITE_BUSY], and [SQLITE_INTERRUPT]) then the
-** transaction might be rolled back automatically. The only way to
-** find out if SQLite automatically rolled back the transaction after
-** an error is to use this function.
-**
-** INVARIANTS:
-**
-** {F12931} The [sqlite3_get_autocommit()] interface returns non-zero or
-** zero if the given database connection is or is not in autocommit
-** mode, respectively.
-**
-** {F12932} Autocommit mode is on by default.
-**
-** {F12933} Autocommit mode is disabled by a successful [BEGIN] statement.
-**
-** {F12934} Autocommit mode is enabled by a successful [COMMIT] or [ROLLBACK]
-** statement.
-**
-**
-** LIMITATIONS:
-***
-** {U12936} If another thread changes the autocommit status of the database
-** connection while this routine is running, then the return value
-** is undefined.
-*/
-int sqlite3_get_autocommit(sqlite3*);
-
-/*
-** CAPI3REF: Find The Database Handle Of A Prepared Statement {F13120}
-**
-** {F13121} The sqlite3_db_handle interface
-** returns the [sqlite3*] database handle to which a
-** [prepared statement] belongs.
-** {F13122} the database handle returned by sqlite3_db_handle
-** is the same database handle that was
-** the first argument to the [sqlite3_prepare_v2()] or its variants
-** that was used to create the statement in the first place.
-*/
-sqlite3 *sqlite3_db_handle(sqlite3_stmt*);
-
-
-/*
-** CAPI3REF: Commit And Rollback Notification Callbacks {F12950}
-**
-** {F12951} The sqlite3_commit_hook() interface registers a callback
-** function to be invoked whenever a transaction is committed.
-** {F12952} Any callback set by a previous call to sqlite3_commit_hook()
-** for the same database connection is overridden.
-** {F12953} The sqlite3_rollback_hook() interface registers a callback
-** function to be invoked whenever a transaction is committed.
-** {F12954} Any callback set by a previous call to sqlite3_commit_hook()
-** for the same database connection is overridden.
-** {F12956} The pArg argument is passed through
-** to the callback. {F12957} If the callback on a commit hook function
-** returns non-zero, then the commit is converted into a rollback.
-**
-** {F12958} If another function was previously registered, its
-** pArg value is returned. Otherwise NULL is returned.
-**
-** {F12959} Registering a NULL function disables the callback.
-**
-** {F12961} For the purposes of this API, a transaction is said to have been
-** rolled back if an explicit "ROLLBACK" statement is executed, or
-** an error or constraint causes an implicit rollback to occur.
-** {F12962} The rollback callback is not invoked if a transaction is
-** automatically rolled back because the database connection is closed.
-** {F12964} The rollback callback is not invoked if a transaction is
-** rolled back because a commit callback returned non-zero.
-** <todo> Check on this </todo> {END}
-**
-** These are experimental interfaces and are subject to change.
-*/
-void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
-void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
-
-/*
-** CAPI3REF: Data Change Notification Callbacks {F12970}
-**
-** {F12971} The sqlite3_update_hook() interface
-** registers a callback function with the database connection identified by the
-** first argument to be invoked whenever a row is updated, inserted or deleted.
-** {F12972} Any callback set by a previous call to this function for the same
-** database connection is overridden.
-**
-** {F12974} The second argument is a pointer to the function to invoke when a
-** row is updated, inserted or deleted.
-** {F12976} The first argument to the callback is
-** a copy of the third argument to sqlite3_update_hook().
-** {F12977} The second callback
-** argument is one of [SQLITE_INSERT], [SQLITE_DELETE] or [SQLITE_UPDATE],
-** depending on the operation that caused the callback to be invoked.
-** {F12978} The third and
-** fourth arguments to the callback contain pointers to the database and
-** table name containing the affected row.
-** {F12979} The final callback parameter is
-** the rowid of the row.
-** {F12981} In the case of an update, this is the rowid after
-** the update takes place.
-**
-** {F12983} The update hook is not invoked when internal system tables are
-** modified (i.e. sqlite_master and sqlite_sequence).
-**
-** {F12984} If another function was previously registered, its pArg value
-** is returned. {F12985} Otherwise NULL is returned.
-*/
-void *sqlite3_update_hook(
- sqlite3*,
- void(*)(void *,int ,char const *,char const *,sqlite3_int64),
- void*
-);
-
-/*
-** CAPI3REF: Enable Or Disable Shared Pager Cache {F10330}
-**
-** {F10331}
-** This routine enables or disables the sharing of the database cache
-** and schema data structures between connections to the same database.
-** {F10332}
-** Sharing is enabled if the argument is true and disabled if the argument
-** is false.
-**
-** {F10333} Cache sharing is enabled and disabled
-** for an entire process. {END} This is a change as of SQLite version 3.5.0.
-** In prior versions of SQLite, sharing was
-** enabled or disabled for each thread separately.
-**
-** {F10334}
-** The cache sharing mode set by this interface effects all subsequent
-** calls to [sqlite3_open()], [sqlite3_open_v2()], and [sqlite3_open16()].
-** {F10335} Existing database connections continue use the sharing mode
-** that was in effect at the time they were opened. {END}
-**
-** Virtual tables cannot be used with a shared cache. {F10336} When shared
-** cache is enabled, the [sqlite3_create_module()] API used to register
-** virtual tables will always return an error. {END}
-**
-** {F10337} This routine returns [SQLITE_OK] if shared cache was
-** enabled or disabled successfully. {F10338} An [error code]
-** is returned otherwise. {END}
-**
-** {F10339} Shared cache is disabled by default. {END} But this might change in
-** future releases of SQLite. Applications that care about shared
-** cache setting should set it explicitly.
-*/
-int sqlite3_enable_shared_cache(int);
-
-/*
-** CAPI3REF: Attempt To Free Heap Memory {F17340}
-**
-** {F17341} The sqlite3_release_memory() interface attempts to
-** free N bytes of heap memory by deallocating non-essential memory
-** allocations held by the database labrary. {END} Memory used
-** to cache database pages to improve performance is an example of
-** non-essential memory. {F16342} sqlite3_release_memory() returns
-** the number of bytes actually freed, which might be more or less
-** than the amount requested.
-*/
-int sqlite3_release_memory(int);
-
-/*
-** CAPI3REF: Impose A Limit On Heap Size {F17350}
-**
-** {F16351} The sqlite3_soft_heap_limit() interface
-** places a "soft" limit on the amount of heap memory that may be allocated
-** by SQLite. {F16352} If an internal allocation is requested
-** that would exceed the soft heap limit, [sqlite3_release_memory()] is
-** invoked one or more times to free up some space before the allocation
-** is made. {END}
-**
-** {F16353} The limit is called "soft", because if
-** [sqlite3_release_memory()] cannot
-** free sufficient memory to prevent the limit from being exceeded,
-** the memory is allocated anyway and the current operation proceeds.
-**
-** {F16354}
-** A negative or zero value for N means that there is no soft heap limit and
-** [sqlite3_release_memory()] will only be called when memory is exhausted.
-** {F16355} The default value for the soft heap limit is zero.
-**
-** SQLite makes a best effort to honor the soft heap limit.
-** {F16356} But if the soft heap limit cannot honored, execution will
-** continue without error or notification. {END} This is why the limit is
-** called a "soft" limit. It is advisory only.
-**
-** Prior to SQLite version 3.5.0, this routine only constrained the memory
-** allocated by a single thread - the same thread in which this routine
-** runs. Beginning with SQLite version 3.5.0, the soft heap limit is
-** applied to all threads. {F16357} The value specified for the soft heap limit
-** is an upper bound on the total memory allocation for all threads. {END} In
-** version 3.5.0 there is no mechanism for limiting the heap usage for
-** individual threads.
-*/
-void sqlite3_soft_heap_limit(int);
-
-/*
-** CAPI3REF: Extract Metadata About A Column Of A Table {F12850}
-**
-** This routine
-** returns meta-data about a specific column of a specific database
-** table accessible using the connection handle passed as the first function
-** argument.
-**
-** The column is identified by the second, third and fourth parameters to
-** this function. The second parameter is either the name of the database
-** (i.e. "main", "temp" or an attached database) containing the specified
-** table or NULL. If it is NULL, then all attached databases are searched
-** for the table using the same algorithm as the database engine uses to
-** resolve unqualified table references.
-**
-** The third and fourth parameters to this function are the table and column
-** name of the desired column, respectively. Neither of these parameters
-** may be NULL.
-**
-** Meta information is returned by writing to the memory locations passed as
-** the 5th and subsequent parameters to this function. Any of these
-** arguments may be NULL, in which case the corresponding element of meta
-** information is ommitted.
-**
-** <pre>
-** Parameter Output Type Description
-** -----------------------------------
-**
-** 5th const char* Data type
-** 6th const char* Name of the default collation sequence
-** 7th int True if the column has a NOT NULL constraint
-** 8th int True if the column is part of the PRIMARY KEY
-** 9th int True if the column is AUTOINCREMENT
-** </pre>
-**
-**
-** The memory pointed to by the character pointers returned for the
-** declaration type and collation sequence is valid only until the next
-** call to any sqlite API function.
-**
-** If the specified table is actually a view, then an error is returned.
-**
-** If the specified column is "rowid", "oid" or "_rowid_" and an
-** INTEGER PRIMARY KEY column has been explicitly declared, then the output
-** parameters are set for the explicitly declared column. If there is no
-** explicitly declared IPK column, then the output parameters are set as
-** follows:
-**
-** <pre>
-** data type: "INTEGER"
-** collation sequence: "BINARY"
-** not null: 0
-** primary key: 1
-** auto increment: 0
-** </pre>
-**
-** This function may load one or more schemas from database files. If an
-** error occurs during this process, or if the requested table or column
-** cannot be found, an SQLITE error code is returned and an error message
-** left in the database handle (to be retrieved using sqlite3_errmsg()).
-**
-** This API is only available if the library was compiled with the
-** SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined.
-*/
-int sqlite3_table_column_metadata(
- sqlite3 *db, /* Connection handle */
- const char *zDbName, /* Database name or NULL */
- const char *zTableName, /* Table name */
- const char *zColumnName, /* Column name */
- char const **pzDataType, /* OUTPUT: Declared data type */
- char const **pzCollSeq, /* OUTPUT: Collation sequence name */
- int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */
- int *pPrimaryKey, /* OUTPUT: True if column part of PK */
- int *pAutoinc /* OUTPUT: True if column is auto-increment */
-);
-
-/*
-** CAPI3REF: Load An Extension {F12600}
-**
-** {F12601} The sqlite3_load_extension() interface
-** attempts to load an SQLite extension library contained in the file
-** zFile. {F12602} The entry point is zProc. {F12603} zProc may be 0
-** in which case the name of the entry point defaults
-** to "sqlite3_extension_init".
-**
-** {F12604} The sqlite3_load_extension() interface shall
-** return [SQLITE_OK] on success and [SQLITE_ERROR] if something goes wrong.
-**
-** {F12605}
-** If an error occurs and pzErrMsg is not 0, then the
-** sqlite3_load_extension() interface shall attempt to fill *pzErrMsg with
-** error message text stored in memory obtained from [sqlite3_malloc()].
-** {END} The calling function should free this memory
-** by calling [sqlite3_free()].
-**
-** {F12606}
-** Extension loading must be enabled using [sqlite3_enable_load_extension()]
-** prior to calling this API or an error will be returned.
-*/
-int sqlite3_load_extension(
- sqlite3 *db, /* Load the extension into this database connection */
- const char *zFile, /* Name of the shared library containing extension */
- const char *zProc, /* Entry point. Derived from zFile if 0 */
- char **pzErrMsg /* Put error message here if not 0 */
-);
-
-/*
-** CAPI3REF: Enable Or Disable Extension Loading {F12620}
-**
-** So as not to open security holes in older applications that are
-** unprepared to deal with extension loading, and as a means of disabling
-** extension loading while evaluating user-entered SQL, the following
-** API is provided to turn the [sqlite3_load_extension()] mechanism on and
-** off. {F12622} It is off by default. {END} See ticket #1863.
-**
-** {F12621} Call the sqlite3_enable_load_extension() routine
-** with onoff==1 to turn extension loading on
-** and call it with onoff==0 to turn it back off again. {END}
-*/
-int sqlite3_enable_load_extension(sqlite3 *db, int onoff);
-
-/*
-** CAPI3REF: Make Arrangements To Automatically Load An Extension {F12640}
-**
-** {F12641} This function
-** registers an extension entry point that is automatically invoked
-** whenever a new database connection is opened using
-** [sqlite3_open()], [sqlite3_open16()], or [sqlite3_open_v2()]. {END}
-**
-** This API can be invoked at program startup in order to register
-** one or more statically linked extensions that will be available
-** to all new database connections.
-**
-** {F12642} Duplicate extensions are detected so calling this routine multiple
-** times with the same extension is harmless.
-**
-** {F12643} This routine stores a pointer to the extension in an array
-** that is obtained from sqlite_malloc(). {END} If you run a memory leak
-** checker on your program and it reports a leak because of this
-** array, then invoke [sqlite3_reset_auto_extension()] prior
-** to shutdown to free the memory.
-**
-** {F12644} Automatic extensions apply across all threads. {END}
-**
-** This interface is experimental and is subject to change or
-** removal in future releases of SQLite.
-*/
-int sqlite3_auto_extension(void *xEntryPoint);
-
-
-/*
-** CAPI3REF: Reset Automatic Extension Loading {F12660}
-**
-** {F12661} This function disables all previously registered
-** automatic extensions. {END} This
-** routine undoes the effect of all prior [sqlite3_auto_extension()]
-** calls.
-**
-** {F12662} This call disabled automatic extensions in all threads. {END}
-**
-** This interface is experimental and is subject to change or
-** removal in future releases of SQLite.
-*/
-void sqlite3_reset_auto_extension(void);
-
-
-/*
-****** EXPERIMENTAL - subject to change without notice **************
-**
-** The interface to the virtual-table mechanism is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stablizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-*/
-
-/*
-** Structures used by the virtual table interface
-*/
-typedef struct sqlite3_vtab sqlite3_vtab;
-typedef struct sqlite3_index_info sqlite3_index_info;
-typedef struct sqlite3_vtab_cursor sqlite3_vtab_cursor;
-typedef struct sqlite3_module sqlite3_module;
-
-/*
-** A module is a class of virtual tables. Each module is defined
-** by an instance of the following structure. This structure consists
-** mostly of methods for the module.
-*/
-struct sqlite3_module {
- int iVersion;
- int (*xCreate)(sqlite3*, void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVTab, char**);
- int (*xConnect)(sqlite3*, void *pAux,
- int argc, const char *const*argv,
- sqlite3_vtab **ppVTab, char**);
- int (*xBestIndex)(sqlite3_vtab *pVTab, sqlite3_index_info*);
- int (*xDisconnect)(sqlite3_vtab *pVTab);
- int (*xDestroy)(sqlite3_vtab *pVTab);
- int (*xOpen)(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor);
- int (*xClose)(sqlite3_vtab_cursor*);
- int (*xFilter)(sqlite3_vtab_cursor*, int idxNum, const char *idxStr,
- int argc, sqlite3_value **argv);
- int (*xNext)(sqlite3_vtab_cursor*);
- int (*xEof)(sqlite3_vtab_cursor*);
- int (*xColumn)(sqlite3_vtab_cursor*, sqlite3_context*, int);
- int (*xRowid)(sqlite3_vtab_cursor*, sqlite3_int64 *pRowid);
- int (*xUpdate)(sqlite3_vtab *, int, sqlite3_value **, sqlite3_int64 *);
- int (*xBegin)(sqlite3_vtab *pVTab);
- int (*xSync)(sqlite3_vtab *pVTab);
- int (*xCommit)(sqlite3_vtab *pVTab);
- int (*xRollback)(sqlite3_vtab *pVTab);
- int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName,
- void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
- void **ppArg);
-
- int (*xRename)(sqlite3_vtab *pVtab, const char *zNew);
-};
-
-/*
-** The sqlite3_index_info structure and its substructures is used to
-** pass information into and receive the reply from the xBestIndex
-** method of an sqlite3_module. The fields under **Inputs** are the
-** inputs to xBestIndex and are read-only. xBestIndex inserts its
-** results into the **Outputs** fields.
-**
-** The aConstraint[] array records WHERE clause constraints of the
-** form:
-**
-** column OP expr
-**
-** Where OP is =, <, <=, >, or >=.
-** The particular operator is stored
-** in aConstraint[].op. The index of the column is stored in
-** aConstraint[].iColumn. aConstraint[].usable is TRUE if the
-** expr on the right-hand side can be evaluated (and thus the constraint
-** is usable) and false if it cannot.
-**
-** The optimizer automatically inverts terms of the form "expr OP column"
-** and makes other simplifications to the WHERE clause in an attempt to
-** get as many WHERE clause terms into the form shown above as possible.
-** The aConstraint[] array only reports WHERE clause terms in the correct
-** form that refer to the particular virtual table being queried.
-**
-** Information about the ORDER BY clause is stored in aOrderBy[].
-** Each term of aOrderBy records a column of the ORDER BY clause.
-**
-** The xBestIndex method must fill aConstraintUsage[] with information
-** about what parameters to pass to xFilter. If argvIndex>0 then
-** the right-hand side of the corresponding aConstraint[] is evaluated
-** and becomes the argvIndex-th entry in argv. If aConstraintUsage[].omit
-** is true, then the constraint is assumed to be fully handled by the
-** virtual table and is not checked again by SQLite.
-**
-** The idxNum and idxPtr values are recorded and passed into xFilter.
-** sqlite3_free() is used to free idxPtr if needToFreeIdxPtr is true.
-**
-** The orderByConsumed means that output from xFilter will occur in
-** the correct order to satisfy the ORDER BY clause so that no separate
-** sorting step is required.
-**
-** The estimatedCost value is an estimate of the cost of doing the
-** particular lookup. A full scan of a table with N entries should have
-** a cost of N. A binary search of a table of N entries should have a
-** cost of approximately log(N).
-*/
-struct sqlite3_index_info {
- /* Inputs */
- int nConstraint; /* Number of entries in aConstraint */
- struct sqlite3_index_constraint {
- int iColumn; /* Column on left-hand side of constraint */
- unsigned char op; /* Constraint operator */
- unsigned char usable; /* True if this constraint is usable */
- int iTermOffset; /* Used internally - xBestIndex should ignore */
- } *aConstraint; /* Table of WHERE clause constraints */
- int nOrderBy; /* Number of terms in the ORDER BY clause */
- struct sqlite3_index_orderby {
- int iColumn; /* Column number */
- unsigned char desc; /* True for DESC. False for ASC. */
- } *aOrderBy; /* The ORDER BY clause */
-
- /* Outputs */
- struct sqlite3_index_constraint_usage {
- int argvIndex; /* if >0, constraint is part of argv to xFilter */
- unsigned char omit; /* Do not code a test for this constraint */
- } *aConstraintUsage;
- int idxNum; /* Number used to identify the index */
- char *idxStr; /* String, possibly obtained from sqlite3_malloc */
- int needToFreeIdxStr; /* Free idxStr using sqlite3_free() if true */
- int orderByConsumed; /* True if output is already ordered */
- double estimatedCost; /* Estimated cost of using this index */
-};
-#define SQLITE_INDEX_CONSTRAINT_EQ 2
-#define SQLITE_INDEX_CONSTRAINT_GT 4
-#define SQLITE_INDEX_CONSTRAINT_LE 8
-#define SQLITE_INDEX_CONSTRAINT_LT 16
-#define SQLITE_INDEX_CONSTRAINT_GE 32
-#define SQLITE_INDEX_CONSTRAINT_MATCH 64
-
-/*
-** This routine is used to register a new module name with an SQLite
-** connection. Module names must be registered before creating new
-** virtual tables on the module, or before using preexisting virtual
-** tables of the module.
-*/
-int sqlite3_create_module(
- sqlite3 *db, /* SQLite connection to register module with */
- const char *zName, /* Name of the module */
- const sqlite3_module *, /* Methods for the module */
- void * /* Client data for xCreate/xConnect */
-);
-
-/*
-** This routine is identical to the sqlite3_create_module() method above,
-** except that it allows a destructor function to be specified. It is
-** even more experimental than the rest of the virtual tables API.
-*/
-int sqlite3_create_module_v2(
- sqlite3 *db, /* SQLite connection to register module with */
- const char *zName, /* Name of the module */
- const sqlite3_module *, /* Methods for the module */
- void *, /* Client data for xCreate/xConnect */
- void(*xDestroy)(void*) /* Module destructor function */
-);
-
-/*
-** Every module implementation uses a subclass of the following structure
-** to describe a particular instance of the module. Each subclass will
-** be tailored to the specific needs of the module implementation. The
-** purpose of this superclass is to define certain fields that are common
-** to all module implementations.
-**
-** Virtual tables methods can set an error message by assigning a
-** string obtained from sqlite3_mprintf() to zErrMsg. The method should
-** take care that any prior string is freed by a call to sqlite3_free()
-** prior to assigning a new string to zErrMsg. After the error message
-** is delivered up to the client application, the string will be automatically
-** freed by sqlite3_free() and the zErrMsg field will be zeroed. Note
-** that sqlite3_mprintf() and sqlite3_free() are used on the zErrMsg field
-** since virtual tables are commonly implemented in loadable extensions which
-** do not have access to sqlite3MPrintf() or sqlite3Free().
-*/
-struct sqlite3_vtab {
- const sqlite3_module *pModule; /* The module for this virtual table */
- int nRef; /* Used internally */
- char *zErrMsg; /* Error message from sqlite3_mprintf() */
- /* Virtual table implementations will typically add additional fields */
-};
-
-/* Every module implementation uses a subclass of the following structure
-** to describe cursors that point into the virtual table and are used
-** to loop through the virtual table. Cursors are created using the
-** xOpen method of the module. Each module implementation will define
-** the content of a cursor structure to suit its own needs.
-**
-** This superclass exists in order to define fields of the cursor that
-** are common to all implementations.
-*/
-struct sqlite3_vtab_cursor {
- sqlite3_vtab *pVtab; /* Virtual table of this cursor */
- /* Virtual table implementations will typically add additional fields */
-};
-
-/*
-** The xCreate and xConnect methods of a module use the following API
-** to declare the format (the names and datatypes of the columns) of
-** the virtual tables they implement.
-*/
-int sqlite3_declare_vtab(sqlite3*, const char *zCreateTable);
-
-/*
-** Virtual tables can provide alternative implementations of functions
-** using the xFindFunction method. But global versions of those functions
-** must exist in order to be overloaded.
-**
-** This API makes sure a global version of a function with a particular
-** name and number of parameters exists. If no such function exists
-** before this API is called, a new function is created. The implementation
-** of the new function always causes an exception to be thrown. So
-** the new function is not good for anything by itself. Its only
-** purpose is to be a place-holder function that can be overloaded
-** by virtual tables.
-**
-** This API should be considered part of the virtual table interface,
-** which is experimental and subject to change.
-*/
-int sqlite3_overload_function(sqlite3*, const char *zFuncName, int nArg);
-
-/*
-** The interface to the virtual-table mechanism defined above (back up
-** to a comment remarkably similar to this one) is currently considered
-** to be experimental. The interface might change in incompatible ways.
-** If this is a problem for you, do not use the interface at this time.
-**
-** When the virtual-table mechanism stabilizes, we will declare the
-** interface fixed, support it indefinitely, and remove this comment.
-**
-****** EXPERIMENTAL - subject to change without notice **************
-*/
-
-/*
-** CAPI3REF: A Handle To An Open BLOB {F17800}
-**
-** An instance of the following opaque structure is used to
-** represent an blob-handle. A blob-handle is created by
-** [sqlite3_blob_open()] and destroyed by [sqlite3_blob_close()].
-** The [sqlite3_blob_read()] and [sqlite3_blob_write()] interfaces
-** can be used to read or write small subsections of the blob.
-** The [sqlite3_blob_bytes()] interface returns the size of the
-** blob in bytes.
-*/
-typedef struct sqlite3_blob sqlite3_blob;
-
-/*
-** CAPI3REF: Open A BLOB For Incremental I/O {F17810}
-**
-** {F17811} This interfaces opens a handle to the blob located
-** in row iRow,, column zColumn, table zTable in database zDb;
-** in other words, the same blob that would be selected by:
-**
-** <pre>
-** SELECT zColumn FROM zDb.zTable WHERE rowid = iRow;
-** </pre> {END}
-**
-** {F17812} If the flags parameter is non-zero, the blob is opened for
-** read and write access. If it is zero, the blob is opened for read
-** access. {END}
-**
-** {F17813} On success, [SQLITE_OK] is returned and the new
-** [sqlite3_blob | blob handle] is written to *ppBlob.
-** {F17814} Otherwise an error code is returned and
-** any value written to *ppBlob should not be used by the caller.
-** {F17815} This function sets the database-handle error code and message
-** accessible via [sqlite3_errcode()] and [sqlite3_errmsg()].
-** <todo>We should go through and mark all interfaces that behave this
-** way with a similar statement</todo>
-*/
-int sqlite3_blob_open(
- sqlite3*,
- const char *zDb,
- const char *zTable,
- const char *zColumn,
- sqlite3_int64 iRow,
- int flags,
- sqlite3_blob **ppBlob
-);
-
-/*
-** CAPI3REF: Close A BLOB Handle {F17830}
-**
-** Close an open [sqlite3_blob | blob handle].
-**
-** {F17831} Closing a BLOB shall cause the current transaction to commit
-** if there are no other BLOBs, no pending prepared statements, and the
-** database connection is in autocommit mode.
-** {F17832} If any writes were made to the BLOB, they might be held in cache
-** until the close operation if they will fit. {END}
-** Closing the BLOB often forces the changes
-** out to disk and so if any I/O errors occur, they will likely occur
-** at the time when the BLOB is closed. {F17833} Any errors that occur during
-** closing are reported as a non-zero return value.
-**
-** {F17839} The BLOB is closed unconditionally. Even if this routine returns
-** an error code, the BLOB is still closed.
-*/
-int sqlite3_blob_close(sqlite3_blob *);
-
-/*
-** CAPI3REF: Return The Size Of An Open BLOB {F17805}
-**
-** {F16806} Return the size in bytes of the blob accessible via the open
-** [sqlite3_blob | blob-handle] passed as an argument.
-*/
-int sqlite3_blob_bytes(sqlite3_blob *);
-
-/*
-** CAPI3REF: Read Data From A BLOB Incrementally {F17850}
-**
-** This function is used to read data from an open
-** [sqlite3_blob | blob-handle] into a caller supplied buffer.
-** {F17851} n bytes of data are copied into buffer
-** z from the open blob, starting at offset iOffset.
-**
-** {F17852} If offset iOffset is less than n bytes from the end of the blob,
-** [SQLITE_ERROR] is returned and no data is read. {F17853} If n is
-** less than zero [SQLITE_ERROR] is returned and no data is read.
-**
-** {F17854} On success, SQLITE_OK is returned. Otherwise, an
-** [error code] or an [extended error code] is returned.
-*/
-int sqlite3_blob_read(sqlite3_blob *, void *z, int n, int iOffset);
-
-/*
-** CAPI3REF: Write Data Into A BLOB Incrementally {F17870}
-**
-** This function is used to write data into an open
-** [sqlite3_blob | blob-handle] from a user supplied buffer.
-** {F17871} n bytes of data are copied from the buffer
-** pointed to by z into the open blob, starting at offset iOffset.
-**
-** {F17872} If the [sqlite3_blob | blob-handle] passed as the first argument
-** was not opened for writing (the flags parameter to [sqlite3_blob_open()]
-*** was zero), this function returns [SQLITE_READONLY].
-**
-** {F17873} This function may only modify the contents of the blob; it is
-** not possible to increase the size of a blob using this API.
-** {F17874} If offset iOffset is less than n bytes from the end of the blob,
-** [SQLITE_ERROR] is returned and no data is written. {F17875} If n is
-** less than zero [SQLITE_ERROR] is returned and no data is written.
-**
-** {F17876} On success, SQLITE_OK is returned. Otherwise, an
-** [error code] or an [extended error code] is returned.
-*/
-int sqlite3_blob_write(sqlite3_blob *, const void *z, int n, int iOffset);
-
-/*
-** CAPI3REF: Virtual File System Objects {F11200}
-**
-** A virtual filesystem (VFS) is an [sqlite3_vfs] object
-** that SQLite uses to interact
-** with the underlying operating system. Most builds come with a
-** single default VFS that is appropriate for the host computer.
-** New VFSes can be registered and existing VFSes can be unregistered.
-** The following interfaces are provided.
-**
-** {F11201} The sqlite3_vfs_find() interface returns a pointer to
-** a VFS given its name. {F11202} Names are case sensitive.
-** {F11203} Names are zero-terminated UTF-8 strings.
-** {F11204} If there is no match, a NULL
-** pointer is returned. {F11205} If zVfsName is NULL then the default
-** VFS is returned. {END}
-**
-** {F11210} New VFSes are registered with sqlite3_vfs_register().
-** {F11211} Each new VFS becomes the default VFS if the makeDflt flag is set.
-** {F11212} The same VFS can be registered multiple times without injury.
-** {F11213} To make an existing VFS into the default VFS, register it again
-** with the makeDflt flag set. {U11214} If two different VFSes with the
-** same name are registered, the behavior is undefined. {U11215} If a
-** VFS is registered with a name that is NULL or an empty string,
-** then the behavior is undefined.
-**
-** {F11220} Unregister a VFS with the sqlite3_vfs_unregister() interface.
-** {F11221} If the default VFS is unregistered, another VFS is chosen as
-** the default. The choice for the new VFS is arbitrary.
-*/
-sqlite3_vfs *sqlite3_vfs_find(const char *zVfsName);
-int sqlite3_vfs_register(sqlite3_vfs*, int makeDflt);
-int sqlite3_vfs_unregister(sqlite3_vfs*);
-
-/*
-** CAPI3REF: Mutexes {F17000}
-**
-** The SQLite core uses these routines for thread
-** synchronization. Though they are intended for internal
-** use by SQLite, code that links against SQLite is
-** permitted to use any of these routines.
-**
-** The SQLite source code contains multiple implementations
-** of these mutex routines. An appropriate implementation
-** is selected automatically at compile-time. The following
-** implementations are available in the SQLite core:
-**
-** <ul>
-** <li> SQLITE_MUTEX_OS2
-** <li> SQLITE_MUTEX_PTHREAD
-** <li> SQLITE_MUTEX_W32
-** <li> SQLITE_MUTEX_NOOP
-** </ul>
-**
-** The SQLITE_MUTEX_NOOP implementation is a set of routines
-** that does no real locking and is appropriate for use in
-** a single-threaded application. The SQLITE_MUTEX_OS2,
-** SQLITE_MUTEX_PTHREAD, and SQLITE_MUTEX_W32 implementations
-** are appropriate for use on os/2, unix, and windows.
-**
-** If SQLite is compiled with the SQLITE_MUTEX_APPDEF preprocessor
-** macro defined (with "-DSQLITE_MUTEX_APPDEF=1"), then no mutex
-** implementation is included with the library. The
-** mutex interface routines defined here become external
-** references in the SQLite library for which implementations
-** must be provided by the application. This facility allows an
-** application that links against SQLite to provide its own mutex
-** implementation without having to modify the SQLite core.
-**
-** {F17011} The sqlite3_mutex_alloc() routine allocates a new
-** mutex and returns a pointer to it. {F17012} If it returns NULL
-** that means that a mutex could not be allocated. {F17013} SQLite
-** will unwind its stack and return an error. {F17014} The argument
-** to sqlite3_mutex_alloc() is one of these integer constants:
-**
-** <ul>
-** <li> SQLITE_MUTEX_FAST
-** <li> SQLITE_MUTEX_RECURSIVE
-** <li> SQLITE_MUTEX_STATIC_MASTER
-** <li> SQLITE_MUTEX_STATIC_MEM
-** <li> SQLITE_MUTEX_STATIC_MEM2
-** <li> SQLITE_MUTEX_STATIC_PRNG
-** <li> SQLITE_MUTEX_STATIC_LRU
-** </ul> {END}
-**
-** {F17015} The first two constants cause sqlite3_mutex_alloc() to create
-** a new mutex. The new mutex is recursive when SQLITE_MUTEX_RECURSIVE
-** is used but not necessarily so when SQLITE_MUTEX_FAST is used. {END}
-** The mutex implementation does not need to make a distinction
-** between SQLITE_MUTEX_RECURSIVE and SQLITE_MUTEX_FAST if it does
-** not want to. {F17016} But SQLite will only request a recursive mutex in
-** cases where it really needs one. {END} If a faster non-recursive mutex
-** implementation is available on the host platform, the mutex subsystem
-** might return such a mutex in response to SQLITE_MUTEX_FAST.
-**
-** {F17017} The other allowed parameters to sqlite3_mutex_alloc() each return
-** a pointer to a static preexisting mutex. {END} Four static mutexes are
-** used by the current version of SQLite. Future versions of SQLite
-** may add additional static mutexes. Static mutexes are for internal
-** use by SQLite only. Applications that use SQLite mutexes should
-** use only the dynamic mutexes returned by SQLITE_MUTEX_FAST or
-** SQLITE_MUTEX_RECURSIVE.
-**
-** {F17018} Note that if one of the dynamic mutex parameters (SQLITE_MUTEX_FAST
-** or SQLITE_MUTEX_RECURSIVE) is used then sqlite3_mutex_alloc()
-** returns a different mutex on every call. {F17034} But for the static
-** mutex types, the same mutex is returned on every call that has
-** the same type number. {END}
-**
-** {F17019} The sqlite3_mutex_free() routine deallocates a previously
-** allocated dynamic mutex. {F17020} SQLite is careful to deallocate every
-** dynamic mutex that it allocates. {U17021} The dynamic mutexes must not be in
-** use when they are deallocated. {U17022} Attempting to deallocate a static
-** mutex results in undefined behavior. {F17023} SQLite never deallocates
-** a static mutex. {END}
-**
-** The sqlite3_mutex_enter() and sqlite3_mutex_try() routines attempt
-** to enter a mutex. {F17024} If another thread is already within the mutex,
-** sqlite3_mutex_enter() will block and sqlite3_mutex_try() will return
-** SQLITE_BUSY. {F17025} The sqlite3_mutex_try() interface returns SQLITE_OK
-** upon successful entry. {F17026} Mutexes created using
-** SQLITE_MUTEX_RECURSIVE can be entered multiple times by the same thread.
-** {F17027} In such cases the,
-** mutex must be exited an equal number of times before another thread
-** can enter. {U17028} If the same thread tries to enter any other
-** kind of mutex more than once, the behavior is undefined.
-** {F17029} SQLite will never exhibit
-** such behavior in its own use of mutexes. {END}
-**
-** Some systems (ex: windows95) do not the operation implemented by
-** sqlite3_mutex_try(). On those systems, sqlite3_mutex_try() will
-** always return SQLITE_BUSY. {F17030} The SQLite core only ever uses
-** sqlite3_mutex_try() as an optimization so this is acceptable behavior. {END}
-**
-** {F17031} The sqlite3_mutex_leave() routine exits a mutex that was
-** previously entered by the same thread. {U17032} The behavior
-** is undefined if the mutex is not currently entered by the
-** calling thread or is not currently allocated. {F17033} SQLite will
-** never do either. {END}
-**
-** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
-*/
-sqlite3_mutex *sqlite3_mutex_alloc(int);
-void sqlite3_mutex_free(sqlite3_mutex*);
-void sqlite3_mutex_enter(sqlite3_mutex*);
-int sqlite3_mutex_try(sqlite3_mutex*);
-void sqlite3_mutex_leave(sqlite3_mutex*);
-
-/*
-** CAPI3REF: Mutex Verifcation Routines {F17080}
-**
-** The sqlite3_mutex_held() and sqlite3_mutex_notheld() routines
-** are intended for use inside assert() statements. {F17081} The SQLite core
-** never uses these routines except inside an assert() and applications
-** are advised to follow the lead of the core. {F17082} The core only
-** provides implementations for these routines when it is compiled
-** with the SQLITE_DEBUG flag. {U17087} External mutex implementations
-** are only required to provide these routines if SQLITE_DEBUG is
-** defined and if NDEBUG is not defined.
-**
-** {F17083} These routines should return true if the mutex in their argument
-** is held or not held, respectively, by the calling thread. {END}
-**
-** {X17084} The implementation is not required to provided versions of these
-** routines that actually work.
-** If the implementation does not provide working
-** versions of these routines, it should at least provide stubs
-** that always return true so that one does not get spurious
-** assertion failures. {END}
-**
-** {F17085} If the argument to sqlite3_mutex_held() is a NULL pointer then
-** the routine should return 1. {END} This seems counter-intuitive since
-** clearly the mutex cannot be held if it does not exist. But the
-** the reason the mutex does not exist is because the build is not
-** using mutexes. And we do not want the assert() containing the
-** call to sqlite3_mutex_held() to fail, so a non-zero return is
-** the appropriate thing to do. {F17086} The sqlite3_mutex_notheld()
-** interface should also return 1 when given a NULL pointer.
-*/
-int sqlite3_mutex_held(sqlite3_mutex*);
-int sqlite3_mutex_notheld(sqlite3_mutex*);
-
-/*
-** CAPI3REF: Mutex Types {F17001}
-**
-** {F17002} The [sqlite3_mutex_alloc()] interface takes a single argument
-** which is one of these integer constants. {END}
-*/
-#define SQLITE_MUTEX_FAST 0
-#define SQLITE_MUTEX_RECURSIVE 1
-#define SQLITE_MUTEX_STATIC_MASTER 2
-#define SQLITE_MUTEX_STATIC_MEM 3 /* sqlite3_malloc() */
-#define SQLITE_MUTEX_STATIC_MEM2 4 /* sqlite3_release_memory() */
-#define SQLITE_MUTEX_STATIC_PRNG 5 /* sqlite3_random() */
-#define SQLITE_MUTEX_STATIC_LRU 6 /* lru page list */
-
-/*
-** CAPI3REF: Low-Level Control Of Database Files {F11300}
-**
-** {F11301} The [sqlite3_file_control()] interface makes a direct call to the
-** xFileControl method for the [sqlite3_io_methods] object associated
-** with a particular database identified by the second argument. {F11302} The
-** name of the database is the name assigned to the database by the
-** <a href="lang_attach.html">ATTACH</a> SQL command that opened the
-** database. {F11303} To control the main database file, use the name "main"
-** or a NULL pointer. {F11304} The third and fourth parameters to this routine
-** are passed directly through to the second and third parameters of
-** the xFileControl method. {F11305} The return value of the xFileControl
-** method becomes the return value of this routine.
-**
-** {F11306} If the second parameter (zDbName) does not match the name of any
-** open database file, then SQLITE_ERROR is returned. {F11307} This error
-** code is not remembered and will not be recalled by [sqlite3_errcode()]
-** or [sqlite3_errmsg()]. {U11308} The underlying xFileControl method might
-** also return SQLITE_ERROR. {U11309} There is no way to distinguish between
-** an incorrect zDbName and an SQLITE_ERROR return from the underlying
-** xFileControl method. {END}
-**
-** See also: [SQLITE_FCNTL_LOCKSTATE]
-*/
-int sqlite3_file_control(sqlite3*, const char *zDbName, int op, void*);
-
-/*
-** CAPI3REF: Testing Interface {F11400}
-**
-** The sqlite3_test_control() interface is used to read out internal
-** state of SQLite and to inject faults into SQLite for testing
-** purposes. The first parameter a operation code that determines
-** the number, meaning, and operation of all subsequent parameters.
-**
-** This interface is not for use by applications. It exists solely
-** for verifying the correct operation of the SQLite library. Depending
-** on how the SQLite library is compiled, this interface might not exist.
-**
-** The details of the operation codes, their meanings, the parameters
-** they take, and what they do are all subject to change without notice.
-** Unlike most of the SQLite API, this function is not guaranteed to
-** operate consistently from one release to the next.
-*/
-int sqlite3_test_control(int op, ...);
-
-/*
-** CAPI3REF: Testing Interface Operation Codes {F11410}
-**
-** These constants are the valid operation code parameters used
-** as the first argument to [sqlite3_test_control()].
-**
-** These parameters and their meansing are subject to change
-** without notice. These values are for testing purposes only.
-** Applications should not use any of these parameters or the
-** [sqlite3_test_control()] interface.
-*/
-#define SQLITE_TESTCTRL_FAULT_CONFIG 1
-#define SQLITE_TESTCTRL_FAULT_FAILURES 2
-#define SQLITE_TESTCTRL_FAULT_BENIGN_FAILURES 3
-#define SQLITE_TESTCTRL_FAULT_PENDING 4
-
-
-
-
-
-/*
-** Undo the hack that converts floating point types to integer for
-** builds on processors without floating point support.
-*/
-#ifdef SQLITE_OMIT_FLOATING_POINT
-# undef double
-#endif
-
-#ifdef __cplusplus
-} /* End of the 'extern "C"' block */
-#endif
-#endif
+++ /dev/null
-#ifndef _STDDEF_H_
-#define _STDDEF_H_
-
-#include "acess/intdefs.h"
-
-#ifndef NULL
-# define NULL ((void*)0)
-#endif
-
-typedef __intptr_t size_t;
-
-#endif
+++ /dev/null
-/*
- */
-#ifndef _STDINT_H_
-#define _STDINT_H_
-
-#include "acess/intdefs.h"
-
-#define INT_MIN -0x80000000
-#define INT_MAX 0x7FFFFFFF
-
-typedef __uint8_t uint8_t;
-typedef __uint16_t uint16_t;
-typedef __uint32_t uint32_t;
-typedef __uint64_t uint64_t;
-typedef __int8_t int8_t;
-typedef __int16_t int16_t;
-typedef __int32_t int32_t;
-typedef __int64_t int64_t;
-
-typedef __intptr_t intptr_t;
-typedef __uintptr_t uintptr_t;
-
-//typedef uint64_t off_t;
-
-#endif
+++ /dev/null
-/*
- * AcessOS LibC
- * stdlib.h
- */
-#ifndef __STDIO_H
-#define __STDIO_H
-
-#include <stdlib.h>
-#include <stdarg.h>
-
-/* === Types === */
-typedef struct sFILE FILE;
-
-/* === CONSTANTS === */
-#define EOF (-1)
-#define BUFSIZ 1024
-
-/* --- Standard IO --- */
-extern int printf(const char *format, ...);
-extern int vsnprintf(char *buf, size_t __maxlen, const char *format, va_list args);
-extern int vsprintf(char *buf, const char *format, va_list args);
-extern int sprintf(char *buf, const char *format, ...);
-extern int snprintf(char *buf, size_t maxlen, const char *format, ...);
-
-extern FILE *fopen(const char *file, const char *mode);
-extern FILE *freopen(const char *file, const char *mode, FILE *fp);
-extern FILE *fdopen(int fd, const char *modes);
-extern int fclose(FILE *fp);
-extern void fflush(FILE *fp);
-extern off_t ftell(FILE *fp);
-extern int fseek(FILE *fp, long int amt, int whence);
-
-extern size_t fread(void *buf, size_t size, size_t n, FILE *fp);
-extern size_t fwrite(void *buf, size_t size, size_t n, FILE *fp);
-extern int fgetc(FILE *fp);
-extern int fputc(int ch, FILE *fp);
-extern int getchar(void);
-extern int putchar(int ch);
-
-extern int fprintf(FILE *fp, const char *format, ...);
-extern int vfprintf(FILE *fp, const char *format, va_list args);
-
-extern FILE *stdin;
-extern FILE *stdout;
-extern FILE *stderr;
-
-#endif
-
+++ /dev/null
-/*\r
- * AcessOS LibC\r
- * stdlib.h\r
- */\r
-#ifndef __STDLIB_H\r
-#define __STDLIB_H\r
-\r
-#include <stddef.h>\r
-#include <stdarg.h>\r
-#include <sys/types.h>\r
-\r
-#define EXIT_FAILURE 1\r
-#define EXIT_SUCCESS 0\r
-\r
-/* --- Spinlock Macros --- */\r
-/* TODO: Support non-x86 architectures */\r
-#define DEFLOCK(_name) static int _spinlock_##_name=0;\r
-#define LOCK(_name) do{int v=1;while(v){__asm__ __volatile__("lock cmpxchgl %0, (%1)":"=a"(v):"D"((&_spinlock_##_name)),"a"(1));yield();}}while(0)\r
-#define UNLOCK(_name) __asm__ __volatile__("lock andl $0, (%0)"::"D"(&_spinlock_##_name))\r
-\r
-/* --- StdLib --- */\r
-extern void _exit(int code) __attribute__((noreturn)); /* NOTE: Also defined in acess/sys.h */\r
-extern int atoi(const char *ptr);\r
-extern void exit(int status) __attribute__((noreturn));\r
-extern void atexit(void (*__func)(void));\r
-extern void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));\r
-\r
-/* --- Environment --- */\r
-extern char *getenv(const char *name);\r
-\r
-/* --- Heap --- */\r
-extern void free(void *mem);\r
-extern void *malloc(size_t bytes);\r
-extern void *calloc(size_t __nmemb, size_t __size);\r
-extern void *realloc(void *__ptr, size_t __size);\r
-extern int IsHeap(void *ptr);\r
-\r
-/* --- Random --- */\r
-extern void srand(unsigned int seed);\r
-extern int rand(void);\r
-extern int rand_p(unsigned int *seedp);\r
-\r
-#ifndef SEEK_CUR\r
-# define SEEK_CUR 0\r
-# define SEEK_SET 1\r
-# define SEEK_END (-1)\r
-#endif\r
-\r
-#endif\r
+++ /dev/null
-/*
- * AcessOS LibC
- * string.h
- */
-#ifndef __STRING_H
-#define __STRING_H
-
-#include <stddef.h>
-
-/* Strings */
-extern size_t strlen(const char *string);
-extern size_t strnlen(const char *string, size_t maxlen);
-extern int strcmp(const char *str1, const char *str2);
-extern int strncmp(const char *str1, const char *str2, size_t maxlen);
-extern int strcasecmp(const char *s1, const char *s2);
-extern int strncasecmp(const char *s1, const char *s2, size_t maxlen);
-extern char *strcpy(char *dst, const char *src);
-extern char *strncpy(char *dst, const char *src, size_t num);
-extern char *strcat(char *dst, const char *src);
-extern char *strdup(const char *src);
-extern char *strndup(const char *src, size_t length);
-extern char *strchr(const char *str, int character);
-extern char *strrchr(const char *str, int character);
-extern char *strstr(const char *str1, const char *str2);
-extern size_t strcspn(const char *haystack, const char *reject);
-extern size_t strspn(const char *haystack, const char *accept);
-
-/* Memory */
-extern void *memset(void *dest, int val, size_t count);
-extern void *memcpy(void *dest, const void *src, size_t count);
-extern void *memmove(void *dest, const void *src, size_t count);
-extern int memcmp(const void *mem1, const void *mem2, size_t count);
-extern void *memchr(const void *ptr, int value, size_t num);
-
-#endif
+++ /dev/null
-/**
- * \file basic_drivers.h
- */
-#ifndef _SYS_BASIC_DRIVERS_H
-#define _SYS_BASIC_DRIVERS_H
-
-// === COMMON ===
-enum eDrv_Common {
- DRV_IOCTL_NULL,
- DRV_IOCTL_TYPE,
- DRV_IOCTL_IDENT,
- DRV_IOCTL_VER
-};
-
-enum eDrv_Types {
- DRV_TYPE_NULL, //!< NULL Type - Custom Interface
- DRV_TYPE_TERMINAL, //!< Terminal
- DRV_TYPE_VIDEO, //!< Video - LFB
- DRV_TYPE_SOUND, //!< Audio
- DRV_TYPE_MOUSE, //!< Mouse
- DRV_TYPE_JOYSTICK //!< Joystick / Gamepad
-};
-
-// === VIDEO ===
-enum eDrv_Video {
- VID_IOCTL_SETMODE = 4,
- VID_IOCTL_GETMODE,
- VID_IOCTL_FINDMODE,
- VID_IOCTL_MODEINFO,
- VID_IOCTL_REQLFB // Request LFB
-};\r
-struct sVideo_IOCtl_Mode {\r
- short id;\r
- Uint16 width;\r
- Uint16 height;\r
- Uint16 bpp;\r
-};\r
-typedef struct sVideo_IOCtl_Mode tVideo_IOCtl_Mode; //!< Mode Type
-
-// === MOUSE ===
-enum eDrv_Mouse {\r
- MSE_IOCTL_SENS = 4,\r
- MSE_IOCTL_MAX_X,\r
- MSE_IOCTL_MAX_Y\r
-};
-
-#endif
+++ /dev/null
-/*
- * Acess2 C Library
- *
- * sys/sockets.h
- * - POSIX Sockets
- *
- * By John Hodge (thePowersGang)
- */
-#ifndef _SYS_SOCKETS_H_
-#define _SYS_SOCKETS_H_
-
-typedef int socklen_t;
-
-typedef enum
-{
- AF_UNSPEC = 0,
- AF_INET = 4,
- AF_INET6 = 6
-} sa_family_t;
-
-struct sockaddr
-{
- sa_family_t sa_family;
- char sa_data[16];
-};
-
-/**
- * \brief Values for \a domain of socket()
- */
-enum eSocketDomains
-{
- PF_LOCAL, //!< Machine-local comms
- PF_INET, //!< IPv4
- PF_INET6, //!< IPv6
- PF_PACKET //!< Low level packet interface
-};
-#define PF_UNIX PF_LOCAL
-
-enum eSocketTypes
-{
- SOCK_STREAM, //!< Stream (TCP)
- SOCK_DGRAM, //!< Datagram (UDP)
- SOCK_SEQPACKET, //!<
- SOCK_RAW, //!< Raw packet access
- SOCK_RDM //!< Reliable non-ordered datagrams
-};
-
-/**
- * \brief Create a new socket descriptor
- * \param domain Address family
- */
-extern int socket(int domain, int type, int protocol);
-
-/**
- * \brief Bind a socket to an address
- */
-extern int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
-/**
- * \brief Connect to another socket
- */
-extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
-
-/**
- * \brief Listen for incoming connections
- */
-extern int listen(int sockfd, int backlog);
-
-/**
- * \brief Accept an incoming connection
- */
-extern int accept(int sockfd, struct sockaddr *clientaddr, socklen_t addrlen);
-
-#endif
-
+++ /dev/null
-/*
- * Acess2 C Library
- * - By John Hodge (thePowersGang)
- */
-#ifndef _SYS_STAT_H_
-#define _SYS_STAT_H_
-
-#include "../acess/intdefs.h" /* Evil */
-#include "../stddef.h"
-
-;
-typedef void *dev_t; /* TODO: How to identify a device with Acess */
-typedef __uint64_t ino_t;
-typedef unsigned int blksize_t;
-typedef __uint64_t blkcnt_t;
-typedef unsigned int nlink_t;
-typedef __uint32_t mode_t;
-
-typedef __uint32_t uid_t;
-typedef __uint32_t gid_t;
-
-#define S_IFMT 0170000 /* type of file */
-#define S_IFDIR 0040000 /* directory */
-#define S_IFCHR 0020000 /* character special */
-#define S_IFBLK 0060000 /* block special */
-#define S_IFREG 0100000 /* regular */
-#define S_IFLNK 0120000 /* symbolic link */
-#define S_IFSOCK 0140000 /* socket */
-#define S_IFIFO 0010000 /* fifo */
-
-
-struct stat
-{
- dev_t st_dev; /* ID of device containing file */
- ino_t st_ino; /* inode number */
- mode_t st_mode; /* protection */
- nlink_t st_nlink; /* number of hard links */
- uid_t st_uid; /* user ID of owner */
- gid_t st_gid; /* group ID of owner */
- dev_t st_rdev; /* device ID (if special file) */
- off_t st_size; /* total size, in bytes */
- blksize_t st_blksize; /* blocksize for file system I/O */
- blkcnt_t st_blocks; /* number of 512B blocks allocated */
- time_t st_atime; /* time of last access */
- time_t st_mtime; /* time of last modification */
- time_t st_ctime; /* time of last status change */
-};
-
-extern int stat(const char *path, struct stat *buf);
-extern int fstat(int fd, struct stat *buf);
-
-#endif
+++ /dev/null
-/*\r
- Syscall Definitions\r
-*/\r
-#ifndef _SYS_SYS_H_\r
-#define _SYS_SYS_H_\r
-\r
-#include <acess/sys.h>\r
-\r
-#include <sys/types.h>\r
-\r
-#define O_RDONLY OPENFLAG_READ\r
-#define O_WRONLY OPENFLAG_WRITE\r
-#define O_CREAT (OPENFLAG_CREATE|OPENFLAG_WRITE)\r
-#define O_TRUNC OPENFLAG_WRITE\r
-#define O_APPEND OPENFLAG_WRITE\r
-\r
-\r
-#if 0\r
-#define OPEN_FLAG_READ 1\r
-#define OPEN_FLAG_WRITE 2\r
-#define OPEN_FLAG_EXEC 4\r
-\r
-enum {\r
- K_WAITPID_DIE = 0\r
-};\r
-\r
-// === System Calls ===\r
-extern void _exit(int ret);\r
-extern int brk(int bssend);\r
-extern int execve(char *file, char *args[], char *envp[]);\r
-extern int fork();\r
-extern int yield();\r
-extern int sleep();\r
-\r
-extern int open(char *file, int flags);\r
-extern int close(int fp);\r
-extern int read(int fp, int len, void *buf);\r
-extern int write(int fp, int len, void *buf);\r
-extern int tell(int fp);\r
-extern void seek(int fp, int64_t dist, int flag);\r
-extern int fstat(int fp, t_fstat *st);\r
-extern int ioctl(int fp, int call, void *arg);\r
-extern int readdir(int fp, char *file);\r
-\r
-extern int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *errfds, time_t *timeout);\r
-\r
-extern int kdebug(char *fmt, ...);\r
-extern int waitpid(int pid, int action);\r
-extern int gettid(); // Get Thread ID\r
-extern int getpid(); // Get Process ID\r
-extern int sendmsg(int dest, unsigned int *Data);\r
-extern int pollmsg(int *src, unsigned int *Data);\r
-extern int getmsg(int *src, unsigned int *Data);\r
-#endif\r
-\r
-#endif\r
+++ /dev/null
-/*
- */
-#ifndef _SYS_TYPES_H
-#define _SYS_TYPES_H
-
-#include "../acess/intdefs.h"
-
-typedef struct stat t_fstat;
-
-#define FD_SETSIZE 128
-
-
-#define CLONE_VM 0x10
-
-typedef unsigned long pid_t;
-typedef unsigned long tid_t;
-typedef signed long long int time_t;
-typedef long long int off_t;
-
-typedef unsigned int uint;
-
-typedef unsigned short fd_set_ent_t;
-
-/**
- * \brief fd_set for select()
- */
-typedef struct
-{
- fd_set_ent_t flags[FD_SETSIZE/16];
-} fd_set;
-
-struct s_sysACL {
- unsigned long object; /*!< Group or user (bit 31 determines) */
- unsigned long perms; /*!< Inverted by bit 31 */
-};
-struct s_sysFInfo {
- unsigned int mount;
- unsigned long long inode;
- unsigned int uid;
- unsigned int gid;
- unsigned int flags;
- unsigned long long size;
- time_t atime;
- time_t mtime;
- time_t ctime;
- int numacls;
- struct s_sysACL acls[];
-} __attribute__((packed));
-typedef struct s_sysFInfo t_sysFInfo;
-typedef struct s_sysACL t_sysACL;
-
-extern void FD_ZERO(fd_set *fdsetp);
-extern void FD_CLR(int fd, fd_set *fdsetp);
-extern void FD_SET(int fd, fd_set *fdsetp);
-extern int FD_ISSET(int fd, fd_set *fdsetp);
-
-typedef __uint8_t u_int8_t;
-typedef __uint16_t u_int16_t;
-typedef __uint32_t u_int32_t;
-
-#include "../sys/stat.h"
-
-#endif
+++ /dev/null
-/*
- * Acess2 C Library
- * - By John Hodge (thePowersGang)
- *
- * time.h
- * - POSIX time functions
- */
-#ifndef _TIME_H_
-#define _TIME_H_
-
-#include <acess/intdefs.h>
-#include <sys/types.h> // time_t
-
-struct tm
-{
- int tm_sec;
- int tm_min;
- int tm_hour;
- int tm_mday;
- int tm_mon;
- int tm_year; // 1900 based
- int tm_wday;
- int tm_yday;
- int tm_isdst;
-};
-
-#define CLOCKS_PER_SEC 1000
-
-typedef signed long long clock_t;
-
-extern clock_t clock();
-
-#endif
-
+++ /dev/null
-#ifndef _UNISTD_H_
-#define _UNISTD_H_
-
-#define O_RDWR (OPENFLAG_READ|OPENFLAG_WRITE)
-
-#include "acess/sys.h"
-
-
-#endif
-
+++ /dev/null
-/*
- * Acess2 - URI Parser and opener
- * By John Hodge (thePowersGang)
- */
-#ifndef _LIB_URI_H_
-#define _LIB_URI_H_
-
-typedef struct sURI tURI;
-typedef struct sURIFile tURIFile;
-typedef struct sURIHandler tURIHandler;
-
-enum eURIModes
-{
- URI_MODE_READ = 0x01,
- URI_MODE_WRITE = 0x02
-};
-
-struct sURI
-{
- char *Proto;
- char *Host;
- char *PortStr;
- int PortNum;
- char *Path;
-};
-
-struct sURIHandler
-{
- char *Name;
- int BlockSize;
-
- int (*Open)(char *Host, int Port, char *Path, int Flags);
- void (*Close)(int Handle);
- size_t (*Read)(int Handle, size_t Bytes, void *Buffer);
- size_t (*Write)(int Handle, size_t Bytes, void *Buffer);
- size_t (*GetSize)(int Handle);
-};
-
-// === FUNCTIONS ===
-extern tURI *URI_Parse(const char *String);
-extern tURIFile *URI_Open(int Mode, tURI *URI);
-extern int URI_GetSize(tURIFile *File, size_t *Size);
-extern size_t URI_Read(tURIFile *File, size_t Bytes, void *Buffer);
-extern size_t URI_Write(tURIFile *File, size_t Bytes, void *Buffer);
-extern void URI_Close(tURIFile *File);
-
-#endif