source "fs/Kconfig.binfmt"
+config EXTERNFS
+ tristate "Support for host-based filesystems"
+
config HOSTFS
tristate "Host filesystem"
help
If you'd like to be able to work with files stored on the host,
say Y or M here; otherwise say N.
+config HUMFS
+ tristate 'Usable host filesystem'
+ depends on EXTERNFS
+
config HPPFS
tristate "HoneyPot ProcFS"
help
config UNIX98_PTYS
bool "Unix98 PTY support"
-
-config UNIX98_PTY_COUNT
- int "Maximum number of Unix98 PTYs in use (0-2048)"
- depends on UNIX98_PTYS
+ ---help---
+ A pseudo terminal (PTY) is a software device consisting of two
+ halves: a master and a slave. The slave device behaves identical to
+ a physical terminal; the master device is used by a process to
+ read data from and write data to the slave, thereby emulating a
+ terminal. Typical programs for the master side are telnet servers
+ and xterms.
+
+ Linux has traditionally used the BSD-like names /dev/ptyxx for
+ masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+ has a number of problems. The GNU C library glibc 2.1 and later,
+ however, supports the Unix98 naming standard: in order to acquire a
+ pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+ terminal is then made available to the process and the pseudo
+ terminal slave can be accessed as /dev/pts/<number>. What was
+ traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+ All modern Linux systems use the Unix98 ptys. Say Y unless
+ you're on an embedded system and want to conserve memory.
+
+config LEGACY_PTYS
+ bool "Legacy (BSD) PTY support"
+ default y
+ ---help---
+ A pseudo terminal (PTY) is a software device consisting of two
+ halves: a master and a slave. The slave device behaves identical to
+ a physical terminal; the master device is used by a process to
+ read data from and write data to the slave, thereby emulating a
+ terminal. Typical programs for the master side are telnet servers
+ and xterms.
+
+ Linux has traditionally used the BSD-like names /dev/ptyxx
+ for masters and /dev/ttyxx for slaves of pseudo
+ terminals. This scheme has a number of problems, including
+ security. This option enables these legacy devices; on most
+ systems, it is safe to say N.
+
+
+config LEGACY_PTY_COUNT
+ int "Maximum number of legacy PTY in use"
+ depends on LEGACY_PTYS
default "256"
+ ---help---
+ The maximum number of legacy PTYs that can be used at any one time.
+ The default is 256, and should be more than enough. Embedded
+ systems may want to reduce this to save memory.
+
+ When not in use, each legacy PTY occupies 12 bytes on 32-bit
+ architectures and 24 bytes on 64-bit architectures.
config WATCHDOG
bool "Watchdog Timer Support"
include $(ARCH_DIR)/Makefile-$(SUBARCH)
include $(ARCH_DIR)/Makefile-os-$(OS)
-EXTRAVERSION := $(EXTRAVERSION)-1um
+EXTRAVERSION := $(EXTRAVERSION)-2um
ARCH_INCLUDE = -I$(ARCH_DIR)/include
-D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \
-Dsigprocmask=kernel_sigprocmask $(MODE_INCLUDE)
+check_gcc = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi)
+
+CFLAGS += $(call check_gcc,-fno-unit-at-a-time,)
+
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
# These are needed for clean and mrproper, since in that case .config is not
# included; the values here are meaningless
CONFIG_NEST_LEVEL ?= 0
-CONFIG_KERNEL_HALF_GIGS ?= 0
+CONFIG_KERNEL_HALF_GIGS ?= 0
SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000)
CONFIG_KERNEL_STACK_ORDER ?= 2
STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
+ifndef START
+ START = $$(($(TOP_ADDR) - $(SIZE)))
+endif
+
AFLAGS_vmlinux.lds.o = $(shell echo -U$(SUBARCH) \
- -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \
+ -DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
-DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE_TT) \
-DKERNEL_STACK_SIZE=$(STACK_SIZE))
$(Q)$(MAKE) $(build)=$@
export SUBARCH USER_CFLAGS OS
+
+all: linux
+
+define archhelp
+ echo '* linux - Binary kernel image (./linux)'
+endef
TOP_ADDR = 0xc0000000
endif
+ifeq ($(CONFIG_MODE_SKAS),y)
+ ifneq ($(CONFIG_MODE_TT),y)
+ START = 0x8048000
+ endif
+endif
+
CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
+
+ifneq ($(CONFIG_GPROF),y)
+ARCH_CFLAGS += -DUM_FASTCALL
+endif
+
ELF_ARCH = $(SUBARCH)
ELF_FORMAT = elf32-$(SUBARCH)
CONFIG_NET=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
+CONFIG_EXTERNFS=y
CONFIG_HOSTFS=y
+CONFIG_HUMFS=y
CONFIG_HPPFS=y
CONFIG_MCONSOLE=y
CONFIG_MAGIC_SYSRQ=y
#
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_HOTPLUG is not set
# CONFIG_IKCONFIG is not set
CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
#
CONFIG_CON_CHAN="xterm"
CONFIG_SSL_CHAN="pty"
CONFIG_UNIX98_PTYS=y
-CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_WATCHDOG is not set
CONFIG_UML_SOUND=y
CONFIG_SOUND=y
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_ARPD is not set
-# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_IPV6 is not set
-# CONFIG_DECNET is not set
-# CONFIG_BRIDGE is not set
# CONFIG_NETFILTER is not set
#
# SCTP Configuration (EXPERIMENTAL)
#
-CONFIG_IPV6_SCTP__=y
# CONFIG_IP_SCTP is not set
# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# Network testing
#
# CONFIG_NET_PKTGEN is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
CONFIG_DUMMY=y
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
#
# Ethernet (10000 Mbit)
#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
CONFIG_PPP=y
# CONFIG_PPP_MULTILINK is not set
# CONFIG_PPP_FILTER is not set
# CONFIG_SLIP_COMPRESSED is not set
# CONFIG_SLIP_SMART is not set
# CONFIG_SLIP_MODE_SLIP6 is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Token Ring devices
-#
# CONFIG_SHAPER is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-
-#
-# Amateur Radio support
-#
-# CONFIG_HAMRADIO is not set
-
-#
-# IrDA (infrared) support
-#
-# CONFIG_IRDA is not set
-
-#
-# Bluetooth support
-#
-# CONFIG_BT is not set
+# CONFIG_NETCONSOLE is not set
#
# File systems
CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
# CONFIG_JFS_FS is not set
# CONFIG_XFS_FS is not set
CONFIG_MINIX_FS=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_SYSFS=y
CONFIG_DEVFS_FS=y
CONFIG_DEVFS_MOUNT=y
# CONFIG_DEVFS_DEBUG is not set
# Library routines
#
# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
#
# SCSI support
#pcap-objs := pcap_kern.o pcap_user.o $(PCAP)
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
-hostaudio-objs := hostaudio_kern.o hostaudio_user.o
+hostaudio-objs := hostaudio_kern.o
ubd-objs := ubd_kern.o ubd_user.o
port-objs := port_kern.o port_user.o
harddog-objs := harddog_kern.o harddog_user.o
#include "irq_user.h"
#include "sigio.h"
#include "line.h"
+#include "os.h"
static void *not_configged_init(char *str, int device, struct chan_opts *opts)
{
.winch = 0,
};
+void generic_close(int fd, void *unused)
+{
+ os_close_file(fd);
+}
+
+int generic_read(int fd, char *c_out, void *unused)
+{
+ int n;
+
+ n = os_read_file(fd, c_out, sizeof(*c_out));
+
+ if(n == -EAGAIN)
+ return(0);
+ else if(n == 0)
+ return(-EIO);
+ return(n);
+}
+
+/* XXX Trivial wrapper around os_write_file */
+
+int generic_write(int fd, const char *buf, int n, void *unused)
+{
+ return(os_write_file(fd, buf, n));
+}
+
+int generic_window_size(int fd, void *unused, unsigned short *rows_out,
+ unsigned short *cols_out)
+{
+ int rows, cols;
+ int ret;
+
+ ret = os_window_size(fd, &rows, &cols);
+ if(ret < 0)
+ return(ret);
+
+ ret = ((*rows_out != rows) || (*cols_out != cols));
+
+ *rows_out = rows;
+ *cols_out = cols;
+
+ return(ret);
+}
+
+void generic_free(void *data)
+{
+ kfree(data);
+}
+
static void tty_receive_char(struct tty_struct *tty, char ch)
{
if(tty == NULL) return;
#include "choose-mode.h"
#include "mode.h"
-void generic_close(int fd, void *unused)
+static void winch_handler(int sig)
{
- os_close_file(fd);
}
-int generic_read(int fd, char *c_out, void *unused)
-{
- int n;
-
- n = os_read_file(fd, c_out, sizeof(*c_out));
-
- if(n == -EAGAIN)
- return(0);
- else if(n == 0)
- return(-EIO);
- return(n);
-}
-
-/* XXX Trivial wrapper around os_write_file */
-
-int generic_write(int fd, const char *buf, int n, void *unused)
-{
- return(os_write_file(fd, buf, n));
-}
+struct winch_data {
+ int pty_fd;
+ int pipe_fd;
+ int close_me;
+};
+/* XXX This breaks horribly (by hanging UML) when moved to chan_kern.c -
+ * needs investigation
+ */
int generic_console_write(int fd, const char *buf, int n, void *unused)
{
struct termios save, new;
return(err);
}
-int generic_window_size(int fd, void *unused, unsigned short *rows_out,
- unsigned short *cols_out)
-{
- int rows, cols;
- int ret;
-
- ret = os_window_size(fd, &rows, &cols);
- if(ret < 0)
- return(ret);
-
- ret = ((*rows_out != rows) || (*cols_out != cols));
-
- *rows_out = rows;
- *cols_out = cols;
-
- return(ret);
-}
-
-void generic_free(void *data)
-{
- kfree(data);
-}
-
-static void winch_handler(int sig)
-{
-}
-
-struct winch_data {
- int pty_fd;
- int pipe_fd;
- int close_me;
-};
-
static int winch_thread(void *arg)
{
struct winch_data *data = arg;
#define PATH_LEN_V2 MAXPATHLEN
struct cow_header_v2 {
- unsigned long magic;
- unsigned long version;
+ __u32 magic;
+ __u32 version;
char backing_file[PATH_LEN_V2];
time_t mtime;
__u64 size;
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>
+#include <errno.h>
#include "user.h"
#include "user_util.h"
#include "chan_user.h"
int fd_open(int input, int output, int primary, void *d, char **dev_out)
{
struct fd_chan *data = d;
+ int err;
if(data->raw && isatty(data->fd)){
- tcgetattr(data->fd, &data->tt);
- raw(data->fd, 0);
+ CATCH_EINTR(err = tcgetattr(data->fd, &data->tt));
+ if(err)
+ return(err);
+
+ err = raw(data->fd);
+ if(err)
+ return(err);
}
sprintf(data->str, "%d", data->fd);
*dev_out = data->str;
void fd_close(int fd, void *d)
{
struct fd_chan *data = d;
+ int err;
if(data->raw && isatty(fd)){
- tcsetattr(fd, TCSAFLUSH, &data->tt);
+ CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &data->tt));
+ if(err)
+ printk("Failed to restore terminal state - "
+ "errno = %d\n", -err);
data->raw = 0;
}
}
#include "asm/uaccess.h"
#include "kern_util.h"
#include "init.h"
-#include "hostaudio.h"
+#include "os.h"
+
+struct hostaudio_state {
+ int fd;
+};
+
+struct hostmixer_state {
+ int fd;
+};
+
+#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp"
+#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer"
/* Only changed from linux_main at boot time */
char *dsp = HOSTAUDIO_DEV_DSP;
" The default is \"" HOSTAUDIO_DEV_DSP "\".\n\n"
#define MIXER_HELP \
-" This is used to specify the host mixer device to the hostaudio driver.\n" \
+" This is used to specify the host mixer device to the hostaudio driver.\n"\
" The default is \"" HOSTAUDIO_DEV_MIXER "\".\n\n"
#ifndef MODULE
if(kbuf == NULL)
return(-ENOMEM);
- err = hostaudio_read_user(state, kbuf, count, ppos);
+ err = os_read_file(state->fd, kbuf, count);
if(err < 0)
goto out;
if(copy_from_user(kbuf, buffer, count))
goto out;
- err = hostaudio_write_user(state, kbuf, count, ppos);
+ err = os_write_file(state->fd, kbuf, count);
if(err < 0)
goto out;
+ *ppos += err;
out:
kfree(kbuf);
break;
}
- err = hostaudio_ioctl_user(state, cmd, (unsigned long) &data);
+ err = os_ioctl_generic(state->fd, cmd, (unsigned long) &data);
switch(cmd){
case SNDCTL_DSP_SPEED:
#endif
state = kmalloc(sizeof(struct hostaudio_state), GFP_KERNEL);
- if(state == NULL) return(-ENOMEM);
+ if(state == NULL)
+ return(-ENOMEM);
if(file->f_mode & FMODE_READ) r = 1;
if(file->f_mode & FMODE_WRITE) w = 1;
- ret = hostaudio_open_user(state, r, w, dsp);
+ ret = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0);
if(ret < 0){
kfree(state);
return(ret);
}
+ state->fd = ret;
file->private_data = state;
return(0);
}
static int hostaudio_release(struct inode *inode, struct file *file)
{
struct hostaudio_state *state = file->private_data;
- int ret;
#ifdef DEBUG
printk("hostaudio: release called\n");
#endif
- ret = hostaudio_release_user(state);
+ os_close_file(state->fd);
kfree(state);
- return(ret);
+ return(0);
}
/* /dev/mixer file operations */
printk("hostmixer: ioctl called\n");
#endif
- return(hostmixer_ioctl_mixdev_user(state, cmd, arg));
+ return(os_ioctl_generic(state->fd, cmd, arg));
}
static int hostmixer_open_mixdev(struct inode *inode, struct file *file)
if(file->f_mode & FMODE_READ) r = 1;
if(file->f_mode & FMODE_WRITE) w = 1;
- ret = hostmixer_open_mixdev_user(state, r, w, mixer);
+ ret = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0);
if(ret < 0){
+ printk("hostaudio_open_mixdev failed to open '%s', err = %d\n",
+ dsp, -ret);
kfree(state);
return(ret);
}
static int hostmixer_release(struct inode *inode, struct file *file)
{
struct hostmixer_state *state = file->private_data;
- int ret;
#ifdef DEBUG
printk("hostmixer: release called\n");
#endif
- ret = hostmixer_release_mixdev_user(state);
+ os_close_file(state->fd);
kfree(state);
- return(ret);
+ return(0);
}
LIST_HEAD(mc_requests);
-void mc_work_proc(void *unused)
+static void mc_work_proc(void *unused)
{
struct mconsole_entry *req;
unsigned long flags;
- int done;
- do {
+ while(!list_empty(&mc_requests)){
local_save_flags(flags);
req = list_entry(mc_requests.next, struct mconsole_entry,
list);
list_del(&req->list);
- done = list_empty(&mc_requests);
local_irq_restore(flags);
req->request.cmd->handler(&req->request);
kfree(req);
- } while(!done);
+ }
}
DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
-irqreturn_t mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
{
int fd;
struct mconsole_entry *new;
}
}
}
- if(!list_empty(&mc_requests)) schedule_work(&mconsole_work);
+ if(!list_empty(&mc_requests))
+ schedule_work(&mconsole_work);
reactivate_fd(fd, MCONSOLE_IRQ);
return(IRQ_HANDLED);
}
ptr += strlen("sysrq");
while(isspace(*ptr)) ptr++;
- handle_sysrq(*ptr, ¤t->thread.regs, NULL);
mconsole_reply(req, "", 0, 0);
+ handle_sysrq(*ptr, ¤t->thread.regs, NULL);
}
#else
void mconsole_sysrq(struct mc_request *req)
#include "linux/inetdevice.h"
#include "linux/ctype.h"
#include "linux/bootmem.h"
+#include "linux/ethtool.h"
+#include "asm/uaccess.h"
#include "user_util.h"
#include "kern_util.h"
#include "net_kern.h"
static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- return(-EINVAL);
+ static const struct ethtool_drvinfo info = {
+ .cmd = ETHTOOL_GDRVINFO,
+ .driver = "uml virtual ethernet",
+ .version = "42",
+ };
+ void *useraddr;
+ u32 ethcmd;
+
+ switch (cmd) {
+ case SIOCETHTOOL:
+ useraddr = ifr->ifr_data;
+ if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd)))
+ return -EFAULT;
+ switch (ethcmd) {
+ case ETHTOOL_GDRVINFO:
+ if (copy_to_user(useraddr, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+ default:
+ return -EINVAL;
+ }
}
void uml_net_user_timer_expire(unsigned long _conn)
pe_data.stdout = fds[1];
pid = run_helper(change_pre_exec, &pe_data, argv, NULL);
- os_close_file(fds[1]);
read_output(fds[0], output, output_len);
- waitpid(pid, NULL, 0);
+ os_close_file(fds[0]);
+ os_close_file(fds[1]);
+ CATCH_EINTR(waitpid(pid, NULL, 0));
return(pid);
}
int port_open(int input, int output, int primary, void *d, char **dev_out)
{
struct port_chan *data = d;
- int fd;
+ int fd, err;
fd = port_wait(data->kernel_data);
if((fd >= 0) && data->raw){
- tcgetattr(fd, &data->tt);
- raw(fd, 0);
+ CATCH_EINTR(err = tcgetattr(fd, &data->tt));
+ if(err)
+ return(err);
+
+ err = raw(fd);
+ if(err)
+ return(err);
}
*dev_out = data->dev;
return(fd);
int port_listen_fd(int port)
{
struct sockaddr_in addr;
- int fd, err;
+ int fd, err, arg;
fd = socket(PF_INET, SOCK_STREAM, 0);
if(fd == -1)
return(-errno);
+ arg = 1;
+ if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &arg, sizeof(arg)) < 0){
+ err = -errno;
+ goto out;
+ }
+
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
{
struct pty_chan *data = d;
char *dev;
- int fd;
+ int fd, err;
fd = get_pty();
if(fd < 0){
return(-errno);
}
if(data->raw){
- tcgetattr(fd, &data->tt);
- raw(fd, 0);
+ CATCH_EINTR(err = tcgetattr(fd, &data->tt));
+ if(err)
+ return(err);
+
+ err = raw(fd);
+ if(err)
+ return(err);
}
dev = ptsname(fd);
int pty_open(int input, int output, int primary, void *d, char **dev_out)
{
struct pty_chan *data = d;
- int fd;
+ int fd, err;
char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx";
fd = getmaster(dev);
- if(fd < 0) return(-errno);
+ if(fd < 0)
+ return(-errno);
+
+ if(data->raw){
+ err = raw(fd);
+ if(err)
+ return(err);
+ }
- if(data->raw) raw(fd, 0);
if(data->announce) (*data->announce)(dev, data->dev);
sprintf(data->dev_name, "%s", dev);
#include <stddef.h>
#include <sched.h>
#include <string.h>
-#include <sys/errno.h>
+#include <errno.h>
#include <sys/termios.h>
#include <sys/wait.h>
#include <sys/signal.h>
printk("%s", output);
kfree(output);
}
- if(waitpid(pid, &status, 0) < 0) err = errno;
+ CATCH_EINTR(err = waitpid(pid, &status, 0));
+ if(err < 0)
+ err = errno;
else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){
printk("'%s' didn't exit with status 0\n", argv[0]);
err = -EINVAL;
#include <stddef.h>
#include <sched.h>
#include <string.h>
-#include <sys/errno.h>
+#include <errno.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include "user_util.h"
}
#endif
- err = waitpid(pri->pid, &status, WNOHANG);
- if(err<0) {
+ CATCH_EINTR(err = waitpid(pri->pid, &status, WNOHANG));
+ if(err < 0) {
printk("slirp_close: waitpid returned %d\n", errno);
return;
}
- if(err==0) {
+ if(err == 0) {
printk("slirp_close: process %d has not exited\n");
return;
}
int tty_open(int input, int output, int primary, void *d, char **dev_out)
{
struct tty_chan *data = d;
- int fd;
+ int fd, err;
fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0);
if(fd < 0) return(fd);
if(data->raw){
- tcgetattr(fd, &data->tt);
- raw(fd, 0);
+ CATCH_EINTR(err = tcgetattr(fd, &data->tt));
+ if(err)
+ return(err);
+
+ err = raw(fd);
+ if(err)
+ return(err);
}
*dev_out = data->dev;
* to write the data to disk first, then we can map the disk
* page in and continue normally from there.
*/
- if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer)){
+ if((rq_data_dir(req) == WRITE) && !is_remapped(req->buffer, dev->fd, io_req->offset + dev->cow.data_offset)){
io_req->map_fd = dev->fd;
io_req->map_offset = io_req->offset +
dev->cow.data_offset;
}
static int ubd_check_remapped(int fd, unsigned long address, int is_write,
- __u64 offset)
+ __u64 offset, int is_user)
{
__u64 bitmap_offset;
unsigned long new_bitmap[2];
int i, err, n;
+ /* This can only fix kernelspace faults */
+ if(is_user)
+ return(0);
+
+ /* ubd-mmap is only enabled in skas mode */
+ if(CHOOSE_MODE(1, 0))
+ return(0);
+
/* If it's not a write access, we can't do anything about it */
if(!is_write)
return(0);
printk("Couldn't stat '%s', err = %d\n", from_cow, -err);
return(1);
}
- if((buf1.ust_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino))
+ if((buf1.ust_major == buf2.ust_major) &&
+ (buf1.ust_minor == buf2.ust_minor) &&
+ (buf1.ust_ino == buf2.ust_ino))
return(1);
printk("Backing file mismatch - \"%s\" requested,\n"
data_offset_out);
if(!err)
return(fd);
+
os_close_file(fd);
out:
return(err);
" are 'xterm=gnome-terminal,-t,-x'.\n\n"
);
+/* XXX This badly needs some cleaning up in the error paths */
int xterm_open(int input, int output, int primary, void *d, char **dev_out)
{
struct xterm_chan *data = d;
goto out;
}
- tcgetattr(new, &data->tt);
- if(data->raw) raw(new, 0);
+ CATCH_EINTR(err = tcgetattr(new, &data->tt));
+ if(err){
+ new = err;
+ goto out;
+ }
+
+ if(data->raw){
+ err = raw(new);
+ if(err){
+ new = err;
+ goto out;
+ }
+ }
data->pid = pid;
*dev_out = NULL;
ENTRY(_start)
jiffies = jiffies_64;
-SEARCH_DIR("/usr/local/i686-pc-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib");
-/* Do we need any of these for elf?
- __DYNAMIC = 0; */
SECTIONS
{
. = START + SIZEOF_HEADERS;
#define __uml_postsetup_call __attribute__ ((unused,__section__ (".uml.postsetup.init")))
#define __uml_exit_call __attribute__ ((unused,__section__ (".uml.exitcall.exit")))
+#ifndef __KERNEL__
+
+#define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn
+#define __exitcall(fn) static exitcall_t __exitcall_##fn __exit_call = fn
+
+#define __init_call __attribute__ ((unused,__section__ (".initcall.init")))
+#define __exit_call __attribute__ ((unused,__section__ (".exitcall.exit")))
+
+#endif
+
#endif /* _LINUX_UML_INIT_H */
/*
extern void free_irq_by_fd(int fd);
extern void reactivate_fd(int fd, int irqnum);
extern void deactivate_fd(int fd, int irqnum);
+extern int deactivate_all_fds(void);
extern void forward_interrupts(int pid);
extern void init_irq_signals(int on_sigstack);
extern void forward_ipi(int fd, int pid);
extern int phys_mapping(unsigned long phys, __u64 *offset_out);
extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
-extern int is_remapped(void *virt);
+extern int is_remapped(const void *virt, int fd, __u64 offset);
extern int physmem_remove_mapping(void *virt);
extern void physmem_forget_descriptor(int fd);
struct remapper {
struct list_head list;
- int (*proc)(int, unsigned long, int, __u64);
+ int (*proc)(int, unsigned long, int, __u64, int);
};
extern void register_remapper(struct remapper *info);
* (if they are wrong here, they are wrong there...).
*/
struct uml_stat {
- int ust_dev; /* device */
+ int ust_major; /* device */
+ int ust_minor;
unsigned long long ust_ino; /* inode */
int ust_mode; /* protection */
int ust_nlink; /* number of hard links */
unsigned long ust_atime; /* time of last access */
unsigned long ust_mtime; /* time of last modification */
unsigned long ust_ctime; /* time of last change */
+ int ust_rmajor;
+ int ust_rminor;
};
struct openflags {
unsigned int a : 1; /* O_APPEND */
unsigned int e : 1; /* O_EXCL */
unsigned int cl : 1; /* FD_CLOEXEC */
+ unsigned int d : 1; /* O_DIRECT */
};
#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \
- .t = 0, .a = 0, .e = 0, .cl = 0 })
+ .t = 0, .a = 0, .e = 0, .cl = 0, \
+ .d = 0 })
static inline struct openflags of_read(struct openflags flags)
{
return(flags);
}
+static inline struct openflags of_direct(struct openflags flags)
+{
+ flags.d = 1;
+ return(flags);
+}
+
extern int os_stat_file(const char *file_name, struct uml_stat *buf);
+extern int os_lstat_file(const char *file_name, struct uml_stat *ubuf);
extern int os_stat_fd(const int fd, struct uml_stat *buf);
extern int os_access(const char *file, int mode);
+extern int os_set_file_time(const char *file, unsigned long access,
+ unsigned long mod);
+extern int os_set_file_perms(const char *file, int mode);
+extern int os_set_file_owner(const char *file, int owner, int group);
extern void os_print_error(int error, const char* str);
extern int os_get_exec_close(int fd, int *close_on_exec);
extern int os_set_exec_close(int fd, int close_on_exec);
extern int os_seek_file(int fd, __u64 offset);
extern int os_open_file(char *file, struct openflags flags, int mode);
+extern void *os_open_dir(char *dir, int *err_out);
+extern int os_seek_dir(void *stream, unsigned long long pos);
+extern int os_read_dir(void *stream, unsigned long long *ino_out,
+ char **name_out);
+extern int os_tell_dir(void *stream);
+extern int os_close_dir(void *stream);
+extern int os_remove_file(const char *file);
+extern int os_move_file(const char *from, const char *to);
+extern int os_truncate_file(const char *file, unsigned long long len);
+extern int os_truncate_fd(int fd, unsigned long long len);
extern int os_read_file(int fd, void *buf, int len);
extern int os_write_file(int fd, const void *buf, int count);
extern int os_file_size(char *file, long long *size_out);
+extern int os_fd_size(int fd, long long *size_out);
extern int os_file_modtime(char *file, unsigned long *modtime);
extern int os_pipe(int *fd, int stream, int close_on_exec);
extern int os_set_fd_async(int fd, int owner);
+extern int os_clear_fd_async(int fd);
extern int os_set_fd_block(int fd, int blocking);
extern int os_accept_connection(int fd);
extern int os_create_unix_socket(char *file, int len, int close_on_exec);
+extern int os_make_symlink(const char *to, const char *from);
+extern int os_read_symlink(const char *file, char *buf, int size);
+extern int os_link_file(const char *to, const char *from);
+extern int os_make_dir(const char *dir, int mode);
+extern int os_remove_dir(const char *dir);
+extern int os_make_dev(const char *name, int mode, int major, int minor);
extern int os_shutdown_socket(int fd, int r, int w);
extern void os_close_file(int fd);
extern int os_rcv_fd(int fd, int *helper_pid_out);
int r, int w, int x);
extern int os_unmap_memory(void *addr, int len);
extern void os_flush_stdout(void);
+extern int os_stat_filesystem(char *path, long *bsize_out,
+ long long *blocks_out, long long *bfree_out,
+ long long *bavail_out, long long *files_out,
+ long long *ffree_out, void *fsid_out,
+ int fsid_size, long *namelen_out,
+ long *spare_out);
+extern unsigned long long os_usecs(void);
#endif
extern void set_interval(int timer_type);
extern void idle_sleep(int secs);
extern void enable_timer(void);
+extern void disable_timer(void);
extern unsigned long time_lock(void);
extern void time_unlock(unsigned long);
extern int in_aton(char *str);
extern int open_gdb_chan(void);
extern int strlcpy(char *, const char *, int);
+extern void *um_vmalloc(int size);
+extern void vfree(void *ptr);
#endif
#include "sysdep/ptrace.h"
+#define CATCH_EINTR(expr) while (((expr) < 0) && (errno == EINTR))
+
extern int mode_tt;
extern int grantpt(int __fd);
extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
extern int get_pty(void);
extern void *um_kmalloc(int size);
-extern int raw(int fd, int complain);
extern int switcheroo(int fd, int prot, void *from, void *to, int size);
extern void setup_machinename(char *machine_out);
extern void setup_hostinfo(void);
extern void tracer_panic(char *msg, ...);
extern char *get_umid(int only_if_set);
extern void do_longjmp(void *p, int val);
-extern void suspend_new_thread(int fd);
extern int detach(int pid, int sig);
extern int attach(int pid);
extern void kill_child_dead(int pid);
extern void forward_pending_sigio(int target);
extern int can_do_skas(void);
extern void arch_init_thread(void);
+extern int setjmp_wrapper(void (*proc)(void *, void *), ...);
+extern int raw(int fd);
#endif
extra-y := vmlinux.lds.s
-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 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
+# Descend into ../util for make clean. This is here because it doesn't work
+# in arch/um/Makefile.
+
+subdir- = ../util
+
+obj-y = checksum.o config.o exec_kern.o exitcode.o filehandle.o frame_kern.o \
+ frame.o helper.o init_task.o irq.o irq_user.o ksyms.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
obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
obj-$(CONFIG_GPROF) += gprof_syms.o
#include "sysdep/sigcontext.h"
#include "frame_user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "ptrace_user.h"
#include "os.h"
/* Wait for it to stop itself and continue it with a SIGUSR1 to force
* it into the signal handler.
*/
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0){
printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1);
* At this point, the handler has stuffed the addresses of
* sig, sc, and SA_RESTORER in raw.
*/
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0){
printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1);
errno);
exit(1);
}
- if(waitpid(pid, &status, 0) < 0){
+ CATCH_EINTR(n = waitpid(pid, &status, 0));
+ if(n < 0){
printf("capture_stack : waitpid failed - errno = %d\n", errno);
exit(1);
}
#include <sys/wait.h>
#include "user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "os.h"
struct helper_data {
if(n < 0){
printk("run_helper : read on pipe failed, err = %d\n", -n);
err = n;
- goto out_kill;
+ os_kill_process(pid, 1);
}
else if(n != 0){
- waitpid(pid, NULL, 0);
+ CATCH_EINTR(n = waitpid(pid, NULL, 0));
pid = -errno;
}
+ err = pid;
- if(stack_out == NULL) free_stack(stack, 0);
- else *stack_out = stack;
- return(pid);
-
- out_kill:
- os_kill_process(pid, 1);
out_close:
os_close_file(fds[0]);
- os_close_file(fds[1]);
out_free:
- free_stack(stack, 0);
+ if(stack_out == NULL)
+ free_stack(stack, 0);
+ else *stack_out = stack;
return(err);
}
irq_unlock(flags);
}
+int deactivate_all_fds(void)
+{
+ struct irq_fd *irq;
+ int err;
+
+ for(irq=active_fds;irq != NULL;irq = irq->next){
+ err = os_clear_fd_async(irq->fd);
+ if(err)
+ return(err);
+ }
+
+ return(0);
+}
+
void forward_ipi(int fd, int pid)
{
int err;
EXPORT_SYMBOL(find_iomem);
#ifdef CONFIG_MODE_TT
+EXPORT_SYMBOL(strncpy_from_user_tt);
EXPORT_SYMBOL(copy_from_user_tt);
EXPORT_SYMBOL(copy_to_user_tt);
#endif
#ifdef CONFIG_MODE_SKAS
+EXPORT_SYMBOL(strncpy_from_user_skas);
EXPORT_SYMBOL(copy_to_user_skas);
EXPORT_SYMBOL(copy_from_user_skas);
#endif
EXPORT_SYMBOL(os_create_unix_socket);
EXPORT_SYMBOL(os_connect_socket);
EXPORT_SYMBOL(os_accept_connection);
+EXPORT_SYMBOL(os_ioctl_generic);
EXPORT_SYMBOL(os_rcv_fd);
EXPORT_SYMBOL(run_helper);
EXPORT_SYMBOL(start_thread);
struct iomem_region *new;
struct uml_stat buf;
char *file, *driver;
- int fd, err;
+ int fd, err, size;
driver = str;
file = strchr(str,',');
goto out_close;
}
+ size = (buf.ust_size + UM_KERN_PAGE_SIZE) & ~(UM_KERN_PAGE_SIZE - 1);
+
*new = ((struct iomem_region) { .next = iomem_regions,
.driver = driver,
.fd = fd,
- .size = buf.ust_size,
+ .size = size,
.phys = 0,
.virt = 0 });
iomem_regions = new;
return(0);
}
+#if 0
+/* Debugging facility for dumping stuff out to the host, avoiding the timing
+ * problems that come with printf and breakpoints.
+ * Enable in case of emergency.
+ */
+
+int logging = 1;
+int logging_fd = -1;
+
+int logging_line = 0;
+char logging_buf[512];
+
+void log(char *fmt, ...)
+{
+ va_list ap;
+ struct timeval tv;
+ struct openflags flags;
+
+ if(logging == 0) return;
+ if(logging_fd < 0){
+ flags = of_create(of_trunc(of_rdwr(OPENFLAGS())));
+ logging_fd = os_open_file("log", flags, 0644);
+ }
+ gettimeofday(&tv, NULL);
+ sprintf(logging_buf, "%d\t %u.%u ", logging_line++, tv.tv_sec,
+ tv.tv_usec);
+ va_start(ap, fmt);
+ vsprintf(&logging_buf[strlen(logging_buf)], fmt, ap);
+ va_end(ap);
+ write(logging_fd, logging_buf, strlen(logging_buf));
+}
+#endif
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
unsigned long phys;
int err;
+ phys = __pa(virt);
+ desc = find_virtmem_hash(&virtmem_hash, (void *) virt);
+ if(desc != NULL){
+ if((virt != desc->virt) || (fd != desc->fd) ||
+ (offset != desc->offset))
+ panic("Address 0x%p is already substituted\n", virt);
+ return(0);
+ }
+
fd_maps = descriptor_mapping(fd);
if(fd_maps == NULL)
return(-ENOMEM);
- phys = __pa(virt);
- if(find_virtmem_hash(&virtmem_hash, virt) != NULL)
- panic("Address 0x%p is already substituted\n", virt);
-
err = -ENOMEM;
desc = kmalloc(sizeof(*desc), GFP_ATOMIC);
if(desc == NULL)
if(desc == NULL)
return;
+ if(!list_empty(&desc->pages))
+ printk("Still have mapped pages on fd %d\n", fd);
+
list_for_each_safe(ele, next, &desc->pages){
page = list_entry(ele, struct phys_desc, list);
offset = page->offset;
}
}
-int is_remapped(void *virt)
+int is_remapped(const void *virt, int fd, __u64 offset)
{
- return(find_virtmem_hash(&virtmem_hash, virt) != NULL);
+ struct phys_desc *desc;
+
+ desc = find_virtmem_hash(&virtmem_hash, (void *) virt);
+ if(desc == NULL)
+ return(0);
+ if(offset != desc->offset)
+ printk("offset mismatch\n");
+ return(find_virtmem_hash(&virtmem_hash, (void *) virt) != NULL);
}
/* Changed during early boot */
int flags = 0, pages;
if(sig_stack != NULL){
- pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2;
+ pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER);
set_sigstack(sig_stack, pages * page_size());
flags = SA_ONSTACK;
}
{
int flags = altstack ? SA_ONSTACK : 0;
- /* NODEFER is set here because SEGV isn't turned back on when the
- * handler is ready to receive signals. This causes any segfault
- * during a copy_user to kill the process because the fault is blocked.
- */
- set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER,
+ set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags,
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags,
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags,
SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
set_handler(SIGUSR2, (__sighandler_t) sig_handler,
- SA_NOMASK | flags, -1);
+ flags, SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1);
signal(SIGHUP, SIG_IGN);
init_irq_signals(altstack);
/* Start the process and wait for it to kill itself */
new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg);
- if(new_pid < 0) return(-errno);
- while(((err = waitpid(new_pid, &status, 0)) < 0) && (errno == EINTR)) ;
- if(err < 0) panic("Waiting for outer trampoline failed - errno = %d",
- errno);
+ if(new_pid < 0)
+ return(new_pid);
+
+ CATCH_EINTR(err = waitpid(new_pid, &status, 0));
+ if(err < 0)
+ panic("Waiting for outer trampoline failed - errno = %d",
+ errno);
+
if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL))
panic("outer trampoline didn't exit with SIGKILL, "
"status = %d", status);
return(arg.pid);
}
-void suspend_new_thread(int fd)
-{
- char c;
-
- os_stop_process(os_getpid());
-
- if(os_read_file(fd, &c, sizeof(c)) != sizeof(c))
- panic("read failed in suspend_new_thread");
-}
-
static int ptrace_child(void *arg)
{
int pid = os_getpid();
pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL);
if(pid < 0)
panic("check_ptrace : clone failed, errno = %d", errno);
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("check_ptrace : wait failed, errno = %d", errno);
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d", errno);
- n = waitpid(pid, &status, 0);
+ CATCH_EINTR(n = waitpid(pid, &status, 0));
if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode))
panic("check_ptrace : child exited with status 0x%x", status);
if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
panic("check_ptrace : ptrace failed, errno = %d",
errno);
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("check_ptrace : wait failed, errno = %d", errno);
if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr)
{
- jmp_buf buf;
+ sigjmp_buf buf;
int n;
*jmp_ptr = &buf;
#include "linux/module.h"
#include "linux/init.h"
#include "linux/capability.h"
+#include "linux/vmalloc.h"
#include "linux/spinlock.h"
#include "asm/unistd.h"
#include "asm/mman.h"
struct pt_regs *regs)
{
p->thread = (struct thread_struct) INIT_THREAD;
- p->thread.kernel_stack =
- (unsigned long) p->thread_info + 2 * PAGE_SIZE;
return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr,
clone_flags, sp, stack_top, p, regs));
}
return(kmalloc(size, GFP_ATOMIC));
}
+void *um_vmalloc(int size)
+{
+ return(vmalloc(size));
+}
+
unsigned long get_fault_addr(void)
{
return((unsigned long) current->thread.fault_addr);
unsigned long stack;
stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER);
- stack += 2 * PAGE_SIZE;
- return(stack != current->thread.kernel_stack);
+ return(stack != (unsigned long) current_thread);
}
extern void remove_umid_dir(void);
/* Protected by sigio_lock() called from write_sigio_workaround */
static int sigio_irq_fd = -1;
-irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
+static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
{
read_sigio_fd(sigio_irq_fd);
reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ);
int write_sigio_irq(int fd)
{
- if(um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
- SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio",
- NULL)){
- printk("write_sigio_irq : um_request_irq failed\n");
+ int err;
+
+ err = um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt,
+ SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio",
+ NULL);
+ if(err){
+ printk("write_sigio_irq : um_request_irq failed, err = %d\n",
+ err);
return(-1);
}
sigio_irq_fd = fd;
#include "init.h"
#include "user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "sigio.h"
#include "helper.h"
#include "os.h"
void __init check_one_sigio(void (*proc)(int, int))
{
struct sigaction old, new;
- struct termios tt;
struct openpty_arg pty = { .master = -1, .slave = -1 };
int master, slave, err;
return;
}
- /* XXX These can fail with EINTR */
- if(tcgetattr(master, &tt) < 0)
- panic("check_sigio : tcgetattr failed, errno = %d\n", errno);
- cfmakeraw(&tt);
- if(tcsetattr(master, TCSADRAIN, &tt) < 0)
- panic("check_sigio : tcsetattr failed, errno = %d\n", errno);
+ /* Not now, but complain so we now where we failed. */
+ err = raw(master);
+ if (err < 0)
+ panic("check_sigio : __raw failed, errno = %d\n", -err);
err = os_sigio_async(master, slave);
if(err < 0)
#include <sys/ptrace.h>
#include "user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "os.h"
#include "time_user.h"
int user_thread(unsigned long stack, int flags)
{
- int pid, status;
+ int pid, status, err;
pid = clone(user_thread_tramp, (void *) stack_sp(stack),
flags | CLONE_FILES | SIGCHLD, NULL);
return(pid);
}
- if(waitpid(pid, &status, WUNTRACED) < 0){
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
+ if(err < 0){
printk("user_thread - waitpid failed, errno = %d\n", errno);
return(-errno);
}
#ifndef __MODE_SKAS_H__
#define __MODE_SKAS_H__
+#include <sysdep/ptrace.h>
+
extern unsigned long exec_regs[];
extern unsigned long exec_fp_regs[];
extern unsigned long exec_fpx_regs[];
panic("handle_trap - continuing to end of syscall failed, "
"errno = %d\n", errno);
- err = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
panic("handle_trap - failed to wait at end of syscall, "
"errno = %d, status = %d\n", errno, status);
panic("start_userspace : clone failed, errno = %d", errno);
do {
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("start_userspace : wait failed, errno = %d",
errno);
panic("userspace - PTRACE_SYSCALL failed, errno = %d\n",
errno);
while(1){
- err = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(err = waitpid(pid, &status, WUNTRACED));
if(err < 0)
panic("userspace - waitpid failed, errno = %d\n",
errno);
void (*handler)(int))
{
unsigned long flags;
- jmp_buf switch_buf, fork_buf;
+ sigjmp_buf switch_buf, fork_buf;
*switch_buf_ptr = &switch_buf;
*fork_buf_ptr = &fork_buf;
void thread_wait(void *sw, void *fb)
{
- jmp_buf buf, **switch_buf = sw, *fork_buf;
+ sigjmp_buf buf, **switch_buf = sw, *fork_buf;
*switch_buf = &buf;
fork_buf = fb;
void switch_threads(void *me, void *next)
{
- jmp_buf my_buf, **me_ptr = me, *next_buf = next;
+ sigjmp_buf my_buf, **me_ptr = me, *next_buf = next;
*me_ptr = &my_buf;
if(sigsetjmp(my_buf, 1) == 0)
siglongjmp(*next_buf, 1);
}
-static jmp_buf initial_jmpbuf;
+static sigjmp_buf initial_jmpbuf;
/* XXX Make these percpu */
static void (*cb_proc)(void *arg);
static void *cb_arg;
-static jmp_buf *cb_back;
+static sigjmp_buf *cb_back;
int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
{
- jmp_buf **switch_buf = switch_buf_ptr;
+ sigjmp_buf **switch_buf = switch_buf_ptr;
int n;
*fork_buf_ptr = &initial_jmpbuf;
void initial_thread_cb_skas(void (*proc)(void *), void *arg)
{
- jmp_buf here;
+ sigjmp_buf here;
cb_proc = proc;
cb_arg = arg;
siglongjmp(initial_jmpbuf, 4);
}
-int new_mm(int from)
-{
- struct proc_mm_op copy;
- int n, fd = os_open_file("/proc/mm",
- of_cloexec(of_write(OPENFLAGS())), 0);
-
- if(fd < 0)
- return(fd);
-
- if(from != -1){
- copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
- .u =
- { .copy_segments = from } } );
- n = os_write_file(fd, ©, sizeof(copy));
- if(n != sizeof(copy))
- printk("new_mm : /proc/mm copy_segments failed, "
- "err = %d\n", -n);
- }
-
- return(fd);
-}
-
void switch_mm_skas(int mm_fd)
{
int err;
#include "frame.h"
#include "kern.h"
#include "mode.h"
+#include "filehandle.h"
+#include "proc_mm.h"
int singlestepping_skas(void)
{
handler = new_thread_handler;
}
- new_thread((void *) p->thread.kernel_stack,
- &p->thread.mode.skas.switch_buf,
+ new_thread(p->thread_info, &p->thread.mode.skas.switch_buf,
&p->thread.mode.skas.fork_buf, handler);
return(0);
}
+int new_mm(int from)
+{
+ struct proc_mm_op copy;
+ int n, fd;
+
+ fd = open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
+ if(fd < 0)
+ return(fd);
+
+ if(from != -1){
+ copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS,
+ .u =
+ { .copy_segments = from } } );
+ n = os_write_file(fd, ©, sizeof(copy));
+ if(n != sizeof(copy))
+ printk("new_mm : /proc/mm copy_segments failed, "
+ "err = %d\n", -n);
+ }
+
+ return(fd);
+}
+
void init_idle_skas(void)
{
cpu_tasks[current_thread->cpu].pid = os_getpid();
{
start_userspace(0);
capture_signal_stack();
- uml_idle_timer();
init_new_thread_signals(1);
+ uml_idle_timer();
init_task.thread.request.u.thread.proc = start_kernel_proc;
init_task.thread.request.u.thread.arg = NULL;
- return(start_idle_thread((void *) init_task.thread.kernel_stack,
+ return(start_idle_thread(init_task.thread_info,
&init_task.thread.mode.skas.switch_buf,
&init_task.thread.mode.skas.fork_buf));
}
struct skas_regs *r;
struct signal_info *info;
int save_errno = errno;
+ int save_user;
r = &TASK_REGS(get_current())->skas;
+ save_user = r->is_user;
r->is_user = 0;
r->fault_addr = SC_FAULT_ADDR(sc);
r->fault_type = SC_FAULT_TYPE(sc);
(*info->handler)(sig, (union uml_pt_regs *) r);
errno = save_errno;
+ r->is_user = save_user;
}
void user_signal(int sig, union uml_pt_regs *regs)
#include "asm/pgtable.h"
#include "asm/uaccess.h"
#include "kern_util.h"
+#include "user_util.h"
extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
pte_t *pte_out);
int dummy_code;
if(IS_ERR(phys) || (is_write && !pte_write(pte))){
- err = handle_page_fault(virt, 0, is_write, 0, &dummy_code);
+ err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
if(err)
return(0);
phys = um_virt_to_phys(current, virt, NULL);
return(n);
}
-static int buffer_op(unsigned long addr, int len, int is_write,
- int (*op)(unsigned long addr, int len, void *arg),
- void *arg)
+static void do_buffer_op(void *jmpbuf, void *arg_ptr)
{
+ va_list args = *((va_list *) arg_ptr);
+ unsigned long addr = va_arg(args, unsigned long);
+ int len = va_arg(args, int);
+ int is_write = va_arg(args, int);
+ int (*op)(unsigned long, int, void *) = va_arg(args, void *);
+ void *arg = va_arg(args, void *);
+ int *res = va_arg(args, int *);
int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
int remain = len, n;
+ current->thread.fault_catcher = jmpbuf;
n = do_op(addr, size, is_write, op, arg);
- if(n != 0)
- return(n < 0 ? remain : 0);
+ if(n != 0){
+ *res = (n < 0 ? remain : 0);
+ goto out;
+ }
addr += size;
remain -= size;
- if(remain == 0)
- return(0);
+ if(remain == 0){
+ *res = 0;
+ goto out;
+ }
while(addr < ((addr + remain) & PAGE_MASK)){
n = do_op(addr, PAGE_SIZE, is_write, op, arg);
- if(n != 0)
- return(n < 0 ? remain : 0);
+ if(n != 0){
+ *res = (n < 0 ? remain : 0);
+ goto out;
+ }
addr += PAGE_SIZE;
remain -= PAGE_SIZE;
}
- if(remain == 0)
- return(0);
+ if(remain == 0){
+ *res = 0;
+ goto out;
+ }
n = do_op(addr, remain, is_write, op, arg);
if(n != 0)
- return(n < 0 ? remain : 0);
- return(0);
+ *res = (n < 0 ? remain : 0);
+ else *res = 0;
+ out:
+ current->thread.fault_catcher = NULL;
+}
+
+static int buffer_op(unsigned long addr, int len, int is_write,
+ int (*op)(unsigned long addr, int len, void *arg),
+ void *arg)
+{
+ int faulted, res;
+
+ faulted = setjmp_wrapper(do_buffer_op, addr, len, is_write, op, arg,
+ &res);
+ if(!faulted)
+ return(res);
+
+ return(addr + len - (unsigned long) current->thread.fault_addr);
}
static int copy_chunk_from_user(unsigned long from, int len, void *arg)
*/
struct cpuinfo_um cpu_data[NR_CPUS];
-spinlock_t um_bh_lock = SPIN_LOCK_UNLOCKED;
-
-atomic_t global_bh_count;
-
-/* Not used by UML */
-unsigned char global_irq_holder = NO_PROC_ID;
-unsigned volatile long global_irq_lock;
-
/* Set when the idlers are all forked */
int smp_threads_ready = 0;
num_reschedules_sent++;
}
-static void show(char * str)
-{
- int cpu = smp_processor_id();
-
- printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu);
-}
-
-#define MAXCOUNT 100000000
-
-static inline void wait_on_bh(void)
-{
- int count = MAXCOUNT;
- do {
- if (!--count) {
- show("wait_on_bh");
- count = ~0;
- }
- /* nothing .. wait for the other bh's to go away */
- } while (atomic_read(&global_bh_count) != 0);
-}
-
-/*
- * This is called when we want to synchronize with
- * bottom half handlers. We need to wait until
- * no other CPU is executing any bottom half handler.
- *
- * Don't wait if we're already running in an interrupt
- * context or are inside a bh handler.
- */
-void synchronize_bh(void)
-{
- if (atomic_read(&global_bh_count) && !in_interrupt())
- wait_on_bh();
-}
-
void smp_send_stop(void)
{
int i;
.task = new_task } );
idle_threads[cpu] = new_task;
CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c,
- sizeof(c)),
- ({ panic("skas mode doesn't support SMP"); }));
+ sizeof(c)),
wake_up_forked_process(new_task);
return(new_task);
}
errno);
}
+void disable_timer(void)
+{
+ struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
+ if((setitimer(ITIMER_VIRTUAL, &disable, NULL) < 0) ||
+ (setitimer(ITIMER_REAL, &disable, NULL) < 0))
+ printk("disnable_timer - setitimer failed, errno = %d\n",
+ errno);
+}
+
void switch_timers(int to_real)
{
struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});
set_interval(ITIMER_REAL);
}
-static unsigned long long get_host_hz(void)
-{
- char mhzline[16], *end;
- unsigned long long mhz;
- int ret, mult, rest, len;
-
- ret = cpu_feature("cpu MHz", mhzline,
- sizeof(mhzline) / sizeof(mhzline[0]));
- if(!ret)
- panic ("Could not get host MHZ");
-
- mhz = strtoul(mhzline, &end, 10);
-
- /* This business is to parse a floating point number without using
- * floating types.
- */
-
- rest = 0;
- mult = 0;
- if(*end == '.'){
- end++;
- len = strlen(end);
- if(len < 6)
- mult = 6 - len;
- else if(len > 6)
- end[6] = '\0';
- rest = strtoul(end, NULL, 10);
- while(mult-- > 0)
- rest *= 10;
- }
-
- return(1000000 * mhz + rest);
-}
-
-unsigned long long host_hz = 0;
-
extern int do_posix_clock_monotonic_gettime(struct timespec *tp);
void time_init(void)
{
struct timespec now;
- host_hz = get_host_hz();
if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR)
panic("Couldn't set SIGVTALRM handler");
set_interval(ITIMER_VIRTUAL);
#include "user_util.h"
#include "time_user.h"
#include "mode.h"
+#include "os.h"
u64 jiffies_64;
int timer_irq_inited = 0;
static int first_tick;
-static unsigned long long prev_tsc;
+static unsigned long long prev_usecs;
static long long delta; /* Deviation per interval */
-extern unsigned long long host_hz;
+#define MILLION 1000000
void timer_irq(union uml_pt_regs *regs)
{
if(first_tick){
#if defined(CONFIG_UML_REAL_TIME_CLOCK)
- unsigned long long tsc;
/* We've had 1 tick */
- tsc = time_stamp();
+ unsigned long long usecs = os_usecs();
- delta += tsc - prev_tsc;
- prev_tsc = tsc;
+ delta += usecs - prev_usecs;
+ prev_usecs = usecs;
- ticks += (delta * HZ) / host_hz;
- delta -= (ticks * host_hz) / HZ;
+ /* Protect against the host clock being set backwards */
+ if(delta < 0)
+ delta = 0;
+
+ ticks += (delta * HZ) / MILLION;
+ delta -= (ticks * MILLION) / HZ;
#else
ticks = 1;
#endif
}
else {
- prev_tsc = time_stamp();
+ prev_usecs = os_usecs();
first_tick = 1;
}
{
int i, n;
- n = (loops_per_jiffy * HZ * usecs) / 1000000;
+ n = (loops_per_jiffy * HZ * usecs) / MILLION;
for(i=0;i<n;i++) ;
}
{
int i, n;
- n = (loops_per_jiffy * HZ * usecs) / 1000000;
+ n = (loops_per_jiffy * HZ * usecs) / MILLION;
for(i=0;i<n;i++) ;
}
err = -ENOMEM;
goto out_of_memory;
default:
- if (current->pid == 1) {
- up_read(&mm->mmap_sem);
- yield();
- down_read(&mm->mmap_sem);
- goto survive;
- }
- goto out;
+ BUG();
}
pte = pte_offset_kernel(pmd, page);
} while(!pte_present(*pte));
down_read(&mm->mmap_sem);
goto survive;
}
- err = -ENOMEM;
goto out;
}
list_add(&info->list, &physmem_remappers);
}
-static int check_remapped_addr(unsigned long address, int is_write)
+static int check_remapped_addr(unsigned long address, int is_write, int is_user)
{
struct remapper *remapper;
struct list_head *ele;
list_for_each(ele, &physmem_remappers){
remapper = list_entry(ele, struct remapper, list);
- if((*remapper->proc)(fd, address, is_write, offset))
+ if((*remapper->proc)(fd, address, is_write, offset, is_user))
return(1);
}
flush_tlb_kernel_vm();
return(0);
}
- else if(check_remapped_addr(address & PAGE_MASK, is_write))
+ else if(check_remapped_addr(address & PAGE_MASK, is_write, is_user))
return(0);
else if(current->mm == NULL)
panic("Segfault with no mm");
{
kill(pid, SIGKILL);
kill(pid, SIGCONT);
- while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT);
+ do {
+ int n;
+ CATCH_EINTR(n = waitpid(pid, NULL, 0));
+ if (n > 0)
+ kill(pid, SIGCONT);
+ else
+ break;
+ } while(1);
}
/* Unlocked - don't care if this is a bit off */
void do_longjmp(void *b, int val)
{
- jmp_buf *buf = b;
+ sigjmp_buf *buf = b;
siglongjmp(*buf, val);
}
#include "kern_util.h"
#include "irq_user.h"
#include "time_user.h"
+#include "signal_user.h"
#include "mem_user.h"
#include "os.h"
#include "tlb.h"
do_exit(SIGKILL);
}
- new_pid = start_fork_tramp((void *) current->thread.kernel_stack,
- stack, 0, exec_tramp);
+ new_pid = start_fork_tramp(current->thread_info, stack, 0, exec_tramp);
if(new_pid < 0){
printk(KERN_ERR
"flush_thread : new thread failed, errno = %d\n",
current->thread.request.u.exec.pid = new_pid;
unprotect_stack((unsigned long) current_thread);
os_usr1_process(os_getpid());
+ change_sig(SIGUSR1, 1);
+ change_sig(SIGUSR1, 0);
enable_timer();
free_page(stack);
protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1);
void do_exec(int old_pid, int new_pid)
{
unsigned long regs[FRAME_SIZE];
+ int err;
if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) ||
- (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) ||
- (waitpid(new_pid, 0, WUNTRACED) < 0))
+ (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0))
tracer_panic("do_exec failed to attach proc - errno = %d",
errno);
+ CATCH_EINTR(err = waitpid(new_pid, 0, WUNTRACED));
+ if (err < 0)
+ tracer_panic("do_exec failed to attach proc in waitpid - errno = %d",
+ errno);
+
if(ptrace_getregs(old_pid, regs) < 0)
tracer_panic("do_exec failed to get registers - errno = %d",
errno);
os_close_file(current->thread.mode.tt.switch_pipe[1]);
}
+void suspend_new_thread(int fd)
+{
+ int err;
+ char c;
+
+ os_stop_process(os_getpid());
+ err = os_read_file(fd, &c, sizeof(c));
+ if(err != sizeof(c))
+ panic("read failed in suspend_new_thread, err = %d", -err);
+}
+
void schedule_tail(task_t *prev);
static void new_thread_handler(int sig)
local_irq_enable();
if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf))
do_exit(0);
+
+ /* XXX No set_user_mode here because a newly execed process will
+ * immediately segfault on its non-existent IP, coming straight back
+ * to the signal handler, which will call set_user_mode on its way
+ * out. This should probably change since it's confusing.
+ */
}
static int new_thread_proc(void *stack)
local_irq_disable();
init_new_thread_stack(stack, new_thread_handler);
os_usr1_process(os_getpid());
+ change_sig(SIGUSR1, 1);
return(0);
}
init_new_thread_stack(stack, finish_fork_handler);
os_usr1_process(os_getpid());
+ change_sig(SIGUSR1, 1);
return(0);
}
err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1);
if(err < 0){
printk("copy_thread : pipe failed, err = %d\n", -err);
- return(err);
+ goto out;
}
stack = alloc_stack(0, 0);
clone_flags &= CLONE_VM;
p->thread.temp_stack = stack;
- new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack,
- clone_flags, tramp);
+ new_pid = start_fork_tramp(p->thread_info, stack, clone_flags, tramp);
if(new_pid < 0){
printk(KERN_ERR "copy_thread : clone failed - errno = %d\n",
-new_pid);
current->thread.request.op = OP_FORK;
current->thread.request.u.fork.pid = new_pid;
os_usr1_process(os_getpid());
- return(0);
+
+ /* Enable the signal and then disable it to ensure that it is handled
+ * here, and nowhere else.
+ */
+ change_sig(SIGUSR1, 1);
+
+ change_sig(SIGUSR1, 0);
+ err = 0;
+ out:
+ return(err);
}
void reboot_tt(void)
{
current->thread.request.op = OP_REBOOT;
os_usr1_process(os_getpid());
+ change_sig(SIGUSR1, 1);
}
void halt_tt(void)
{
current->thread.request.op = OP_HALT;
os_usr1_process(os_getpid());
+ change_sig(SIGUSR1, 1);
}
void kill_off_processes_tt(void)
current->thread.request.u.cb.proc = proc;
current->thread.request.u.cb.arg = arg;
os_usr1_process(os_getpid());
+ change_sig(SIGUSR1, 1);
+
+ change_sig(SIGUSR1, 0);
}
}
init_task.thread.mode.tt.extern_pid = pid;
err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1);
- if(err)
+ if(err)
panic("Can't create switch pipe for init_task, errno = %d",
-err);
}
void *sp;
int pages;
- pages = (1 << CONFIG_KERNEL_STACK_ORDER) - 2;
- sp = (void *) init_task.thread.kernel_stack + pages * PAGE_SIZE -
- sizeof(unsigned long);
+ pages = (1 << CONFIG_KERNEL_STACK_ORDER);
+ sp = (void *) ((unsigned long) init_task.thread_info) +
+ pages * PAGE_SIZE - sizeof(unsigned long);
return(tracer(start_kernel_proc, sp));
}
child_proxy(1, W_EXITCODE(0, 0));
while(debugger.waiting == 1){
- pid = waitpid(debugger.pid, &status, WUNTRACED);
+ CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
if(pid != debugger.pid){
printk("fake_child_exit - waitpid failed, "
"errno = %d\n", errno);
}
debugger_proxy(status, debugger.pid);
}
- pid = waitpid(debugger.pid, &status, WUNTRACED);
+ CATCH_EINTR(pid = waitpid(debugger.pid, &status, WUNTRACED));
if(pid != debugger.pid){
printk("fake_child_exit - waitpid failed, "
"errno = %d\n", errno);
printf("tracing thread pid = %d\n", tracing_pid);
pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc);
- n = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0){
printf("waitpid on idle thread failed, errno = %d\n", errno);
exit(1);
}
set_cmdline("(tracing thread)");
while(1){
- pid = waitpid(-1, &status, WUNTRACED);
+ CATCH_EINTR(pid = waitpid(-1, &status, WUNTRACED));
if(pid <= 0){
if(errno != ECHILD){
printf("wait failed - errno = %d\n", errno);
unprotect_kernel_mem();
+ /* This is done because to allow SIGSEGV to be delivered inside a SEGV
+ * handler. This can happen in copy_user, and if SEGV is disabled,
+ * the process will die.
+ */
+ if(sig == SIGSEGV)
+ change_sig(SIGSEGV, 1);
+
r = &TASK_REGS(get_current())->tt;
save_regs = *r;
is_user = user_context(SC_SP(sc));
if(sig != SIGUSR2)
r->syscall = -1;
- change_sig(SIGUSR1, 1);
info = &sig_info[sig];
if(!info->is_irq) unblock_signals();
if(is_user){
interrupt_end();
block_signals();
- change_sig(SIGUSR1, 0);
set_user_mode(NULL);
}
*r = save_regs;
struct tt_regs save = TASK_REGS(get_current())->tt;
int ret;
unsigned long *faddrp = (unsigned long *)fault_addr;
- jmp_buf jbuf;
+ sigjmp_buf jbuf;
*fault_catcher = &jbuf;
if(sigsetjmp(jbuf, 1) == 0)
printf("set_tty_log_fd - strtoul failed on '%s'\n", name);
tty_log_fd = -1;
}
+
+ *add = 0;
return 0;
}
{
unsigned long *faddrp = (unsigned long *) fault_addr, ret;
- jmp_buf jbuf;
+ sigjmp_buf jbuf;
*fault_catcher = &jbuf;
if(sigsetjmp(jbuf, 1) == 0){
(*op)(to, from, n);
#include "user_util.h"
#include "kern_util.h"
#include "kern.h"
-#include "mprot.h"
#include "mem_user.h"
#include "mem.h"
#include "umid.h"
int linux_main(int argc, char **argv)
{
- unsigned long avail;
+ unsigned long avail, diff;
unsigned long virtmem_size, max_physmem;
unsigned int i, add;
brk_start = (unsigned long) sbrk(0);
CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start);
+ /* Increase physical memory size for exec-shield users
+ so they actually get what they asked for. This should
+ add zero for non-exec shield users */
+
+ diff = UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
+ if(diff > 1024 * 1024){
+ printf("Adding %ld bytes to physical memory to account for "
+ "exec-shield gap\n", diff);
+ physmem_size += UML_ROUND_UP(brk_start) - UML_ROUND_UP(&_end);
+ }
uml_physmem = uml_start;
uml_postsetup();
- init_task.thread.kernel_stack = (unsigned long) &init_thread_info +
- 2 * PAGE_SIZE;
-
task_protections((unsigned long) &init_thread_info);
os_flush_stdout();
}
if(strlen(name) > UMID_LEN - 1)
- (*printer)("Unique machine name is being truncated to %s "
+ (*printer)("Unique machine name is being truncated to %d "
"characters\n", UMID_LEN);
strlcpy(umid, name, sizeof(umid));
static int __init set_umid_arg(char *name, int *add)
{
+ *add = 0;
return(set_umid(name, 0, printf));
}
static int __init set_uml_dir(char *name, int *add)
{
if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){
- uml_dir = malloc(strlen(name) + 1);
+ uml_dir = malloc(strlen(name) + 2);
if(uml_dir == NULL){
printf("Failed to malloc uml_dir - error = %d\n",
errno);
uml_dir = name;
+ /* Return 0 here because do_initcalls doesn't look at
+ * the return value.
+ */
return(0);
}
sprintf(uml_dir, "%s/", name);
}
else uml_dir = name;
- return 0;
+ return(0);
}
static int __init make_uml_dir(void)
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
+#include <setjmp.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ptrace.h>
int status, ret;
while(1){
- ret = waitpid(pid, &status, WUNTRACED);
+ CATCH_EINTR(ret = waitpid(pid, &status, WUNTRACED));
if((ret < 0) ||
!WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){
if(ret < 0){
- if(errno == EINTR) continue;
printk("wait failed, errno = %d\n",
errno);
}
else if(WIFEXITED(status))
- printk("process exited with status %d\n",
- WEXITSTATUS(status));
+ printk("process %d exited with status %d\n",
+ pid, WEXITSTATUS(status));
else if(WIFSIGNALED(status))
- printk("process exited with signal %d\n",
- WTERMSIG(status));
+ printk("process %d exited with signal %d\n",
+ pid, WTERMSIG(status));
else if((WSTOPSIG(status) == SIGVTALRM) ||
(WSTOPSIG(status) == SIGALRM) ||
(WSTOPSIG(status) == SIGIO) ||
ptrace(cont_type, pid, 0, WSTOPSIG(status));
continue;
}
- else printk("process stopped with signal %d\n",
- WSTOPSIG(status));
+ else printk("process %d stopped with signal %d\n",
+ pid, WSTOPSIG(status));
panic("wait_for_stop failed to wait for %d to stop "
"with %d\n", pid, sig);
}
}
}
-int raw(int fd, int complain)
+int raw(int fd)
{
struct termios tt;
int err;
- tcgetattr(fd, &tt);
+ CATCH_EINTR(err = tcgetattr(fd, &tt));
+ if (err < 0) {
+ printk("tcgetattr failed, errno = %d\n", errno);
+ return(-errno);
+ }
+
cfmakeraw(&tt);
- err = tcsetattr(fd, TCSANOW, &tt);
- if((err < 0) && complain){
+
+ CATCH_EINTR(err = tcsetattr(fd, TCSADRAIN, &tt));
+ if (err < 0) {
printk("tcsetattr failed, errno = %d\n", errno);
return(-errno);
}
+
+ /* XXX tcsetattr could have applied only some changes
+ * (and cfmakeraw() is a set of changes) */
return(0);
}
host.release, host.version, host.machine);
}
+int setjmp_wrapper(void (*proc)(void *, void *), ...)
+{
+ va_list args;
+ sigjmp_buf buf;
+ int n;
+
+ n = sigsetjmp(buf, 1);
+ if(n == 0){
+ va_start(args, proc);
+ (*proc)(&buf, &args);
+ }
+ va_end(args);
+ return(n);
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
#include "kern_util.h"
#include "mem_user.h"
#include "signal_user.h"
+#include "time_user.h"
+#include "irq_user.h"
#include "user.h"
#include "init.h"
#include "mode.h"
/* Reboot */
if(ret){
+ int err;
+
printf("\n");
+
+ /* Let any pending signals fire, then disable them. This
+ * ensures that they won't be delivered after the exec, when
+ * they are definitely not expected.
+ */
+ unblock_signals();
+ disable_timer();
+ err = deactivate_all_fds();
+ if(err)
+ printf("deactivate_all_fds failed, errno = %d\n", -err);
+
execvp(new_argv[0], new_argv);
perror("Failed to exec kernel");
ret = 1;
void *__wrap_malloc(int size)
{
- if(CAN_KMALLOC())
- return(um_kmalloc(size));
- else
+ void *ret;
+
+ if(!CAN_KMALLOC())
return(__real_malloc(size));
+ else if(size <= PAGE_SIZE) /* finding contiguos pages is hard */
+ ret = um_kmalloc(size);
+ else ret = um_vmalloc(size);
+
+ /* glibc people insist that if malloc fails, errno should be
+ * set by malloc as well. So we do.
+ */
+ if(ret == NULL)
+ errno = ENOMEM;
+
+ return(ret);
}
void *__wrap_calloc(int n, int size)
extern void __real_free(void *);
+extern unsigned long high_physmem;
+
void __wrap_free(void *ptr)
{
- if(CAN_KMALLOC()) kfree(ptr);
+ unsigned long addr = (unsigned long) ptr;
+
+ /* We need to know how the allocation happened, so it can be correctly
+ * freed. This is done by seeing what region of memory the pointer is
+ * in -
+ * physical memory - kmalloc/kfree
+ * kernel virtual memory - vmalloc/vfree
+ * anywhere else - malloc/free
+ * If kmalloc is not yet possible, then the kernel memory regions
+ * may not be set up yet, and the variables not set up. So,
+ * free is called.
+ *
+ * CAN_KMALLOC is checked because it would be bad to free a buffer
+ * with kmalloc/vmalloc after they have been turned off during
+ * shutdown.
+ */
+
+ if((addr >= uml_physmem) && (addr < high_physmem)){
+ if(CAN_KMALLOC())
+ kfree(ptr);
+ }
+ else if((addr >= start_vm) && (addr < end_vm)){
+ if(CAN_KMALLOC())
+ vfree(ptr);
+ }
else __real_free(ptr);
}
# Licensed under the GPL
#
-obj-y = file.o process.o tty.o user_syms.o drivers/
+obj-y = aio.o file.o process.o time.o tty.o user_syms.o drivers/
-USER_OBJS := $(foreach file,file.o process.o tty.o,$(obj)/$(file))
+USER_OBJS := $(foreach file,aio.o file.o process.o time.o tty.o,$(obj)/$(file))
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+
+HAVE_AIO_ABI = $(shell [ -e /usr/include/linux/aio_abi.h ] && \
+ echo -DHAVE_AIO_ABI)
+HAVE_AIO_LIBC = $(shell objdump -T /lib/libc-*.so | grep io_submit && \
+ echo -DHAVE_AIO_LIBC)
+CFLAGS_aio.o = $(HAVE_AIO_ABI) $(HAVE_AIO_LIBC)
#include <net/if.h>
#include "user.h"
#include "kern_util.h"
+#include "user_util.h"
#include "net_user.h"
#include "etap.h"
#include "helper.h"
if(c != 1){
printk("etap_tramp : uml_net failed\n");
err = -EINVAL;
- if(waitpid(pid, &status, 0) < 0)
+ CATCH_EINTR(n = waitpid(pid, &status, 0));
+ if(n < 0)
err = -errno;
else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
printk("uml_net didn't exit with status 1\n");
#include "net_user.h"
#include "tuntap.h"
#include "kern_util.h"
+#include "user_util.h"
#include "user.h"
#include "helper.h"
#include "os.h"
errno);
return(-errno);
}
- waitpid(pid, NULL, 0);
+ CATCH_EINTR(waitpid(pid, NULL, 0));
cmsg = CMSG_FIRSTHDR(&msg);
if(cmsg == NULL){
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
+#include <utime.h>
+#include <dirent.h>
+#include <linux/kdev_t.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/mount.h>
#include <sys/uio.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
#include "os.h"
#include "user.h"
#include "kern_util.h"
static void copy_stat(struct uml_stat *dst, struct stat64 *src)
{
*dst = ((struct uml_stat) {
- .ust_dev = src->st_dev, /* device */
+ .ust_major = MAJOR(src->st_dev), /* device */
+ .ust_minor = MINOR(src->st_dev),
.ust_ino = src->st_ino, /* inode */
.ust_mode = src->st_mode, /* protection */
.ust_nlink = src->st_nlink, /* number of hard links */
.ust_atime = src->st_atime, /* time of last access */
.ust_mtime = src->st_mtime, /* time of last modification */
.ust_ctime = src->st_ctime, /* time of last change */
+ .ust_rmajor = MAJOR(src->st_rdev),
+ .ust_rminor = MINOR(src->st_rdev),
});
}
return(err);
}
-int os_access(const char* file, int mode)
+int os_lstat_file(const char *file_name, struct uml_stat *ubuf)
+{
+ struct stat64 sbuf;
+ int err;
+
+ do {
+ err = lstat64(file_name, &sbuf);
+ } while((err < 0) && (errno == EINTR)) ;
+
+ if(err < 0)
+ return(-errno);
+
+ if(ubuf != NULL)
+ copy_stat(ubuf, &sbuf);
+ return(err);
+}
+
+int os_access(const char *file, int mode)
{
int amode, err;
- amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
- (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
+ amode=(mode& OS_ACC_R_OK ? R_OK : 0) | (mode& OS_ACC_W_OK ? W_OK : 0) |
+ (mode& OS_ACC_X_OK ? X_OK : 0) | (mode& OS_ACC_F_OK ? F_OK : 0) ;
err = access(file, amode);
if(err < 0)
return(0);
}
+int os_set_file_time(const char *file, unsigned long access, unsigned long mod)
+{
+ struct utimbuf buf = ((struct utimbuf){ .actime = access,
+ .modtime = mod });
+ int err;
+
+ err = utime(file, &buf);
+ if(err < 0)
+ return(-errno);
+
+ return(0);
+}
+
+int os_set_file_perms(const char *file, int mode)
+{
+ int err;
+
+ err = chmod(file, mode);
+ if(err < 0)
+ return(-errno);
+
+ return(0);
+}
+
+int os_set_file_owner(const char *file, int owner, int group)
+{
+ int err;
+
+ err = chown(file, owner, group);
+ if(err < 0)
+ return(-errno);
+
+ return(0);
+}
+
void os_print_error(int error, const char* str)
{
errno = error < 0 ? -error : error;
if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
(fcntl(master, F_SETOWN, os_getpid()) < 0)){
- printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno);
+ printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n",
+ errno);
return(-errno);
}
struct uml_stat buf;
int err;
- err = os_stat_file(file, &buf);
+ err = os_lstat_file(file, &buf);
if(err < 0)
return(err);
if(flags.c) f |= O_CREAT;
if(flags.t) f |= O_TRUNC;
if(flags.e) f |= O_EXCL;
+ if(flags.d) f |= O_DIRECT;
fd = open64(file, f, mode);
if(fd < 0)
return(fd);
}
+void *os_open_dir(char *path, int *err_out)
+{
+ void *dir;
+
+ dir = opendir(path);
+ *err_out = -errno;
+ return(dir);
+}
+
+int os_seek_dir(void *stream, unsigned long long pos)
+{
+ seekdir(stream, pos);
+ return(0);
+}
+
+int os_read_dir(void *stream, unsigned long long *ino_out, char **name_out)
+{
+ struct dirent *ent;
+
+ errno = 0;
+ ent = readdir(stream);
+ if(ent == NULL){
+ if(errno != 0)
+ return(-errno);
+ *name_out = NULL;
+ return(0);
+ }
+
+ *ino_out = ent->d_ino;
+ *name_out = ent->d_name;
+ return(0);
+}
+
+int os_tell_dir(void *stream)
+{
+ return(telldir(stream));
+}
+
+int os_close_dir(void *stream)
+{
+ int err;
+
+ err = closedir(stream);
+ if(err < 0)
+ return(-errno);
+ return(0);
+}
+
+int os_remove_file(const char *file)
+{
+ int err;
+
+ err = unlink(file);
+ if(err)
+ return(-errno);
+
+ return(0);
+}
+
+int os_move_file(const char *from, const char *to)
+{
+ int err;
+
+ err = rename(from, to);
+ if(err)
+ return(-errno);
+
+ return(0);
+}
+
+int os_truncate_fd(int fd, unsigned long long len)
+{
+ int err;
+
+ err = ftruncate(fd, len);
+ if(err)
+ return(-errno);
+ return(0);
+}
+
+int os_truncate_file(const char *file, unsigned long long len)
+{
+ int err;
+
+ err = truncate(file, len);
+ if(err)
+ return(-errno);
+ return(0);
+}
+
int os_connect_socket(char *name)
{
struct sockaddr_un sock;
__u64 actual;
actual = lseek64(fd, offset, SEEK_SET);
- if(actual != offset) return(-errno);
+ if(actual != offset)
+ return(-errno);
return(0);
}
return(0);
}
+int os_fd_size(int fd, long long *size_out)
+{
+ struct stat buf;
+ int err;
+
+ err = fstat(fd, &buf);
+ if(err)
+ return(-errno);
+
+ *size_out = buf.st_size;
+ return(0);
+}
+
int os_file_modtime(char *file, unsigned long *modtime)
{
struct uml_stat buf;
return(0);
}
+int os_clear_fd_async(int fd)
+{
+ int flags = fcntl(fd, F_GETFL);
+
+ flags &= ~(O_ASYNC | O_NONBLOCK);
+ if(fcntl(fd, F_SETFL, flags) < 0)
+ return(-errno);
+ return(0);
+}
+
int os_set_fd_block(int fd, int blocking)
{
int flags;
return(sock);
}
+int os_make_symlink(const char *to, const char *from)
+{
+ int err;
+
+ err = symlink(to, from);
+ if(err)
+ return(-errno);
+
+ return(0);
+}
+
+int os_read_symlink(const char *file, char *buf, int size)
+{
+ int err;
+
+ err = readlink(file, buf, size);
+ if(err < 0)
+ return(-errno);
+
+ return(err);
+}
+
+int os_link_file(const char *to, const char *from)
+{
+ int err;
+
+ err = link(to, from);
+ if(err)
+ return(-errno);
+
+ return(0);
+}
+
+int os_make_dir(const char *dir, int mode)
+{
+ int err;
+
+ err = mkdir(dir, mode);
+ if(err)
+ return(-errno);
+
+ return(0);
+}
+
+int os_make_dev(const char *name, int mode, int major, int minor)
+{
+ int err;
+
+ err = mknod(name, mode, MKDEV(major, minor));
+ if(err)
+ return(-errno);
+
+ return(0);
+}
+
+int os_remove_dir(const char *dir)
+{
+ int err;
+
+ err = rmdir(dir);
+ if(err)
+ return(-errno);
+
+ return(0);
+}
+
void os_flush_stdout(void)
{
fflush(stdout);
return(err);
}
+int os_stat_filesystem(char *path, long *bsize_out, long long *blocks_out,
+ long long *bfree_out, long long *bavail_out,
+ long long *files_out, long long *ffree_out,
+ void *fsid_out, int fsid_size, long *namelen_out,
+ long *spare_out)
+{
+ struct statfs64 buf;
+ int err;
+
+ err = statfs64(path, &buf);
+ if(err < 0)
+ return(-errno);
+
+ *bsize_out = buf.f_bsize;
+ *blocks_out = buf.f_blocks;
+ *bfree_out = buf.f_bfree;
+ *bavail_out = buf.f_bavail;
+ *files_out = buf.f_files;
+ *ffree_out = buf.f_ffree;
+ memcpy(fsid_out, &buf.f_fsid,
+ sizeof(buf.f_fsid) > fsid_size ? fsid_size :
+ sizeof(buf.f_fsid));
+ *namelen_out = buf.f_namelen;
+ spare_out[0] = buf.f_spare[0];
+ spare_out[1] = buf.f_spare[1];
+ spare_out[2] = buf.f_spare[2];
+ spare_out[3] = buf.f_spare[3];
+ spare_out[4] = buf.f_spare[4];
+ spare_out[5] = buf.f_spare[5];
+ return(0);
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
#include <sys/wait.h>
#include "os.h"
#include "user.h"
+#include "user_util.h"
#define ARBITRARY_ADDR -1
#define FAILURE_PID -1
+#define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
+#define COMM_SCANF "%*[^)])"
+
unsigned long os_process_pc(int pid)
{
- char proc_stat[sizeof("/proc/#####/stat\0")], buf[256];
+ char proc_stat[STAT_PATH_LEN], buf[256];
unsigned long pc;
int fd, err;
}
os_close_file(fd);
pc = ARBITRARY_ADDR;
- if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d "
+ if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
"%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
- "%*d %*d %*d %*d %ld", &pc) != 1){
+ "%*d %*d %*d %*d %*d %lu", &pc) != 1){
printk("os_process_pc - couldn't find pc in '%s'\n", buf);
}
return(pc);
int os_process_parent(int pid)
{
- char stat[sizeof("/proc/nnnnn/stat\0")];
+ char stat[STAT_PATH_LEN];
char data[256];
int parent, n, fd;
}
parent = FAILURE_PID;
- /* XXX This will break if there is a space in the command */
- n = sscanf(data, "%*d %*s %*c %d", &parent);
+ n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
if(n != 1)
printk("Failed to scan '%s'\n", data);
{
kill(pid, SIGKILL);
if(reap_child)
- waitpid(pid, NULL, 0);
+ CATCH_EINTR(waitpid(pid, NULL, 0));
}
void os_usr1_process(int pid)
{
- syscall(__NR_tkill, pid, SIGUSR1);
- /* kill(pid, SIGUSR1); */
+ kill(pid, SIGUSR1);
}
int os_getpid(void)
obj-y = bugs.o checksum.o fault.o ksyms.o ldt.o ptrace.o ptrace_user.o \
- semaphore.o sigcontext.o syscalls.o sysrq.o time.o
+ semaphore.o sigcontext.o syscalls.o sysrq.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_MODULES) += module.o
int arch_handle_signal(int sig, union uml_pt_regs *regs)
{
- unsigned long ip;
+ unsigned char tmp[2];
/* This is testing for a cmov (0x0f 0x4x) instruction causing a
* SIGILL in init.
*/
if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0);
- ip = UPT_IP(regs);
- if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40))
+ if (copy_from_user_proc(tmp, (void *) UPT_IP(regs), 2))
+ panic("SIGILL in init, could not read instructions!\n");
+ if((tmp[0] != 0x0f) || ((tmp[1] & 0xf0) != 0x40))
return(0);
if(host_has_cmov == 0)
#ifdef CONFIG_MODE_TT
extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
+/* XXX this needs copy_to_user and copy_from_user */
+
int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
{
if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT);
if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i],
regs[i]) < 0)
printk("write_debugregs - ptrace failed on "
- "register %d, errno = %d\n", errno);
+ "register %d, value = 0x%x, errno = %d\n", i,
+ regs[i], errno);
}
}
HOSTCFLAGS_mk_task_kern.o := $(CFLAGS) $(CPPFLAGS)
HOSTCFLAGS_mk_constants_kern.o := $(CFLAGS) $(CPPFLAGS)
+
+clean:
+ $(RM) -f $(host-progs)
obj-$(CONFIG_XFS_FS) += xfs/
obj-$(CONFIG_AFS_FS) += afs/
obj-$(CONFIG_BEFS_FS) += befs/
-obj-$(CONFIG_HOSTFS) += hostfs/
-obj-$(CONFIG_HPPFS) += hppfs/
+obj-$(CONFIG_EXTERNFS) += hostfs/
# Licensed under the GPL
#
-# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino
-# to __st_ino. It stayed in the same place, so as long as the correct name
-# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa.
-
-STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \
- echo __)st_ino
-
-hostfs-objs := hostfs_kern.o hostfs_user.o
-
obj-y =
-obj-$(CONFIG_HOSTFS) += hostfs.o
+obj-$(CONFIG_EXTERNFS) += externfs.o
+obj-$(CONFIG_HOSTFS) += host_fs.o host_file.o
+obj-$(CONFIG_HUMFS) += humfs.o meta_fs.o
SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs))
USER_OBJS := $(filter %_user.o,$(obj-y) $(obj-m) $(SINGLE_OBJS))
USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
-USER_CFLAGS += -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD)
-
$(USER_OBJS) : %.o: %.c
$(CC) $(CFLAGS_$(notdir $@)) $(USER_CFLAGS) -c -o $@ $<
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
#ifndef __UM_FS_HOSTFS
#define __UM_FS_HOSTFS
+#include "linux/fs.h"
+#include "filehandle.h"
#include "os.h"
/* These are exactly the same definitions as in fs.h, but the names are
* changed so that this file can be included in both kernel and user files.
*/
-#define HOSTFS_ATTR_MODE 1
-#define HOSTFS_ATTR_UID 2
-#define HOSTFS_ATTR_GID 4
-#define HOSTFS_ATTR_SIZE 8
-#define HOSTFS_ATTR_ATIME 16
-#define HOSTFS_ATTR_MTIME 32
-#define HOSTFS_ATTR_CTIME 64
-#define HOSTFS_ATTR_ATIME_SET 128
-#define HOSTFS_ATTR_MTIME_SET 256
-#define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */
-#define HOSTFS_ATTR_ATTR_FLAG 1024
-
-struct hostfs_iattr {
+#define EXTERNFS_ATTR_MODE 1
+#define EXTERNFS_ATTR_UID 2
+#define EXTERNFS_ATTR_GID 4
+#define EXTERNFS_ATTR_SIZE 8
+#define EXTERNFS_ATTR_ATIME 16
+#define EXTERNFS_ATTR_MTIME 32
+#define EXTERNFS_ATTR_CTIME 64
+#define EXTERNFS_ATTR_ATIME_SET 128
+#define EXTERNFS_ATTR_MTIME_SET 256
+#define EXTERNFS_ATTR_FORCE 512 /* Not a change, but a change it */
+#define EXTERNFS_ATTR_ATTR_FLAG 1024
+
+struct externfs_iattr {
unsigned int ia_valid;
mode_t ia_mode;
uid_t ia_uid;
gid_t ia_gid;
loff_t ia_size;
- struct timespec ia_atime;
- struct timespec ia_mtime;
- struct timespec ia_ctime;
+ time_t ia_atime;
+ time_t ia_mtime;
+ time_t ia_ctime;
unsigned int ia_attr_flags;
};
-extern int stat_file(const char *path, unsigned long long *inode_out,
- int *mode_out, int *nlink_out, int *uid_out, int *gid_out,
- unsigned long long *size_out, struct timespec *atime_out,
- struct timespec *mtime_out, struct timespec *ctime_out,
- int *blksize_out, unsigned long long *blocks_out);
-extern int access_file(char *path, int r, int w, int x);
-extern int open_file(char *path, int r, int w, int append);
-extern int file_type(const char *path, int *rdev);
-extern void *open_dir(char *path, int *err_out);
-extern char *read_dir(void *stream, unsigned long long *pos,
- unsigned long long *ino_out, int *len_out);
-extern void close_file(void *stream);
-extern void close_dir(void *stream);
-extern int read_file(int fd, unsigned long long *offset, char *buf, int len);
-extern int write_file(int fd, unsigned long long *offset, const char *buf,
- int len);
-extern int lseek_file(int fd, long long offset, int whence);
-extern int file_create(char *name, int ur, int uw, int ux, int gr,
- int gw, int gx, int or, int ow, int ox);
-extern int set_attr(const char *file, struct hostfs_iattr *attrs);
-extern int make_symlink(const char *from, const char *to);
-extern int unlink_file(const char *file);
-extern int do_mkdir(const char *file, int mode);
-extern int do_rmdir(const char *file);
-extern int do_mknod(const char *file, int mode, int dev);
-extern int link_file(const char *from, const char *to);
-extern int do_readlink(char *file, char *buf, int size);
-extern int rename_file(char *from, char *to);
-extern int do_statfs(char *root, long *bsize_out, long long *blocks_out,
- long long *bfree_out, long long *bavail_out,
- long long *files_out, long long *ffree_out,
- void *fsid_out, int fsid_size, long *namelen_out,
- long *spare_out);
+struct externfs_data {
+ struct externfs_file_ops *file_ops;
+ struct externfs_mount_ops *mount_ops;
+};
+
+struct externfs_inode {
+ struct inode vfs_inode;
+ struct externfs_file_ops *ops;
+};
+
+struct externfs_mount_ops {
+ struct externfs_data *(*mount)(char *mount_arg);
+ struct externfs_inode *(*init_file)(struct externfs_data *ed);
+};
+
+struct externfs_file_ops {
+ int (*stat_file)(const char *path, struct externfs_data *ed,
+ dev_t *dev_out, unsigned long long *inode_out,
+ int *mode_out, int *nlink_out, int *uid_out,
+ int *gid_out, unsigned long long *size_out,
+ unsigned long *atime_out, unsigned long *mtime_out,
+ unsigned long *ctime_out, int *blksize_out,
+ unsigned long long *blocks_out);
+ int (*file_type)(const char *path, int *rdev,
+ struct externfs_data *ed);
+ int (*access_file)(char *path, int r, int w, int x, int uid, int gid,
+ struct externfs_data *ed);
+ int (*open_file)(struct externfs_inode *ext, char *file,
+ int uid, int gid, struct inode *inode,
+ struct externfs_data *ed);
+ void (*close_file)(struct externfs_inode *ext,
+ unsigned long long size);
+ void *(*open_dir)(char *path, int uid, int gid,
+ struct externfs_data *ed);
+ char *(*read_dir)(void *stream, unsigned long long *pos,
+ unsigned long long *ino_out, int *len_out,
+ struct externfs_data *ed);
+ int (*read_file)(struct externfs_inode *ext,
+ unsigned long long offset, char *buf, int len,
+ int ignore_start, int ignore_end,
+ void (*completion)(char *, int, void *), void *arg,
+ struct externfs_data *ed);
+ int (*write_file)(struct externfs_inode *ext,
+ unsigned long long offset, const char *buf,
+ int start, int len,
+ void (*completion)(char *, int, void *), void *arg,
+ struct externfs_data *ed);
+ int (*map_file_page)(struct externfs_inode *ext,
+ unsigned long long offset, char *buf, int w,
+ struct externfs_data *ed);
+ void (*close_dir)(void *stream, struct externfs_data *ed);
+ void (*invisible)(struct externfs_inode *ext);
+ int (*create_file)(struct externfs_inode *ext, char *path,
+ int mode, int uid, int gid, struct inode *inode,
+ struct externfs_data *ed);
+ int (*set_attr)(const char *path, struct externfs_iattr *attrs,
+ struct externfs_data *ed);
+ int (*make_symlink)(const char *from, const char *to, int uid, int gid,
+ struct externfs_data *ed);
+ int (*unlink_file)(const char *path, struct externfs_data *ed);
+ int (*make_dir)(const char *path, int mode, int uid, int gid,
+ struct externfs_data *ed);
+ int (*remove_dir)(const char *path, int uid, int gid,
+ struct externfs_data *ed);
+ int (*make_node)(const char *path, int mode, int uid, int gid,
+ int type, int maj, int min, struct externfs_data *ed);
+ int (*link_file)(const char *to, const char *from, int uid, int gid,
+ struct externfs_data *ed);
+ int (*read_link)(char *path, int uid, int gid, char *buf, int size,
+ struct externfs_data *ed);
+ int (*rename_file)(char *from, char *to, struct externfs_data *ed);
+ int (*statfs)(long *bsize_out, long long *blocks_out,
+ long long *bfree_out, long long *bavail_out,
+ long long *files_out, long long *ffree_out,
+ void *fsid_out, int fsid_size, long *namelen_out,
+ long *spare_out, struct externfs_data *ed);
+ int (*truncate_file)(struct externfs_inode *ext, __u64 size,
+ struct externfs_data *ed);
+};
+
+#define HOSTFS_BUFSIZE 64
+
+extern int register_externfs(char *name, struct externfs_mount_ops *mount_ops);
+extern void unregister_externfs(char *name);
+extern void init_externfs(struct externfs_data *ed,
+ struct externfs_file_ops *ops);
+struct externfs_data *inode_externfs_info(struct inode *inode);
+
+extern char *generic_root_filename(char *mount_arg);
+extern void host_close_file(void *stream);
+extern int host_read_file(int fd, unsigned long long offset, char *buf,
+ int len);
+extern int host_open_file(const char *path[], int r, int w,
+ struct file_handle *fh);
+extern void *host_open_dir(const char *path[]);
+extern char *host_read_dir(void *stream, unsigned long long *pos,
+ unsigned long long *ino_out, int *len_out);
+extern int host_file_type(const char *path[], int *rdev);
+extern char *host_root_filename(char *mount_arg);
+extern char *get_path(const char *path[], char *buf, int size);
+extern void free_path(const char *buf, char *tmp);
+extern int host_create_file(const char *path[], int mode,
+ struct file_handle *fh);
+extern int host_set_attr(const char *path[], struct externfs_iattr *attrs);
+extern int host_make_symlink(const char *from[], const char *to);
+extern int host_unlink_file(const char *path[]);
+extern int host_make_dir(const char *path[], int mode);
+extern int host_remove_dir(const char *path[]);
+extern int host_link_file(const char *to[], const char *from[]);
+extern int host_read_link(const char *path[], char *buf, int size);
+extern int host_rename_file(const char *from[], const char *to[]);
+extern int host_stat_fs(const char *path[], long *bsize_out,
+ long long *blocks_out, long long *bfree_out,
+ long long *bavail_out, long long *files_out,
+ long long *ffree_out, void *fsid_out, int fsid_size,
+ long *namelen_out, long *spare_out);
+extern int host_stat_file(const char *path[], int *dev_out,
+ unsigned long long *inode_out, int *mode_out,
+ int *nlink_out, int *uid_out, int *gid_out,
+ unsigned long long *size_out,
+ unsigned long *atime_out, unsigned long *mtime_out,
+ unsigned long *ctime_out, int *blksize_out,
+ unsigned long long *blocks_out);
+
+extern char *generic_host_read_dir(void *stream, unsigned long long *pos,
+ unsigned long long *ino_out, int *len_out,
+ void *mount);
+extern int generic_host_read_file(int fd, unsigned long long offset, char *buf,
+ int len, void *mount);
+extern void generic_host_close_file(void *stream, unsigned long long size,
+ void *mount);
+extern int generic_host_truncate_file(struct file_handle *fh, __u64 size,
+ void *m);
+
+extern char *inode_name_prefix(struct inode *inode, char *prefix);
#endif
} \
} while (0)
-extern int foo;
-
#endif
#endif
#define SIGIO_WRITE_IRQ 11
#define TELNETD_IRQ 12
#define XTERM_IRQ 13
-
-#define LAST_IRQ XTERM_IRQ
+#define HUMFS_IRQ 14
+
+#define LAST_IRQ HUMFS_IRQ
#define NR_IRQS (LAST_IRQ + 1)
#endif
/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2000 - 2004 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
struct thread_struct {
int forking;
- unsigned long kernel_stack;
int nsyscalls;
struct pt_regs regs;
unsigned long cr2;
#define INIT_THREAD \
{ \
.forking = 0, \
- .kernel_stack = 0, \
.nsyscalls = 0, \
.regs = EMPTY_REGS, \
.cr2 = 0, \