The linux kernel
If you want to access files on the host machine from inside UML, you can treat it as a separate machine and either nfs mount directories from the host or copy files into the virtual machine with scp or rcp. However, since UML is running on the the host, it can access those files just like any other process and make them available inside the virtual machine without needing to use the network.
This is now possible with the hostfs virtual filesystem. With it, you can mount a host directory into the UML filesystem and access the files contained in it just as you would on the host.
Note that hostfs is currently not available on 2.5. The reason is that there was an fs.h rework early in 2.5 which required filesystem changes, and I haven't got around to updating hostfs to those changes.
Using hostfs |
To begin with, make sure that hostfs is available inside the virtual machine withUML# cat /proc/filesystemshostfs should be listed. If it's not, either rebuild the kernel with hostfs configured into it or make sure that hostfs is built as a module and available inside the virtual machine, and insmod it.Now all you need to do is run mount:
UML# mount none /mnt/host -t hostfswill mount the host's / on the virtual machine's /mnt/host.UML# mount none /mnt/home -t hostfs -o /homewill mount the hosts's /home on the virtual machine's /mnt/home.
This document describes how to add a system call to User-mode Linux. The original version was written by Alexandros Karypidis. The version presented here is slightly modified to handle 2.6 kernels, specifically this is based on the 2.6.10 kernel. Furthermore, we use output from diff
to show what to change.
Further information can be found here:
The first thing you need to do is modify the file unistd.h
in include/asm/arch
. In this file, you need to add a line providing an id for your system call. Locate the bunch of lines of the form #define __NR_somename
, and add a new entry for your system call. Further, you should increment the total number of available system calls as defined by NR_syscalls
.
--- old/include/asm-i386/unistd.h 2005-01-10 09:08:18.000000000 +0100
+++ new/include/asm-i386/unistd.h 2005-03-03 14:33:25.366255000 +0100
@@ -294,8 +294,9 @@
#define __NR_add_key 286
#define __NR_request_key 287
#define __NR_keyctl 288
+#define __NR_somename 289
-#define NR_syscalls 289
+#define NR_syscalls 290
/*
* user-visible error numbers are in the range -1 - -128: see
Next, you must add and entry refering to your call in the system calls table. To do this, modify sys_call_table.c
file in arch/um/kernel
and edit the following lines:
--- old/arch/um/kernel/sys_call_table.c 2005-01-10 09:08:18.000000000 +0100
+++ new/arch/um/kernel/sys_call_table.c 2005-03-03 14:21:00.580270000 +0100
@@ -19,7 +19,7 @@
#define NFSSERVCTL sys_ni_syscall
#endif
-#define LAST_GENERIC_SYSCALL __NR_vserver
+#define LAST_GENERIC_SYSCALL __NR_somename
#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
#define LAST_SYSCALL LAST_GENERIC_SYSCALL
@@ -51,8 +51,12 @@
extern syscall_handler_t old_select;
extern syscall_handler_t sys_modify_ldt;
extern syscall_handler_t sys_rt_sigsuspend;
+extern syscall_handler_t sys_somename;
syscall_handler_t *sys_call_table[] = {
+ /* The following line ensures that we do not get any problems with */
+ /* undefined system calls. */
+ [ 0 ... LAST_GENERIC_SYSCALL ] = (syscall_handler_t *) sys_ni_syscall,
[ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall,
[ __NR_exit ] (syscall_handler_t *) sys_exit,
[ __NR_fork ] (syscall_handler_t *) sys_fork,
@@ -306,6 +310,7 @@
[ __NR_utimes ] (syscall_handler_t *) sys_utimes,
[ __NR_fadvise64_64 ] (syscall_handler_t *) sys_fadvise64_64,
[ __NR_vserver ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_somename ] (syscall_handler_t *) sys_somename,
ARCH_SYSCALLS
[ LAST_SYSCALL + 1 ... NR_syscalls ] =
LAST_GENERIC_SYSCALL
must be changed such that your new system call's id is considered to be within the allowable range.
Next, we add a declaration for your system call in the area where all the other system calls are defined.
The line with [ 0 ... LAST_GENERIC_SYSCALL ] = (syscall_handler_t *) sys_ni_syscall,
ensures that system calls which are in the normal kernel, but not in User-mode Linux are defined as not implemented. At least the 2.6.10 kernel are missing more than 10 system calls, and without this change, the kernel could segfault if one of the missing system calls were used.
The last change adds your system call to the system call table, such that it can be called from user space.
Having done all these, an attempt to compile the kernel should fail during linking, as the sys_somename
function must now be implemented.
First of all, create a header file somename.h
for your system call and place it in arch/um/include
as shown here:
/*
* somename.h
*/
#ifndef __UML_SOMENAME_H__
#define __UML_SOMENAME_H__
extern int sys_somename(int flag);
#endif
Then, write out the implementation somename.c
of your system call in arch/um/kernel
as shown here:
/*
* somename.c
*/
#include "linux/kernel.h"
#include "linux/unistd.h"
asmlinkage
int sys_somename(int flag) {
printk("Hello from somename! flag=%d.\n", flag);
return 0;
}
Finally, modify the respective Makefile
in arch/um/kernel
and add somename.o to the list of build targets.
--- old/arch/um/kernel/Makefile 2005-01-10 09:08:18.000000000 +0100
+++ new/arch/um/kernel/Makefile 2005-02-09 15:59:14.185985000 +0100
@@ -9,13 +9,13 @@
obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o physmem.o process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o - um_arch.o umid.o user_util.o
+ um_arch.o umid.o user_util.o somename.o
obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
obj-$(CONFIG_GPROF) += gprof_syms.o
obj-$(CONFIG_GCOV) += gmon_syms.o
obj-$(CONFIG_TTY_LOG) += tty_log.o
The listing below shows a program which uses the _syscall
macro to create a stub for the system call. It then proceeds to call the stub function. When compiling, be sure to specify the -I option so that gcc will look at the modified version of unistd.h
. In the example, the preprocessor looks for the file in asm/arch/unistd.h
, so if the UML code is in the directory /uml-code
you should compile with -I/uml-code/include
.
/*
* test_somename.c
*
* Note: should be compiled with:
* gcc -I path.to.kernel.tree/linux-2.6.10/include -o test_somename test_somename.c
*/
#include
#include
#include "asm/arch/unistd.h"
_syscall1(int, somename, int, flag);
int main(int argc, char** argv) {
printf("Calling...\n");
somename(1);
}
Define the entry point
/etc/syslog.conf tells us where the kernel messages will be stored.
The previous post has the details of loading Slackware in the slackware.img file specified by /dev/ubd1 in the initial command line:
First unpack and build the UML utilities. No ./configure, just type make, and make sure the port-helper utility is put somewhere in your path.
tar -jxvf uml_utilities_20040406.tar.bz2
cd tools
make
cp port-helper/port-helper /usr/local/bin
You probably also want tunctl, but that's for a future HOWTO.
Next you need to configure your kernel. You don't need to be root to do this, (in fact it's better if you don't do it in /usr/src/linux). I used kernel 2.6.12.1 mostly with defaults, but make sure you have iso9660 and ext2 compiled in. We need ext2 for the initial ram drive and iso9660 for reading the install CD/image. You should also compile in your favourite file system driver, whichever one you normally select in the Slackware install menu (Reiserfs for me):
wgethttp://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.12.1.tar.bz2
tar -jxf linux-2.6.12.1.tar.bz2
cd linux-2.6.12.1
make menuconfig ARCH=um
make linux ARCH=um
That should give you a linux executable called 'linux'. Go on - run it. It should just complain about the fact that it's missing a root file system. You might need to kill it from another terminal.
Mount the first slackware CD, then copy the installation root fs:
mount /mnt/cdrom
cp /mnt/cdrom/isolinux/initrd.img initrd.gz
gzip -d initrd.gz
chmod 666 initrd
umount /mnt/cdrom
Don't forget to unmount the CD, because UML needs direct access to /dev/cdrom.
Next we need the target file system, created by dd (this is a sparse file, of course):
dd if=/dev/zero of=slackware.img bs=1M count=1 seek=4000
Now, run the linux executable using the Slackware initial ramdrive as root. Make sure you do this in an Xterm, and as a user who has access to the X server, because this will try to throw up some Xterm consoles (unless you foolishly disabled them in the kernel config).
linux mem=128M ubd0=initrd ubd1=slackware.img ubd2r=/dev/cdrom rw
Note: If you want to install both CDs of software then you need to specify a 'real' CD device (/dev/cdrom) instead of an ISO image file. This is because you can't really 'eject' an ISO image, and that is required for the install.
--------------------------------------------------------------------------------------------DatuX Usermode Linux with Slackware 9.1 HOWTO
http://uml.harlowhill.com/index.php/SlackwareHowto