Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / openbios / fs / grubfs / grubfs_fs.c
diff --git a/qemu/roms/openbios/fs/grubfs/grubfs_fs.c b/qemu/roms/openbios/fs/grubfs/grubfs_fs.c
new file mode 100644 (file)
index 0000000..acd2a64
--- /dev/null
@@ -0,0 +1,398 @@
+/*
+ *     /packages/grubfs-files
+ *
+ *     grub vfs
+ *
+ *   Copyright (C) 2004 Stefan Reinauer
+ *   Copyright (C) 2004 Samuel Rydh
+ *   Copyright (C) 2010 Mark Cave-Ayland
+ *
+ *   inspired by HFS code from Samuel Rydh
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation
+ *
+ */
+
+#include "config.h"
+#include "libopenbios/bindings.h"
+#include "fs/fs.h"
+#include "filesys.h"
+#include "glue.h"
+#include "libc/diskio.h"
+#include "libc/vsprintf.h"
+
+extern void     grubfs_init( void );
+
+/************************************************************************/
+/*     grub GLOBALS (horrible... but difficult to fix)                 */
+/************************************************************************/
+
+/* the grub drivers want these: */
+int            filepos;
+int            filemax;
+grub_error_t   errnum;
+char           FSYS_BUF[FSYS_BUFLEN];
+
+/* these are not even used by us, instead
+ * the grub fs drivers want them:
+ */
+int            fsmax;
+void           (*disk_read_hook) (int, int, int);
+void           (*disk_read_func) (int, int, int);
+
+
+/************************************************************************/
+/*     filsystem table                                                 */
+/************************************************************************/
+
+typedef struct fsys_entry {
+        const char *name;
+       int     (*mount_func) (void);
+       int     (*read_func) (char *buf, int len);
+       int     (*dir_func) (char *dirname);
+       void    (*close_func) (void);
+       int     (*embed_func) (int *start_sector, int needed_sectors);
+} fsys_entry_t;
+
+static const struct fsys_entry fsys_table[] = {
+# ifdef CONFIG_FSYS_FAT
+    {"fat", fat_mount, fat_read, fat_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_EXT2FS
+    {"ext2fs", ext2fs_mount, ext2fs_read, ext2fs_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_MINIX
+    {"minix", minix_mount, minix_read, minix_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_REISERFS
+    {"reiserfs", reiserfs_mount, reiserfs_read, reiserfs_dir, NULL, reiserfs_embed},
+# endif
+# ifdef CONFIG_FSYS_JFS
+    {"jfs", jfs_mount, jfs_read, jfs_dir, NULL, jfs_embed},
+# endif
+# ifdef CONFIG_FSYS_XFS
+    {"xfs", xfs_mount, xfs_read, xfs_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_UFS
+    {"ufs", ufs_mount, ufs_read, ufs_dir, NULL, ufs_embed},
+# endif
+# ifdef CONFIG_FSYS_ISO9660
+    {"iso9660", iso9660_mount, iso9660_read, iso9660_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_NTFS
+    {"ntfs", ntfs_mount, ntfs_read, ntfs_dir, NULL, NULL},
+# endif
+# ifdef CONFIG_FSYS_AFFS
+    {"affs", affs_mount, affs_read, affs_dir, NULL, NULL},
+# endif
+};
+
+/* We don't provide a file search mechanism (yet) */
+typedef struct {
+       unsigned long   pos;
+       unsigned long   len;
+       const char      *path;
+} grubfile_t;
+
+typedef struct {
+       const struct fsys_entry *fsys;
+       grubfile_t *fd;
+       int dev_fd;
+       long long offset;       /* Offset added onto each device read; should only ever be non-zero
+                               when probing a partition for a filesystem */
+} grubfs_t;
+
+typedef struct {
+       grubfs_t *gfs;
+} grubfs_info_t;
+
+/* Static block and global pointer required for I/O glue */
+static grubfs_t dummy_fs;
+static grubfs_t *curfs = &dummy_fs;
+
+DECLARE_NODE( grubfs, 0, sizeof(grubfs_info_t), "+/packages/grubfs-files" );
+
+
+/************************************************************************/
+/*     I/O glue (called by grub source)                                */
+/************************************************************************/
+
+int
+devread( unsigned long sector, unsigned long byte_offset,
+        unsigned long byte_len, void *buf )
+{
+       long long offs = (long long)sector * 512 + byte_offset;
+
+#ifdef CONFIG_DEBUG_FS
+       //printk("devread s=%x buf=%x, fd=%x\n",sector, buf, curfs->dev_fd);
+#endif
+
+       if( !curfs ) {
+#ifdef CONFIG_DEBUG_FS
+               printk("devread: fsys == NULL!\n");
+#endif
+               return -1;
+       }
+
+       if( seek_io(curfs->dev_fd, offs + curfs->offset) ) {
+#ifdef CONFIG_DEBUG_FS
+               printk("seek failure\n");
+#endif
+               return -1;
+       }
+       return (read_io(curfs->dev_fd, buf, byte_len) == byte_len) ? 1:0;
+}
+
+int
+file_read( void *buf, unsigned long len )
+{
+       if (filepos < 0 || filepos > filemax)
+               filepos = filemax;
+       if (len > filemax-filepos)
+               len = filemax - filepos;
+       errnum = 0;
+       return curfs->fsys->read_func( buf, len );
+}
+
+
+/************************************************************************/
+/*     Standard package methods                                        */
+/************************************************************************/
+
+/* ( -- success? ) */
+static void
+grubfs_files_open( grubfs_info_t *mi )
+{
+       int fd, i;
+       char *path = my_args_copy();
+       char *s;
+
+       fd = open_ih( my_parent() );
+       if ( fd == -1 ) {
+               free( path );
+               RET( 0 );
+       }
+
+       mi->gfs = &dummy_fs;
+
+       for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) {
+#ifdef CONFIG_DEBUG_FS
+               printk("Trying %s\n", fsys_table[i].name);
+#endif
+               if (fsys_table[i].mount_func()) {
+                       const fsys_entry_t *fsys = &fsys_table[i];
+#ifdef CONFIG_DEBUG_FS
+                       printk("Mounted %s\n", fsys->name);
+#endif
+                       mi->gfs = malloc(sizeof(grubfs_t));
+                       mi->gfs->fsys = fsys;
+                       mi->gfs->dev_fd = fd;
+                       mi->gfs->offset = 0;
+
+                       s = path;
+                       while (*s) {
+                               if(*s=='\\') *s='/';
+                               s++;
+                       }
+#ifdef CONFIG_DEBUG_FS
+                       printk("Path=%s\n",path);
+#endif
+                       if (!mi->gfs->fsys->dir_func((char *) path)) {
+                               forth_printf("File not found\n");
+                               RET( 0 );
+                       }
+
+                       mi->gfs->fd = malloc(sizeof(grubfile_t));
+                       mi->gfs->fd->pos = filepos;
+                       mi->gfs->fd->len = filemax;
+                       mi->gfs->fd->path = strdup(path);
+
+                       RET( -1 );
+               }
+       }
+#ifdef CONFIG_DEBUG_FS
+       printk("Unknown filesystem type\n");
+#endif
+
+       RET( 0 );
+}
+
+/* ( -- ) */
+static void
+grubfs_files_close( grubfs_info_t *mi )
+{
+       grubfile_t *gf = mi->gfs->fd;
+
+       if (gf->path)
+               free((void *)(gf->path));
+       free(gf);
+
+       filepos = 0;
+       filemax = 0;
+}
+
+/* ( buf len -- actlen ) */
+static void
+grubfs_files_read( grubfs_info_t *mi )
+{
+       int count = POP();
+       char *buf = (char *)cell2pointer(POP());
+
+       grubfile_t *file = mi->gfs->fd;
+        int ret;
+
+       filepos = file->pos;
+       filemax = file->len;
+
+       if (count > filemax - filepos)
+               count = filemax - filepos;
+
+       ret = mi->gfs->fsys->read_func(buf, count);
+
+       file->pos = filepos;
+
+       RET( ret );
+}
+
+/* ( pos.d -- status ) */
+static void
+grubfs_files_seek( grubfs_info_t *mi )
+{
+       long long pos = DPOP();
+       int offs = (int)pos;
+       int whence = SEEK_SET;
+
+       grubfile_t *file = mi->gfs->fd;
+       unsigned long newpos;
+
+       switch( whence ) {
+       case SEEK_END:
+               if (offs < 0 && (unsigned long) -offs > file->len)
+                       newpos = 0;
+               else
+                       newpos = file->len + offs;
+               break;
+       default:
+       case SEEK_SET:
+               newpos = (offs < 0) ? 0 : offs;
+               break;
+       }
+
+       if (newpos > file->len)
+               newpos = file->len;
+
+       file->pos = newpos;
+
+       if (newpos)
+               RET( -1 );
+       else
+               RET( 0 );
+}
+
+/* ( addr -- size ) */
+static void
+grubfs_files_load( grubfs_info_t *mi )
+{
+       char *buf = (char *)cell2pointer(POP());
+       int count, ret;
+
+       grubfile_t *file = mi->gfs->fd;
+       count = file->len;
+
+       ret = mi->gfs->fsys->read_func(buf, count);
+       file->pos = filepos;
+
+       RET( ret );
+}
+
+/* ( -- cstr ) */
+static void
+grubfs_files_get_path( grubfs_info_t *mi )
+{
+       grubfile_t *file = mi->gfs->fd;
+       const char *path = file->path;
+
+       RET( pointer2cell(strdup(path)) );
+}
+
+/* ( -- cstr ) */
+static void
+grubfs_files_get_fstype( grubfs_info_t *mi )
+{
+       grubfs_t *gfs = mi->gfs;
+
+       PUSH( pointer2cell(strdup(gfs->fsys->name)) );
+}
+
+
+/* static method, ( pos.d ih -- flag? ) */
+static void
+grubfs_files_probe( grubfs_info_t *dummy )
+{
+       ihandle_t ih = POP_ih();
+       long long offs = DPOP();
+       int i;
+
+       curfs->dev_fd = open_ih(ih);
+        if (curfs->dev_fd == -1) {
+                RET( -1 );
+        }
+       curfs->offset = offs;
+
+       for (i = 0; i < sizeof(fsys_table)/sizeof(fsys_table[0]); i++) {
+#ifdef CONFIG_DEBUG_FS
+               printk("Probing for %s\n", fsys_table[i].name);
+#endif
+               if (fsys_table[i].mount_func()) {
+                       RET( -1 );
+               }
+       }
+
+#ifdef CONFIG_DEBUG_FS
+       printk("Unknown filesystem type\n");
+#endif
+
+       close_io(curfs->dev_fd);
+
+       RET ( 0 );
+}
+
+/* static method, ( pathstr len ihandle -- ) */
+static void
+grubfs_files_dir( grubfs_info_t *dummy )
+{
+       forth_printf("dir method not implemented for grubfs filesystem\n");
+       POP();
+       POP();
+       POP();
+}
+
+static void
+grubfs_initializer( grubfs_info_t *dummy )
+{
+       fword("register-fs-package");
+}
+
+NODE_METHODS( grubfs ) = {
+       { "probe",      grubfs_files_probe      },
+       { "open",       grubfs_files_open       },
+       { "close",      grubfs_files_close      },
+       { "read",       grubfs_files_read       },
+       { "seek",       grubfs_files_seek       },
+       { "load",       grubfs_files_load       },
+       { "dir",        grubfs_files_dir        },
+
+       /* special */
+       { "get-path",   grubfs_files_get_path   },
+       { "get-fstype", grubfs_files_get_fstype },
+
+       { NULL,         grubfs_initializer      },
+};
+
+void
+grubfs_init( void )
+{
+       REGISTER_NODE( grubfs );
+}