extmod: Add generic VFS sub-system.

This provides mp_vfs_XXX functions (eg mount, open, listdir) which are
agnostic to the underlying filesystem type, and just require an object with
the relevant filesystem-like methods (eg .mount, .open, .listidr) which can
then be mounted.

These mp_vfs_XXX functions would typically be used by a port to implement
the "uos" module, and mp_vfs_open would be the builtin open function.

This feature is controlled by MICROPY_VFS, disabled by default.
diff --git a/py/lexer.c b/py/lexer.c
index 458fba0..e9b571c 100644
--- a/py/lexer.c
+++ b/py/lexer.c
@@ -753,7 +753,7 @@
     return mp_lexer_new(src_name, reader);
 }
 
-#if MICROPY_READER_POSIX || MICROPY_READER_FATFS
+#if MICROPY_READER_POSIX || MICROPY_READER_VFS || MICROPY_READER_FATFS
 
 mp_lexer_t *mp_lexer_new_from_file(const char *filename) {
     mp_reader_t reader;
diff --git a/py/mpconfig.h b/py/mpconfig.h
index 3bccada..a924eda 100644
--- a/py/mpconfig.h
+++ b/py/mpconfig.h
@@ -398,6 +398,11 @@
 #define MICROPY_READER_POSIX (0)
 #endif
 
+// Whether to use the VFS reader for importing files
+#ifndef MICROPY_READER_VFS
+#define MICROPY_READER_VFS (0)
+#endif
+
 // Whether to use the FatFS reader for importing files
 #ifndef MICROPY_READER_FATFS
 #define MICROPY_READER_FATFS (0)
@@ -621,6 +626,11 @@
 #define MICROPY_FSUSERMOUNT (0)
 #endif
 
+// Support for generic VFS sub-system
+#ifndef MICROPY_VFS
+#define MICROPY_VFS (0)
+#endif
+
 /*****************************************************************************/
 /* Fine control over Python builtins, classes, modules, etc                  */
 
diff --git a/py/mpstate.h b/py/mpstate.h
index 91fb68b..9c73f77 100644
--- a/py/mpstate.h
+++ b/py/mpstate.h
@@ -165,6 +165,11 @@
     struct _fs_user_mount_t *fs_user_mount[MICROPY_FATFS_VOLUMES];
     #endif
 
+    #if MICROPY_VFS
+    struct _vfs_mount_t *vfs_cur;
+    struct _vfs_mount_t *vfs_mount_table;
+    #endif
+
     //
     // END ROOT POINTER SECTION
     ////////////////////////////////////////////////////////////
diff --git a/py/py.mk b/py/py.mk
index 6981905..94265c3 100644
--- a/py/py.mk
+++ b/py/py.mk
@@ -233,6 +233,8 @@
 	../extmod/modwebrepl.o \
 	../extmod/modframebuf.o \
 	../extmod/fsusermount.o \
+	../extmod/vfs.o \
+	../extmod/vfs_reader.o \
 	../extmod/vfs_fat.o \
 	../extmod/vfs_fat_ffconf.o \
 	../extmod/vfs_fat_diskio.o \
diff --git a/py/qstrdefs.h b/py/qstrdefs.h
index c98a253..4581e5e 100644
--- a/py/qstrdefs.h
+++ b/py/qstrdefs.h
@@ -36,6 +36,7 @@
 Q()
 Q(*)
 Q(_)
+Q(/)
 Q(%#o)
 Q(%#x)
 Q({:#b})
diff --git a/py/runtime.c b/py/runtime.c
index 0ccfd8d..e6aef21 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -105,6 +105,12 @@
     memset(MP_STATE_VM(fs_user_mount), 0, sizeof(MP_STATE_VM(fs_user_mount)));
     #endif
 
+    #if MICROPY_VFS
+    // initialise the VFS sub-system
+    MP_STATE_VM(vfs_cur) = NULL;
+    MP_STATE_VM(vfs_mount_table) = NULL;
+    #endif
+
     #if MICROPY_PY_THREAD_GIL
     mp_thread_mutex_init(&MP_STATE_VM(gil_mutex));
     #endif