diff --git a/Makefile b/Makefile index 18dcef2e2..83949c350 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ JAVAC := $(shell which javac) all: cd tools/emulator && make cd tools/serial_boot && make + cd tools/mkfs && make cd rtl/ && make cd software/libs/libc && make cd software/libs/librender && make @@ -36,6 +37,7 @@ test: all FORCE clean: cd tools/emulator && make clean cd tools/serial_boot && make clean + cd tools/mkfs && make clean cd software/libs/libc && make clean cd software/libs/librender && make clean cd software/libs/libos && make clean diff --git a/software/apps/doom/Makefile b/software/apps/doom/Makefile index a65205c4b..1b00b0eea 100644 --- a/software/apps/doom/Makefile +++ b/software/apps/doom/Makefile @@ -94,19 +94,22 @@ $(O)/doom.hex: $(OBJS) $(ELF2HEX) -o $(O)/doom.hex -b 0 $(O)/doom.elf $(OBJDUMP) --disassemble $(O)/doom.elf > doom.lst 2> /dev/null -run: $(O) $(O)/doom.hex - ../../../bin/emulator -f 640x400 -b doom1.wad obj/doom.hex +run: $(O) $(O)/doom.hex fsimage.bin + ../../../bin/emulator -f 640x400 -b fsimage.bin obj/doom.hex -debug: $(O) $(O)/doom.hex - ../../../bin/emulator -m gdb -f 640x400 -b doom1.wad obj/doom.hex & +debug: $(O) $(O)/doom.hex fsimage.bin + ../../../bin/emulator -m gdb -f 640x400 -b fsimage.bin obj/doom.hex & /usr/local/llvm-nyuzi/bin/lldb --arch nyuzi $(O)/doom.elf -o "gdb-remote 8000" -verirun: $(O) $(O)/doom.hex - ../../../bin/verilator_model +bin=obj/doom.hex +block=doom1.wad +verirun: $(O) $(O)/doom.hex fsimage.bin + ../../../bin/verilator_model +bin=obj/doom.hex +block=fsimage.bin fpgarun: $(O)/doom.hex ../../../bin/serial_boot $(SERIAL_PORT) $(O)/doom.hex +fsimage.bin: doom1.wad + ../../../bin/mkfs fsimage.bin DOOM1.WAD + $(O)/%.o: %.c $(CC) $(CFLAGS) -c $< -o $@ diff --git a/software/apps/doom/README.md b/software/apps/doom/README.md index 48251da2b..134145351 100644 --- a/software/apps/doom/README.md +++ b/software/apps/doom/README.md @@ -6,22 +6,16 @@ compiled to 300k). A shareware WAD file is required to use this. This is not included in this repository, but can be found pretty easily with a Google search. It should be -named "doom1.wad" and placed in this directory. +named "DOOM1.WAD" (case sensitive) and placed in this directory. To run (in the emulator) type 'make run'. This does not currently run on FPGA because there isn't a mass storage device to store the WAD. The primary changes I made for the port were: -* In w_wad.c, read the WAD file directly from a simulated block device. Since -this is running on bare metal with a minimal libc, there is no filesystem layer. -I commented out other code that interacted with the filesystem (for example, -saving and restoring games). The size of the WAD file is hardcoded in this file. * in i_video.c, added code to copy the screen to the framebuffer, expanding from an 8 bit paletted format to the 32 bit per pixel framebuffer format. * in i_video.c, reads from a virtual keyboard device for input. -* Fixed some places that made bad assumptions that the hardware supported -unaligned memory accesses. -* Code from i_net and i_sound mostly removed, since there's no support for -them. +* W_CheckNumForName assumes support for unaligned accesses, changed to use memcmp. +* Code from i_net and i_sound removed, since there's no support for them. diff --git a/software/apps/doom/w_wad.c b/software/apps/doom/w_wad.c index af4a25174..549b09ddc 100644 --- a/software/apps/doom/w_wad.c +++ b/software/apps/doom/w_wad.c @@ -1,4 +1,4 @@ -// Emacs style mode select -*- C++ -*- +// Emacs style mode select -*- C++ -*- //----------------------------------------------------------------------------- // // $Id:$ @@ -25,16 +25,15 @@ static const char rcsid[] = "$Id: w_wad.c,v 1.5 1997/02/03 16:47:57 b1 Exp $"; - -#ifdef NORMALUNIX +#include +#include +#include #define O_BINARY 0 -#endif #include "doomtype.h" #include "m_swap.h" #include "i_system.h" #include "z_zone.h" -#include "sdmmc.h" #ifdef __GNUG__ #pragma implementation "w_wad.h" @@ -43,6 +42,9 @@ rcsid[] = "$Id: w_wad.c,v 1.5 1997/02/03 16:47:57 b1 Exp $"; + + + // // GLOBALS // @@ -51,9 +53,10 @@ rcsid[] = "$Id: w_wad.c,v 1.5 1997/02/03 16:47:57 b1 Exp $"; lumpinfo_t* lumpinfo; int numlumps; -void** lumpcache; +void** lumpcache; -#define strcmpi strcasecmp + +#define strcmpi strcasecmp void strupr (char* s) { @@ -62,63 +65,22 @@ void strupr (char* s) int filelength (int handle) { -#if 0 - struct stat fileinfo; + struct stat fileinfo; if (fstat (handle,&fileinfo) == -1) I_Error ("Error fstating"); return fileinfo.st_size; -#endif } -#define WAD_SIZE 4196020 - -static volatile unsigned int * const REGISTERS = (volatile unsigned int*) 0xffff0000; -static char currentBlock[BLOCK_SIZE]; -static int currentBlockOffset = -1; -static int initializedBlockDevice = 0; - -void readFromBlockDevice(unsigned int offset, void *ptr, int length) -{ - int sliceLength; - char *out = ptr; - int offsetInBlock = offset & (BLOCK_SIZE - 1); - int blockBase = offset - offsetInBlock; - - if (!initializedBlockDevice) - { - if (initSdmmcDevice() < 0) - { - printf("Error initializing sdmmc\n"); - exit(1); - } - - initializedBlockDevice = 1; - } - - while (length > 0) - { - sliceLength = BLOCK_SIZE - offsetInBlock; - if (sliceLength > length) - sliceLength = length; - - readSdmmcDevice(blockBase / BLOCK_SIZE, currentBlock); - memcpy(out, currentBlock + offsetInBlock, sliceLength); - out += sliceLength; - length -= sliceLength; - offsetInBlock = 0; - blockBase += BLOCK_SIZE; - } -} void ExtractFileBase -( char* path, - char* dest ) +( char* path, + char* dest ) { char* src; - int length; + int length; src = path + strlen(path) - 1; @@ -154,31 +116,31 @@ ExtractFileBase // // W_AddFile // All files are optional, but at least one file must be -// found (PWAD, if all required lumps are present). +// found (PWAD, if all required lumps are present). // Files with a .wad extension are wadlink files -// with multiple lumps. +// with multiple lumps. // Other files are single lumps with the base filename -// for the lump name. +// for the lump name. // // If filename starts with a tilde, the file is handled -// specially to allow map reloads. +// specially to allow map reloads. // But: the reload feature is a fragile hack... int reloadlump; -char* reloadname; +char* reloadname; void W_AddFile (char *filename) { - wadinfo_t header; - lumpinfo_t* lump_p; - unsigned i; - int handle; - int length; - int startlump; - filelump_t* fileinfo; - filelump_t singleinfo; - int storehandle; + wadinfo_t header; + lumpinfo_t* lump_p; + unsigned i; + int handle; + int length; + int startlump; + filelump_t* fileinfo; + filelump_t singleinfo; + int storehandle; // open the file and add to directory @@ -190,16 +152,12 @@ void W_AddFile (char *filename) reloadlump = numlumps; } - printf("W_AddFile(%s)\n", filename); - -#if 0 if ( (handle = open (filename,O_RDONLY | O_BINARY)) == -1) { printf (" couldn't open %s\n",filename); return; } -#endif - + printf (" adding %s\n",filename); startlump = numlumps; @@ -215,36 +173,27 @@ void W_AddFile (char *filename) else { // WAD file -#if 0 read (handle, &header, sizeof(header)); -#else - readFromBlockDevice(0, &header, sizeof(header)); -#endif - if (memcmp(header.identification,"IWAD",4)) + if (strncmp(header.identification,"IWAD",4)) { // Homebrew levels? - if (memcmp(header.identification,"PWAD",4)) + if (strncmp(header.identification,"PWAD",4)) { I_Error ("Wad file %s doesn't have IWAD " "or PWAD id\n", filename); } - // ???modifiedgame = true; + // ???modifiedgame = true; } header.numlumps = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = header.numlumps*sizeof(filelump_t); - fileinfo = alloca (length); -#if 0 lseek (handle, header.infotableofs, SEEK_SET); read (handle, fileinfo, length); -#else - readFromBlockDevice(header.infotableofs, fileinfo, length); -#endif - numlumps += header.numlumps; } + // Fill in lumpinfo lumpinfo = realloc (lumpinfo, numlumps*sizeof(lumpinfo_t)); @@ -263,11 +212,9 @@ void W_AddFile (char *filename) lump_p->size = LONG(fileinfo->size); strncpy (lump_p->name, fileinfo->name, 8); } - -#if 0 + if (reloadname) close (handle); -#endif } @@ -276,43 +223,32 @@ void W_AddFile (char *filename) // // W_Reload // Flushes any of the reloadable lumps in memory -// and reloads the directory. +// and reloads the directory. // void W_Reload (void) { - wadinfo_t header; - int lumpcount; - lumpinfo_t* lump_p; - unsigned i; - int handle; - int length; - filelump_t* fileinfo; - - printf("W_Reload()\n"); - + wadinfo_t header; + int lumpcount; + lumpinfo_t* lump_p; + unsigned i; + int handle; + int length; + filelump_t* fileinfo; + if (!reloadname) return; -#if 0 if ( (handle = open (reloadname,O_RDONLY | O_BINARY)) == -1) I_Error ("W_Reload: couldn't open %s",reloadname); read (handle, &header, sizeof(header)); -#else - readFromBlockDevice(0, &header, sizeof(header)); -#endif - lumpcount = LONG(header.numlumps); header.infotableofs = LONG(header.infotableofs); length = lumpcount*sizeof(filelump_t); fileinfo = alloca (length); -#if 0 lseek (handle, header.infotableofs, SEEK_SET); read (handle, fileinfo, length); -#else - readFromBlockDevice(header.infotableofs, fileinfo, length); -#endif - + // Fill in lumpinfo lump_p = &lumpinfo[reloadlump]; @@ -326,10 +262,8 @@ void W_Reload (void) lump_p->position = LONG(fileinfo->filepos); lump_p->size = LONG(fileinfo->size); } - -#if 0 + close (handle); -#endif } @@ -338,18 +272,18 @@ void W_Reload (void) // W_InitMultipleFiles // Pass a null terminated list of files to use. // All files are optional, but at least one file -// must be found. +// must be found. // Files with a .wad extension are idlink files -// with multiple lumps. +// with multiple lumps. // Other files are single lumps with the base filename -// for the lump name. +// for the lump name. // Lump names can appear multiple times. // The name searcher looks backwards, so a later file -// does override all earlier ones. +// does override all earlier ones. // void W_InitMultipleFiles (char** filenames) { - int size; + int size; // open all the files, load headers, and count lumps numlumps = 0; @@ -401,55 +335,60 @@ int W_NumLumps (void) +// +// W_CheckNumForName +// Returns -1 if name not found. +// -int W_CheckNumForName (char* name) -{ -#if 0 - union { - char s[9]; - int x[2]; + int W_CheckNumForName (char* name) + { + #if 0 + // XXX jeff: this assumes support for unaligned accesses + union { + char s[9]; + int x[2]; + + } name8; - } name8; - - int v1; - int v2; - lumpinfo_t* lump_p; + int v1; + int v2; + lumpinfo_t* lump_p; - // make the name into two integers for easy compares - strncpy (name8.s,name,8); + // make the name into two integers for easy compares + strncpy (name8.s,name,8); - // in case the name was a fill 8 chars - name8.s[8] = 0; + // in case the name was a fill 8 chars + name8.s[8] = 0; - // case insensitive - strupr (name8.s); + // case insensitive + strupr (name8.s); - v1 = name8.x[0]; - v2 = name8.x[1]; + v1 = name8.x[0]; + v2 = name8.x[1]; - // scan backwards so patch lump files take precedence - lump_p = lumpinfo + numlumps; + // scan backwards so patch lump files take precedence + lump_p = lumpinfo + numlumps; - while (lump_p-- != lumpinfo) - { - if ( *(int *)lump_p->name == v1 - && *(int *)&lump_p->name[4] == v2) - { - return lump_p - lumpinfo; - } - } -#else - int i; - for (i = 0; i < numlumps; i++) - if (strncasecmp(lumpinfo[i].name, name, 8) == 0) - return i; + while (lump_p-- != lumpinfo) + { + if ( *(int *)lump_p->name == v1 + && *(int *)&lump_p->name[4] == v2) + { + return lump_p - lumpinfo; + } + } + #else + int i; + for (i = 0; i < numlumps; i++) + if (strncasecmp(lumpinfo[i].name, name, 8) == 0) + return i; - return -1; -#endif + return -1; + #endif - // TFB. Not found. - return -1; -} + // TFB. Not found. + return -1; + } @@ -460,7 +399,7 @@ int W_CheckNumForName (char* name) // int W_GetNumForName (char* name) { - int i; + int i; i = W_CheckNumForName (name); @@ -488,23 +427,22 @@ int W_LumpLength (int lump) // // W_ReadLump // Loads the lump into the given buffer, -// which must be >= W_LumpLength(). +// which must be >= W_LumpLength(). // void W_ReadLump -( int lump, - void* dest ) +( int lump, + void* dest ) { - int c; - lumpinfo_t* l; - int handle; + int c; + lumpinfo_t* l; + int handle; if (lump >= numlumps) I_Error ("W_ReadLump: %i >= numlumps",lump); l = lumpinfo+lump; -#if 0 // ??? I_BeginRead (); if (l->handle == -1) @@ -527,9 +465,6 @@ W_ReadLump close (handle); // ??? I_EndRead (); -#else - readFromBlockDevice(l->position, dest, l->size); -#endif } @@ -540,8 +475,8 @@ W_ReadLump // void* W_CacheLumpNum -( int lump, - int tag ) +( int lump, + int tag ) { byte* ptr; @@ -572,8 +507,8 @@ W_CacheLumpNum // void* W_CacheLumpName -( char* name, - int tag ) +( char* name, + int tag ) { return W_CacheLumpNum (W_GetNumForName(name), tag); } @@ -582,10 +517,62 @@ W_CacheLumpName // // W_Profile // +int info[2500][10]; +int profilecount; void W_Profile (void) { + int i; + memblock_t* block; + void* ptr; + char ch; + FILE* f; + int j; + char name[9]; + + + for (i=0 ; itag < PU_PURGELEVEL) + ch = 'S'; + else + ch = 'P'; + } + info[i][profilecount] = ch; + } + profilecount++; + + f = fopen ("waddump.txt","w"); + name[8] = 0; + + for (i=0 ; i #include "DepthShader.h" #include "schedule.h" -#include "sdmmc.h" #include "TextureShader.h" //#define TEST_TEXTURE 1 @@ -55,22 +54,35 @@ const int kAttrsPerVertex = 8; char *readResourceFile() { - char tmp[BLOCK_SIZE]; - unsigned int fileSize; + FileHeader header; char *resourceData; + FILE *fp; - initSdmmcDevice(); + fp = fopen("resource.bin", "rb"); + if (fp == nullptr) + { + printf("can't find resource.bin\n"); + return nullptr; + } // Read the first block to determine how large the rest of the file is. - readSdmmcDevice(0, tmp); - fileSize = ((FileHeader*) tmp)->fileSize; - - printf("reading resource file, %d bytes\n", fileSize); + if (fread(&header, sizeof(header), 1, fp) != 1) + { + printf("error reading resource file header\n"); + return nullptr; + } + + printf("reading resource file, %d bytes\n", header.fileSize); + + resourceData = (char*) malloc(header.fileSize); + fseek(fp, 0, SEEK_SET); + if (fread(resourceData, header.fileSize, 1, fp) != 1) + { + printf("error reading resource file\n"); + return nullptr; + } - resourceData = (char*) malloc(fileSize + BLOCK_SIZE); - memcpy(resourceData, tmp, BLOCK_SIZE); - for (int i = 1, len=(fileSize + BLOCK_SIZE - 1) / BLOCK_SIZE; i < len; i++) - readSdmmcDevice(i, resourceData + i * BLOCK_SIZE); + fclose(fp); return resourceData; } diff --git a/software/libs/libc/include/stdio.h b/software/libs/libc/include/stdio.h index 7bc449edb..934b6eeb7 100644 --- a/software/libs/libc/include/stdio.h +++ b/software/libs/libc/include/stdio.h @@ -27,6 +27,7 @@ #define SEEK_END 2 typedef struct __file FILE; +typedef int off_t; extern FILE *stdout; extern FILE *stdin; @@ -49,6 +50,7 @@ FILE *fopen(const char *filename, const char *mode); size_t fread(void *ptr, size_t size, size_t nelem, FILE *stream); size_t fwrite(const void *ptr, size_t size, size_t nelem, FILE *stream); int fclose(FILE *stream); +off_t fseek(FILE *stream, off_t offset, int whence); #ifdef __cplusplus } diff --git a/software/libs/libc/include/string.h b/software/libs/libc/include/string.h index 7945b8380..aa1a25ac0 100644 --- a/software/libs/libc/include/string.h +++ b/software/libs/libc/include/string.h @@ -29,6 +29,7 @@ int strcmp(const char *str1, const char *str2); int memcmp(const void *a, const void *b, size_t length); int strcasecmp(const char *str1, const char *str2); int strncasecmp(const char *str1, const char *str2, size_t length); +int strncmp(const char *str1, const char *str2, size_t len); size_t strlen(const char *str); char* strcpy(char *dest, const char *src); char* strncpy(char *dest, const char *src, size_t length); diff --git a/software/libs/libc/src/__stdio_internal.h b/software/libs/libc/src/__stdio_internal.h index 9f3b13d1a..0a18d92ba 100644 --- a/software/libs/libc/src/__stdio_internal.h +++ b/software/libs/libc/src/__stdio_internal.h @@ -24,6 +24,7 @@ struct __file char *write_buf; int write_offset; int write_buf_len; + int fd; }; #endif diff --git a/software/libs/libc/src/stdio.c b/software/libs/libc/src/stdio.c index c81fda9d0..533cccadf 100644 --- a/software/libs/libc/src/stdio.c +++ b/software/libs/libc/src/stdio.c @@ -366,8 +366,13 @@ void fputc(int ch, FILE *file) { if (file == stdout) writeUart(ch); - else if (file->write_offset < file->write_buf_len) - file->write_buf[file->write_offset++] = ch; + else if (file->write_buf) + { + if (file->write_offset < file->write_buf_len) + file->write_buf[file->write_offset++] = ch; + } + else + write(file->fd, &ch, 1); } void fputs(const char *str, FILE *file) @@ -378,8 +383,10 @@ void fputs(const char *str, FILE *file) FILE *fopen(const char *filename, const char *mode) { - // XXX implement me - return NULL; + FILE *fptr = (FILE*) malloc(sizeof(FILE)); + fptr->write_buf = 0; + fptr->fd = open(filename, 0); + return fptr; } size_t fwrite(const void *ptr, size_t size, size_t count, FILE *file) @@ -394,16 +401,23 @@ size_t fwrite(const void *ptr, size_t size, size_t count, FILE *file) size_t fread(void *ptr, size_t size, size_t nelem, FILE *stream) { - // XXX implement me - return 0; + int got = read(stream->fd, ptr, size * nelem); + if (got < 0) + return 0; + + return got / size; } int fclose(FILE *stream) { - // XXX implement me - return -1; + close(stream->fd); + free(stream); } +off_t fseek(FILE *stream, off_t offset, int whence) +{ + return lseek(stream->fd, offset, whence); +} int fprintf(FILE *f, const char *fmt, ...) { diff --git a/software/libs/libc/src/string.c b/software/libs/libc/src/string.c index da381af74..14a5dcb55 100644 --- a/software/libs/libc/src/string.c +++ b/software/libs/libc/src/string.c @@ -72,6 +72,20 @@ int strcmp(const char *str1, const char *str2) return *str1 - *str2; } +int strncmp(const char *str1, const char *str2, size_t length) +{ + if (length-- == 0) + return 0; + + while (*str1 && *str2 && length && *str1 == *str2) + { + str1++; + str2++; + length--; + } + + return *str1 - *str2; +} int memcmp(const void *_str1, const void *_str2, size_t len) { const char *str1 = _str1; diff --git a/software/libs/libos/Makefile b/software/libs/libos/Makefile index 004165d3e..4dd2dec67 100644 --- a/software/libs/libos/Makefile +++ b/software/libs/libos/Makefile @@ -24,7 +24,8 @@ CFLAGS=-g -Wall -W -O3 -I../libc/include SRCS=schedule.c \ sdmmc.c \ - uart.c + uart.c \ + fs.c OBJS := $(addprefix $(WORKDIR),$(notdir $(patsubst %.c,%.o,$(filter %.c,$(SRCS))))) \ $(addprefix $(WORKDIR),$(notdir $(patsubst %.s,%.o,$(filter %.s,$(SRCS))))) \ diff --git a/software/libs/libos/fs.c b/software/libs/libos/fs.c new file mode 100644 index 000000000..77e8f6d42 --- /dev/null +++ b/software/libs/libos/fs.c @@ -0,0 +1,256 @@ +// +// Copyright 2015 Jeff Bush +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// +// This module exposes the standard filesystem calls read/write/open/close/lseek. +// It uses a very simple read-only filesystem format that is created by +// tools/mkfs. It reads the raw data from the sdmmc driver. +// + +#include +#include +#include "sdmmc.h" +#include "unistd.h" + +#define FS_MAGIC 'spfs' +#define MAX_DESCRIPTORS 32 + +typedef struct FileDescriptor FileDescriptor; +typedef struct DirectoryEntry DirectoryEntry; +typedef struct FsHeader FsHeader; + +struct FileDescriptor +{ + int isOpen; + int fileLength; + int startOffset; + int currentOffset; +}; + +struct DirectoryEntry +{ + unsigned int startOffset; + unsigned int length; + char name[32]; +}; + +struct FsHeader +{ + int magic; + int numDirectoryEntries; + DirectoryEntry dir[1]; +}; + +static FileDescriptor gFileDescriptors[MAX_DESCRIPTORS]; +static int gInitialized; +static FsHeader *gDirectory; + +static int initFileSystem() +{ + char superBlock[BLOCK_SIZE]; + int numDirectoryBlocks; + int blockNum; + FsHeader *header; + + initSdmmcDevice(); + + // Read directory + if (!readSdmmcDevice(0, superBlock)) + return -1; + + header = (FsHeader*) superBlock; + if (header->magic != FS_MAGIC) + { + printf("bad magic on header\n"); + return -1; + } + + numDirectoryBlocks = ((header->numDirectoryEntries - 1) * sizeof(DirectoryEntry) + + sizeof(FsHeader) + BLOCK_SIZE - 1) / BLOCK_SIZE; + gDirectory = (FsHeader*) malloc(numDirectoryBlocks * BLOCK_SIZE); + memcpy(gDirectory, superBlock, BLOCK_SIZE); + for (blockNum = 1; blockNum < numDirectoryBlocks; blockNum++) + readSdmmcDevice(blockNum, ((char*)gDirectory) + BLOCK_SIZE * blockNum); + + return 0; +} + +int open(const char *path, int mode) +{ + int fd; + struct FileDescriptor *fdPtr; + int directoryIndex; + + (void) mode; // mode is ignored + + if (!gInitialized) + { + if (initFileSystem() < 0) + return -1; + + gInitialized = 1; + } + + for (fd = 0; fd < MAX_DESCRIPTORS; fd++) + { + if (!gFileDescriptors[fd].isOpen) + break; + } + + if (fd == MAX_DESCRIPTORS) + return -1; // Too many files open + + fdPtr = &gFileDescriptors[fd]; + + // Search for file + for (directoryIndex = 0; directoryIndex < gDirectory->numDirectoryEntries; directoryIndex++) + { + DirectoryEntry *entry = gDirectory->dir + directoryIndex; + if (strcmp(entry->name, path) == 0) + { + fdPtr->isOpen = 1; + fdPtr->fileLength = entry->length; + fdPtr->startOffset = entry->startOffset; + fdPtr->currentOffset = 0; + return fd; + } + } + + return -1; +} + +int close(int fd) +{ + if (fd < 0 || fd >= MAX_DESCRIPTORS) + return -1; + + gFileDescriptors[fd].isOpen = 0; + return 0; +} + +int read(int fd, void *buf, unsigned int nbytes) +{ + int sizeToCopy; + struct FileDescriptor *fdPtr; + int sliceLength; + int totalRead; + char currentBlock[BLOCK_SIZE]; + int offsetInBlock; + int blockNumber; + + if (fd < 0 || fd >= MAX_DESCRIPTORS) + return -1; + + fdPtr = &gFileDescriptors[fd]; + if (!fdPtr->isOpen) + return -1; + + sizeToCopy = fdPtr->fileLength - fdPtr->currentOffset; + if (sizeToCopy < 0) + return 0; // Past end of file + + if (nbytes > sizeToCopy) + nbytes = sizeToCopy; + + offsetInBlock = fdPtr->currentOffset & (BLOCK_SIZE - 1); + blockNumber = (fdPtr->startOffset + fdPtr->currentOffset) / BLOCK_SIZE; + + totalRead = 0; + while (totalRead < nbytes) + { + readSdmmcDevice(blockNumber, currentBlock); + sliceLength = BLOCK_SIZE - offsetInBlock; + if (sliceLength > nbytes - totalRead) + sliceLength = nbytes - totalRead; + + memcpy((char*) buf + totalRead, currentBlock + offsetInBlock, sliceLength); + totalRead += sliceLength; + offsetInBlock = 0; + blockNumber++; + } + + fdPtr->currentOffset += nbytes; + + return nbytes; +} + +int write(int fd, const void *buf, unsigned int nbyte) +{ + return -1; // Read-only filesystem +} + +off_t lseek(int fd, off_t offset, int whence) +{ + struct FileDescriptor *fdPtr; + if (fd < 0 || fd >= MAX_DESCRIPTORS) + return -1; + + fdPtr = &gFileDescriptors[fd]; + if (!fdPtr->isOpen) + return -1; + + switch (whence) + { + case SEEK_SET: + fdPtr->currentOffset = offset; + break; + + case SEEK_CUR: + fdPtr->currentOffset += offset; + break; + + case SEEK_END: + fdPtr->currentOffset = fdPtr->fileLength - offset; + break; + + default: + return -1; + } + + if (fdPtr->currentOffset < 0) + fdPtr->currentOffset = 0; +} + +int stat(const char *path, struct stat *buf) +{ + int fd = open(path, 0); + if (fd < 0) + return fd; + + fstat(fd, buf); + close(fd); + + return 0; +} + +int fstat(int fd, struct stat *buf) +{ + struct FileDescriptor *fdPtr; + if (fd < 0 || fd >= MAX_DESCRIPTORS) + return -1; + + fdPtr = &gFileDescriptors[fd]; + if (!fdPtr->isOpen) + return -1; + + buf->st_size = fdPtr->fileLength; + + return 0; +} + + + + diff --git a/software/libs/libos/unistd.h b/software/libs/libos/unistd.h new file mode 100644 index 000000000..e323e7468 --- /dev/null +++ b/software/libs/libos/unistd.h @@ -0,0 +1,52 @@ +// +// Copyright 2015 Jeff Bush +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#ifndef __UNISTD_H +#define __UNISTD_H + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define O_RDONLY 1 +#define O_BINARY 2 + +typedef int off_t; + +struct stat +{ + off_t st_size; +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int open(const char *path, int mode); +int close(int fd); +int read(int fd, void *buf, unsigned int nbyte); +int write(int fd, const void *buf, unsigned int nbyte); +off_t lseek(int fd, off_t offset, int whence); +int stat(const char *path, struct stat *buf); +int fstat(int fd, struct stat *buf); + +#ifdef __cplusplus +} +#endif + +#endif + + \ No newline at end of file diff --git a/tools/mkfs/Makefile b/tools/mkfs/Makefile new file mode 100644 index 000000000..1aed8f515 --- /dev/null +++ b/tools/mkfs/Makefile @@ -0,0 +1,43 @@ +# +# Copyright 2011-2015 Jeff Bush +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +BINDIR=../../bin +OBJDIR=OBJECTS +CFLAGS=-Wall -W -g + +SRCS=mkfs.c + +OBJS := $(SRCS:%.c=$(OBJDIR)/%.o) +DEPS := $(SRCS:%.c=$(OBJDIR)/%.d) + +$(BINDIR)/mkfs: $(OBJS) + gcc -g -o $@ $(OBJS) + +-include $(DEPS) + +$(OBJDIR)/%.o : %.c + mkdir -p $(dir $@) + gcc $(CFLAGS) -o $@ -c $< + gcc $(CFLAGS) -o $(OBJDIR)/$*.d -MM $< + +$(BINDIR): + mkdir -p $(BINDIR) + +clean: + rm -rf $(OBJDIR) + rm -f $(BINDIR)/mkfs + diff --git a/tools/mkfs/mkfs.c b/tools/mkfs/mkfs.c new file mode 100644 index 000000000..bc2ff42f0 --- /dev/null +++ b/tools/mkfs/mkfs.c @@ -0,0 +1,153 @@ +// +// Copyright 2015 Jeff Bush +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +// +// This utility creates a simple read-only filesystem that is exposed by +// software/libs/libos/fs.c +// + +#include +#include +#include +#include + +#define FS_NAME_LEN 32 +#define BLOCK_SIZE 512 +#define FS_MAGIC 'spfs' +#define ROUND_UP(x, y) (((x + y - 1) / y) * y) + +typedef struct DirectoryEntry DirectoryEntry; +typedef struct FsHeader FsHeader; + +struct DirectoryEntry +{ + unsigned int startOffset; + unsigned int length; + char name[FS_NAME_LEN]; +}; + +struct FsHeader +{ + int magic; + int numDirectoryEntries; + DirectoryEntry dir[1]; +}; + +void normalizeFileName(char outName[32], const char *fullPath) +{ + const char *end = fullPath + strlen(fullPath) - 1; + const char *begin = end; + while (begin > fullPath && begin[-1] != '/') + begin--; + + if (end - begin > FS_NAME_LEN - 1) + { + // Truncate + begin = end - (FS_NAME_LEN -1); + } + + strcpy(outName, begin); +} + +int main(int argc, const char *argv[]) +{ + int fileIndex; + unsigned fileOffset; + int numDirectoryEntries = argc - 2; + FsHeader *header; + FILE *outputFp; + int headerSize; + + if (argc < 2) + { + fprintf(stderr, "USAGE: %s [...]\n", argv[0]); + return 1; + } + + outputFp = fopen(argv[1], "wb"); + if (outputFp == NULL) + { + perror("error creating output file"); + return 1; + } + + fileOffset = ROUND_UP((numDirectoryEntries - 1) * sizeof(DirectoryEntry) + + sizeof(FsHeader), BLOCK_SIZE); + printf("first file offset = %d\n", fileOffset); + headerSize = sizeof(FsHeader) + sizeof(DirectoryEntry) * (numDirectoryEntries - 1); + header = (FsHeader*) malloc(headerSize); + + // Build the directory + for (fileIndex = 0; fileIndex < numDirectoryEntries; fileIndex++) + { + struct stat st; + + if (stat(argv[fileIndex + 2], &st) < 0) + { + fprintf(stderr, "error opening %s\n", argv[fileIndex + 2]); + return 1; + } + + header->dir[fileIndex].startOffset = fileOffset; + header->dir[fileIndex].length = st.st_size; + normalizeFileName(header->dir[fileIndex].name, argv[fileIndex + 2]); + printf("Adding %s %08x %08x\n", header->dir[fileIndex].name, header->dir[fileIndex].startOffset, + header->dir[fileIndex].length); + fileOffset = ROUND_UP(fileOffset + st.st_size, BLOCK_SIZE); + } + + header->magic = FS_MAGIC; + header->numDirectoryEntries = numDirectoryEntries; + + if (fwrite(header, headerSize, 1, outputFp) != 1) + { + perror("error writing header"); + return 1; + } + + // Copy file contents + for (fileIndex = 0; fileIndex < numDirectoryEntries; fileIndex++) + { + char tmp[0x4000]; + fseek(outputFp, header->dir[fileIndex].startOffset, SEEK_SET); + FILE *sourceFp = fopen(argv[fileIndex + 2], "rb"); + int leftToCopy = header->dir[fileIndex].length; + while (leftToCopy > 0) + { + int sliceLength = 0x4000; + if (leftToCopy < sliceLength) + sliceLength = leftToCopy; + + if (fread(tmp, sliceLength, 1, sourceFp) != 1) + { + perror("error reading from source file"); + return 1; + } + + if (fwrite(tmp, sliceLength, 1, outputFp) != 1) + { + perror("error writing to output file"); + return 1; + } + + leftToCopy -= sliceLength; + } + + fclose(sourceFp); + } + + fclose(outputFp); +}