mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
merge?
This commit is contained in:
commit
4ebbde31e7
33 files changed
+3627
-744
No files matched your search
@@ -31,16 +31,18 @@ TARGET := mini-os
|
||||
OBJS := $(TARGET_ARCH).o
|
||||
OBJS += $(patsubst %.c,%.o,$(wildcard *.c))
|
||||
OBJS += $(patsubst %.c,%.o,$(wildcard lib/*.c))
|
||||
|
||||
OBJS += $(patsubst %.c,%.o,$(wildcard xenbus/*.c))
|
||||
|
||||
HDRS := $(wildcard include/*.h)
|
||||
HDRS += $(wildcard include/xen/*.h)
|
||||
|
||||
default: $(TARGET)
|
||||
|
||||
xen-public:
|
||||
links:
|
||||
[ -e include/xen ] || ln -sf ../../../xen/include/public include/xen
|
||||
|
||||
$(TARGET): xen-public $(OBJS)
|
||||
[ -e xenbus/xenstored.h ] || ln -sf ../../../tools/xenstore/xenstored.h xenbus/xenstored.h
|
||||
|
||||
$(TARGET): links $(OBJS)
|
||||
$(LD) -N -T minios-$(TARGET_ARCH).lds $(OBJS) -o $@.elf
|
||||
gzip -f -9 -c $@.elf >$@.gz
|
||||
|
||||
@@ -55,3 +57,4 @@ clean:
|
||||
%.o: %.S $(HDRS) Makefile
|
||||
$(CC) $(CFLAGS) -D__ASSEMBLY__ -c $< -o $@
|
||||
|
||||
|
||||
+20
-18
@@ -17,13 +17,13 @@
|
||||
*/
|
||||
|
||||
#include <os.h>
|
||||
#include <mm.h>
|
||||
#include <hypervisor.h>
|
||||
#include <events.h>
|
||||
#include <lib.h>
|
||||
|
||||
#include <xen/event_channel.h>
|
||||
static ev_action_t ev_actions[NR_EVS];
|
||||
void default_handler(u32 port, struct pt_regs *regs);
|
||||
void default_handler(int port, struct pt_regs *regs);
|
||||
|
||||
|
||||
/*
|
||||
@@ -32,7 +32,6 @@ void default_handler(u32 port, struct pt_regs *regs);
|
||||
int do_event(u32 port, struct pt_regs *regs)
|
||||
{
|
||||
ev_action_t *action;
|
||||
|
||||
if (port >= NR_EVS) {
|
||||
printk("Port number too large: %d\n", port);
|
||||
return 0;
|
||||
@@ -57,11 +56,23 @@ int do_event(u32 port, struct pt_regs *regs)
|
||||
|
||||
}
|
||||
|
||||
void bind_evtchn( u32 port, void (*handler)(int, struct pt_regs *) )
|
||||
{
|
||||
if(ev_actions[port].handler)
|
||||
printk("WARN: Handler for port %d already registered, replacing\n",
|
||||
port);
|
||||
|
||||
ev_actions[port].handler = handler;
|
||||
ev_actions[port].status &= ~EVS_DISABLED;
|
||||
|
||||
/* Finally unmask the port */
|
||||
unmask_evtchn(port);
|
||||
}
|
||||
|
||||
int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *) )
|
||||
{
|
||||
evtchn_op_t op;
|
||||
int ret = 0;
|
||||
u32 port;
|
||||
|
||||
/* Try to bind the virq to a port */
|
||||
op.cmd = EVTCHNOP_bind_virq;
|
||||
@@ -73,22 +84,13 @@ int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *) )
|
||||
printk("Failed to bind virtual IRQ %d\n", virq);
|
||||
goto out;
|
||||
}
|
||||
|
||||
port = op.u.bind_virq.port;
|
||||
|
||||
if(ev_actions[port].handler)
|
||||
printk("WARN: Handler for port %d already registered, replacing\n",
|
||||
port);
|
||||
|
||||
ev_actions[port].handler = handler;
|
||||
ev_actions[port].status &= ~EVS_DISABLED;
|
||||
|
||||
/* Finally unmask the port */
|
||||
unmask_evtchn(port);
|
||||
bind_evtchn(op.u.bind_virq.port, handler);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Initially all events are without a handler and disabled
|
||||
*/
|
||||
@@ -100,10 +102,10 @@ void init_events(void)
|
||||
for ( i = 0; i < NR_EVS; i++ )
|
||||
{
|
||||
ev_actions[i].status = EVS_DISABLED;
|
||||
ev_actions[i].handler = NULL;
|
||||
ev_actions[i].handler = default_handler;
|
||||
}
|
||||
}
|
||||
|
||||
void default_handler(u32 port, struct pt_regs *regs) {
|
||||
void default_handler(int port, struct pt_regs *regs) {
|
||||
printk("[Port %d] - event received\n", port);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef _CTYPE_H
|
||||
#define _CTYPE_H
|
||||
|
||||
/*
|
||||
* NOTE! This ctype does not handle EOF like the standard C
|
||||
* library is required to.
|
||||
*/
|
||||
|
||||
#define _U 0x01 /* upper */
|
||||
#define _L 0x02 /* lower */
|
||||
#define _D 0x04 /* digit */
|
||||
#define _C 0x08 /* cntrl */
|
||||
#define _P 0x10 /* punct */
|
||||
#define _S 0x20 /* white space (space/lf/tab) */
|
||||
#define _X 0x40 /* hex digit */
|
||||
#define _SP 0x80 /* hard space (0x20) */
|
||||
|
||||
|
||||
unsigned char _ctype[] = {
|
||||
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
|
||||
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
|
||||
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
|
||||
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
|
||||
_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
|
||||
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
|
||||
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
|
||||
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
|
||||
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
|
||||
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
|
||||
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
|
||||
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
|
||||
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
|
||||
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
|
||||
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
|
||||
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
|
||||
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
|
||||
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
|
||||
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
|
||||
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
|
||||
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
|
||||
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
|
||||
|
||||
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
|
||||
|
||||
#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
|
||||
#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
|
||||
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
|
||||
#define isdigit(c) ((__ismask(c)&(_D)) != 0)
|
||||
#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
|
||||
#define islower(c) ((__ismask(c)&(_L)) != 0)
|
||||
#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
|
||||
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
|
||||
#define isspace(c) ((__ismask(c)&(_S)) != 0)
|
||||
#define isupper(c) ((__ismask(c)&(_U)) != 0)
|
||||
#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
|
||||
|
||||
#define isascii(c) (((unsigned char)(c))<=0x7f)
|
||||
#define toascii(c) (((unsigned char)(c))&0x7f)
|
||||
|
||||
static inline unsigned char __tolower(unsigned char c)
|
||||
{
|
||||
if (isupper(c))
|
||||
c -= 'A'-'a';
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline unsigned char __toupper(unsigned char c)
|
||||
{
|
||||
if (islower(c))
|
||||
c -= 'a'-'A';
|
||||
return c;
|
||||
}
|
||||
|
||||
#define tolower(c) __tolower(c)
|
||||
#define toupper(c) __toupper(c)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef _ERR_H
|
||||
#define _ERR_H
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
/*
|
||||
* Kernel pointers have redundant information, so we can use a
|
||||
* scheme where we can return either an error code or a dentry
|
||||
* pointer with the same return value.
|
||||
*
|
||||
* This should be a per-architecture thing, to allow different
|
||||
* error and pointer decisions.
|
||||
*/
|
||||
#define IS_ERR_VALUE(x) ((x) > (unsigned long)-1000L)
|
||||
|
||||
static inline void *ERR_PTR(long error)
|
||||
{
|
||||
return (void *) error;
|
||||
}
|
||||
|
||||
static inline long PTR_ERR(const void *ptr)
|
||||
{
|
||||
return (long) ptr;
|
||||
}
|
||||
|
||||
static inline long IS_ERR(const void *ptr)
|
||||
{
|
||||
return IS_ERR_VALUE((unsigned long)ptr);
|
||||
}
|
||||
|
||||
#endif /* _LINUX_ERR_H */
|
||||
@@ -0,0 +1,39 @@
|
||||
#ifndef _ERRNO_BASE_H
|
||||
#define _ERRNO_BASE_H
|
||||
|
||||
#define EPERM 1 /* Operation not permitted */
|
||||
#define ENOENT 2 /* No such file or directory */
|
||||
#define ESRCH 3 /* No such process */
|
||||
#define EINTR 4 /* Interrupted system call */
|
||||
#define EIO 5 /* I/O error */
|
||||
#define ENXIO 6 /* No such device or address */
|
||||
#define E2BIG 7 /* Argument list too long */
|
||||
#define ENOEXEC 8 /* Exec format error */
|
||||
#define EBADF 9 /* Bad file number */
|
||||
#define ECHILD 10 /* No child processes */
|
||||
#define EAGAIN 11 /* Try again */
|
||||
#define ENOMEM 12 /* Out of memory */
|
||||
#define EACCES 13 /* Permission denied */
|
||||
#define EFAULT 14 /* Bad address */
|
||||
#define ENOTBLK 15 /* Block device required */
|
||||
#define EBUSY 16 /* Device or resource busy */
|
||||
#define EEXIST 17 /* File exists */
|
||||
#define EXDEV 18 /* Cross-device link */
|
||||
#define ENODEV 19 /* No such device */
|
||||
#define ENOTDIR 20 /* Not a directory */
|
||||
#define EISDIR 21 /* Is a directory */
|
||||
#define EINVAL 22 /* Invalid argument */
|
||||
#define ENFILE 23 /* File table overflow */
|
||||
#define EMFILE 24 /* Too many open files */
|
||||
#define ENOTTY 25 /* Not a typewriter */
|
||||
#define ETXTBSY 26 /* Text file busy */
|
||||
#define EFBIG 27 /* File too large */
|
||||
#define ENOSPC 28 /* No space left on device */
|
||||
#define ESPIPE 29 /* Illegal seek */
|
||||
#define EROFS 30 /* Read-only file system */
|
||||
#define EMLINK 31 /* Too many links */
|
||||
#define EPIPE 32 /* Broken pipe */
|
||||
#define EDOM 33 /* Math argument out of domain of func */
|
||||
#define ERANGE 34 /* Math result not representable */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
#ifndef _ERRNO_H
|
||||
#define _ERRNO_H
|
||||
|
||||
#include <errno-base.h>
|
||||
|
||||
#define EDEADLK 35 /* Resource deadlock would occur */
|
||||
#define ENAMETOOLONG 36 /* File name too long */
|
||||
#define ENOLCK 37 /* No record locks available */
|
||||
#define ENOSYS 38 /* Function not implemented */
|
||||
#define ENOTEMPTY 39 /* Directory not empty */
|
||||
#define ELOOP 40 /* Too many symbolic links encountered */
|
||||
#define EWOULDBLOCK EAGAIN /* Operation would block */
|
||||
#define ENOMSG 42 /* No message of desired type */
|
||||
#define EIDRM 43 /* Identifier removed */
|
||||
#define ECHRNG 44 /* Channel number out of range */
|
||||
#define EL2NSYNC 45 /* Level 2 not synchronized */
|
||||
#define EL3HLT 46 /* Level 3 halted */
|
||||
#define EL3RST 47 /* Level 3 reset */
|
||||
#define ELNRNG 48 /* Link number out of range */
|
||||
#define EUNATCH 49 /* Protocol driver not attached */
|
||||
#define ENOCSI 50 /* No CSI structure available */
|
||||
#define EL2HLT 51 /* Level 2 halted */
|
||||
#define EBADE 52 /* Invalid exchange */
|
||||
#define EBADR 53 /* Invalid request descriptor */
|
||||
#define EXFULL 54 /* Exchange full */
|
||||
#define ENOANO 55 /* No anode */
|
||||
#define EBADRQC 56 /* Invalid request code */
|
||||
#define EBADSLT 57 /* Invalid slot */
|
||||
|
||||
#define EDEADLOCK EDEADLK
|
||||
|
||||
#define EBFONT 59 /* Bad font file format */
|
||||
#define ENOSTR 60 /* Device not a stream */
|
||||
#define ENODATA 61 /* No data available */
|
||||
#define ETIME 62 /* Timer expired */
|
||||
#define ENOSR 63 /* Out of streams resources */
|
||||
#define ENONET 64 /* Machine is not on the network */
|
||||
#define ENOPKG 65 /* Package not installed */
|
||||
#define EREMOTE 66 /* Object is remote */
|
||||
#define ENOLINK 67 /* Link has been severed */
|
||||
#define EADV 68 /* Advertise error */
|
||||
#define ESRMNT 69 /* Srmount error */
|
||||
#define ECOMM 70 /* Communication error on send */
|
||||
#define EPROTO 71 /* Protocol error */
|
||||
#define EMULTIHOP 72 /* Multihop attempted */
|
||||
#define EDOTDOT 73 /* RFS specific error */
|
||||
#define EBADMSG 74 /* Not a data message */
|
||||
#define EOVERFLOW 75 /* Value too large for defined data type */
|
||||
#define ENOTUNIQ 76 /* Name not unique on network */
|
||||
#define EBADFD 77 /* File descriptor in bad state */
|
||||
#define EREMCHG 78 /* Remote address changed */
|
||||
#define ELIBACC 79 /* Can not access a needed shared library */
|
||||
#define ELIBBAD 80 /* Accessing a corrupted shared library */
|
||||
#define ELIBSCN 81 /* .lib section in a.out corrupted */
|
||||
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
|
||||
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
|
||||
#define EILSEQ 84 /* Illegal byte sequence */
|
||||
#define ERESTART 85 /* Interrupted system call should be restarted */
|
||||
#define ESTRPIPE 86 /* Streams pipe error */
|
||||
#define EUSERS 87 /* Too many users */
|
||||
#define ENOTSOCK 88 /* Socket operation on non-socket */
|
||||
#define EDESTADDRREQ 89 /* Destination address required */
|
||||
#define EMSGSIZE 90 /* Message too long */
|
||||
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
|
||||
#define ENOPROTOOPT 92 /* Protocol not available */
|
||||
#define EPROTONOSUPPORT 93 /* Protocol not supported */
|
||||
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
|
||||
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
|
||||
#define EPFNOSUPPORT 96 /* Protocol family not supported */
|
||||
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
|
||||
#define EADDRINUSE 98 /* Address already in use */
|
||||
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
|
||||
#define ENETDOWN 100 /* Network is down */
|
||||
#define ENETUNREACH 101 /* Network is unreachable */
|
||||
#define ENETRESET 102 /* Network dropped connection because of reset */
|
||||
#define ECONNABORTED 103 /* Software caused connection abort */
|
||||
#define ECONNRESET 104 /* Connection reset by peer */
|
||||
#define ENOBUFS 105 /* No buffer space available */
|
||||
#define EISCONN 106 /* Transport endpoint is already connected */
|
||||
#define ENOTCONN 107 /* Transport endpoint is not connected */
|
||||
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
|
||||
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
|
||||
#define ETIMEDOUT 110 /* Connection timed out */
|
||||
#define ECONNREFUSED 111 /* Connection refused */
|
||||
#define EHOSTDOWN 112 /* Host is down */
|
||||
#define EHOSTUNREACH 113 /* No route to host */
|
||||
#define EALREADY 114 /* Operation already in progress */
|
||||
#define EINPROGRESS 115 /* Operation now in progress */
|
||||
#define ESTALE 116 /* Stale NFS file handle */
|
||||
#define EUCLEAN 117 /* Structure needs cleaning */
|
||||
#define ENOTNAM 118 /* Not a XENIX named type file */
|
||||
#define ENAVAIL 119 /* No XENIX semaphores available */
|
||||
#define EISNAM 120 /* Is a named type file */
|
||||
#define EREMOTEIO 121 /* Remote I/O error */
|
||||
#define EDQUOT 122 /* Quota exceeded */
|
||||
|
||||
#define ENOMEDIUM 123 /* No medium found */
|
||||
#define EMEDIUMTYPE 124 /* Wrong medium type */
|
||||
#define ECANCELED 125 /* Operation Canceled */
|
||||
#define ENOKEY 126 /* Required key not available */
|
||||
#define EKEYEXPIRED 127 /* Key has expired */
|
||||
#define EKEYREVOKED 128 /* Key has been revoked */
|
||||
#define EKEYREJECTED 129 /* Key was rejected by service */
|
||||
|
||||
/* for robust mutexes */
|
||||
#define EOWNERDEAD 130 /* Owner died */
|
||||
#define ENOTRECOVERABLE 131 /* State not recoverable */
|
||||
|
||||
#endif
|
||||
@@ -20,6 +20,7 @@
|
||||
#define _EVENTS_H_
|
||||
|
||||
#include<traps.h>
|
||||
#include <xen/event_channel.h>
|
||||
|
||||
#define NR_EVS 1024
|
||||
|
||||
@@ -39,6 +40,16 @@ typedef struct _ev_action_t {
|
||||
/* prototypes */
|
||||
int do_event(u32 port, struct pt_regs *regs);
|
||||
int bind_virq( u32 virq, void (*handler)(int, struct pt_regs *) );
|
||||
void bind_evtchn( u32 virq, void (*handler)(int, struct pt_regs *) );
|
||||
void init_events(void);
|
||||
|
||||
static inline int notify_via_evtchn(int port)
|
||||
{
|
||||
evtchn_op_t op;
|
||||
op.cmd = EVTCHNOP_send;
|
||||
op.u.send.local_port = port;
|
||||
return HYPERVISOR_event_channel_op(&op);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _EVENTS_H_ */
|
||||
@@ -0,0 +1,89 @@
|
||||
#ifndef _I386_FCNTL_H
|
||||
#define _I386_FCNTL_H
|
||||
|
||||
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
|
||||
located on an ext2 file system */
|
||||
#define O_ACCMODE 0003
|
||||
#define O_RDONLY 00
|
||||
#define O_WRONLY 01
|
||||
#define O_RDWR 02
|
||||
#define O_CREAT 0100 /* not fcntl */
|
||||
#define O_EXCL 0200 /* not fcntl */
|
||||
#define O_NOCTTY 0400 /* not fcntl */
|
||||
#define O_TRUNC 01000 /* not fcntl */
|
||||
#define O_APPEND 02000
|
||||
#define O_NONBLOCK 04000
|
||||
#define O_NDELAY O_NONBLOCK
|
||||
#define O_SYNC 010000
|
||||
#define FASYNC 020000 /* fcntl, for BSD compatibility */
|
||||
#define O_DIRECT 040000 /* direct disk access hint */
|
||||
#define O_LARGEFILE 0100000
|
||||
#define O_DIRECTORY 0200000 /* must be a directory */
|
||||
#define O_NOFOLLOW 0400000 /* don't follow links */
|
||||
#define O_NOATIME 01000000
|
||||
|
||||
#define F_DUPFD 0 /* dup */
|
||||
#define F_GETFD 1 /* get close_on_exec */
|
||||
#define F_SETFD 2 /* set/clear close_on_exec */
|
||||
#define F_GETFL 3 /* get file->f_flags */
|
||||
#define F_SETFL 4 /* set file->f_flags */
|
||||
#define F_GETLK 5
|
||||
#define F_SETLK 6
|
||||
#define F_SETLKW 7
|
||||
|
||||
#define F_SETOWN 8 /* for sockets. */
|
||||
#define F_GETOWN 9 /* for sockets. */
|
||||
#define F_SETSIG 10 /* for sockets. */
|
||||
#define F_GETSIG 11 /* for sockets. */
|
||||
|
||||
#define F_GETLK64 12 /* using 'struct flock64' */
|
||||
#define F_SETLK64 13
|
||||
#define F_SETLKW64 14
|
||||
|
||||
/* for F_[GET|SET]FL */
|
||||
#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
|
||||
|
||||
/* for posix fcntl() and lockf() */
|
||||
#define F_RDLCK 0
|
||||
#define F_WRLCK 1
|
||||
#define F_UNLCK 2
|
||||
|
||||
/* for old implementation of bsd flock () */
|
||||
#define F_EXLCK 4 /* or 3 */
|
||||
#define F_SHLCK 8 /* or 4 */
|
||||
|
||||
/* for leases */
|
||||
#define F_INPROGRESS 16
|
||||
|
||||
/* operations for bsd flock(), also used by the kernel implementation */
|
||||
#define LOCK_SH 1 /* shared lock */
|
||||
#define LOCK_EX 2 /* exclusive lock */
|
||||
#define LOCK_NB 4 /* or'd with one of the above to prevent
|
||||
blocking */
|
||||
#define LOCK_UN 8 /* remove lock */
|
||||
|
||||
#define LOCK_MAND 32 /* This is a mandatory flock */
|
||||
#define LOCK_READ 64 /* ... Which allows concurrent read operations */
|
||||
#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */
|
||||
#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */
|
||||
|
||||
/*
|
||||
struct flock {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
off_t l_start;
|
||||
off_t l_len;
|
||||
pid_t l_pid;
|
||||
};
|
||||
|
||||
struct flock64 {
|
||||
short l_type;
|
||||
short l_whence;
|
||||
loff_t l_start;
|
||||
loff_t l_len;
|
||||
pid_t l_pid;
|
||||
};
|
||||
|
||||
#define F_LINUX_SPECIFIC_BASE 1024
|
||||
*/
|
||||
#endif
|
||||
@@ -13,7 +13,6 @@
|
||||
#define _HYPERVISOR_H_
|
||||
|
||||
#include <types.h>
|
||||
|
||||
#include <xen/xen.h>
|
||||
#include <xen/io/domain_controller.h>
|
||||
|
||||
@@ -40,48 +39,26 @@ void clear_evtchn(u32 port);
|
||||
/*
|
||||
* Assembler stubs for hyper-calls.
|
||||
*/
|
||||
|
||||
#ifdef __i386__
|
||||
#define _a1 "b"
|
||||
#define _a2 "c"
|
||||
#define _a3 "d"
|
||||
#define _a4 "S"
|
||||
#else
|
||||
#define _a1 "D"
|
||||
#define _a2 "S"
|
||||
#define _a3 "d"
|
||||
#define _a4 "b"
|
||||
#endif
|
||||
|
||||
static __inline__ int HYPERVISOR_event_channel_op(
|
||||
void *op)
|
||||
#if defined(__i386__)
|
||||
static inline int
|
||||
HYPERVISOR_set_trap_table(
|
||||
trap_info_t *table)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ignore;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ignore)
|
||||
: "0" (__HYPERVISOR_event_channel_op), "1" (op)
|
||||
: "0" (__HYPERVISOR_set_trap_table), "1" (table)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline__ int HYPERVISOR_set_trap_table(trap_info_t *table)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_set_trap_table),
|
||||
_a1 (table) : "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline__ int HYPERVISOR_mmu_update(mmu_update_t *req,
|
||||
int count,
|
||||
int *success_count,
|
||||
domid_t domid)
|
||||
static inline int
|
||||
HYPERVISOR_mmu_update(
|
||||
mmu_update_t *req, int count, int *success_count, domid_t domid)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3, ign4;
|
||||
@@ -89,18 +66,16 @@ static __inline__ int HYPERVISOR_mmu_update(mmu_update_t *req,
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4)
|
||||
: "0" (__HYPERVISOR_mmu_update), "1" (req), "2" (count),
|
||||
"3" (success_count), "4" (domid)
|
||||
: "memory" );
|
||||
: "0" (__HYPERVISOR_mmu_update), "1" (req), "2" (count),
|
||||
"3" (success_count), "4" (domid)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static __inline__ int HYPERVISOR_mmuext_op(struct mmuext_op *op,
|
||||
int count,
|
||||
int *success_count,
|
||||
domid_t domid)
|
||||
static inline int
|
||||
HYPERVISOR_mmuext_op(
|
||||
struct mmuext_op *op, int count, int *success_count, domid_t domid)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3, ign4;
|
||||
@@ -108,70 +83,65 @@ static __inline__ int HYPERVISOR_mmuext_op(struct mmuext_op *op,
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4)
|
||||
: "0" (__HYPERVISOR_mmuext_op), "1" (op), "2" (count),
|
||||
"3" (success_count), "4" (domid)
|
||||
: "memory" );
|
||||
: "0" (__HYPERVISOR_mmuext_op), "1" (op), "2" (count),
|
||||
"3" (success_count), "4" (domid)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static __inline__ int HYPERVISOR_set_gdt(unsigned long *frame_list, int entries)
|
||||
static inline int
|
||||
HYPERVISOR_set_gdt(
|
||||
unsigned long *frame_list, int entries)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_set_gdt),
|
||||
_a1 (frame_list), _a2 (entries) : "memory" );
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_set_gdt), "1" (frame_list), "2" (entries)
|
||||
: "memory" );
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline__ int HYPERVISOR_stack_switch(unsigned long ss, unsigned long esp)
|
||||
static inline int
|
||||
HYPERVISOR_stack_switch(
|
||||
unsigned long ss, unsigned long esp)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_stack_switch),
|
||||
_a1 (ss), _a2 (esp) : "memory" );
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_stack_switch), "1" (ss), "2" (esp)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
static __inline__ int HYPERVISOR_set_callbacks(
|
||||
static inline int
|
||||
HYPERVISOR_set_callbacks(
|
||||
unsigned long event_selector, unsigned long event_address,
|
||||
unsigned long failsafe_selector, unsigned long failsafe_address)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3, ign4;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_set_callbacks),
|
||||
_a1 (event_selector), _a2 (event_address),
|
||||
_a3 (failsafe_selector), _a4 (failsafe_address) : "memory" );
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4)
|
||||
: "0" (__HYPERVISOR_set_callbacks), "1" (event_selector),
|
||||
"2" (event_address), "3" (failsafe_selector), "4" (failsafe_address)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static __inline__ int HYPERVISOR_set_callbacks(
|
||||
unsigned long event_address,
|
||||
unsigned long failsafe_address,
|
||||
unsigned long syscall_address)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_set_callbacks),
|
||||
_a1 (event_address), _a2 (failsafe_address),
|
||||
_a3 (syscall_address) : "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static __inline__ int
|
||||
static inline int
|
||||
HYPERVISOR_fpu_taskswitch(
|
||||
int set)
|
||||
{
|
||||
@@ -187,67 +157,106 @@ HYPERVISOR_fpu_taskswitch(
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline__ int HYPERVISOR_yield(void)
|
||||
static inline int
|
||||
HYPERVISOR_yield(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
|
||||
_a1 (SCHEDOP_yield) : "memory" );
|
||||
: "=a" (ret), "=b" (ign)
|
||||
: "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_yield)
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline__ int HYPERVISOR_block(void)
|
||||
static inline int
|
||||
HYPERVISOR_block(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
|
||||
_a1 (SCHEDOP_block) : "memory" );
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op), "1" (SCHEDOP_block)
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline__ int HYPERVISOR_shutdown(void)
|
||||
static inline int
|
||||
HYPERVISOR_shutdown(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
|
||||
_a1 (SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift))
|
||||
: "memory" );
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift))
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline__ int HYPERVISOR_reboot(void)
|
||||
static inline int
|
||||
HYPERVISOR_reboot(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
|
||||
_a1 (SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift))
|
||||
: "memory" );
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift))
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __inline__ int HYPERVISOR_suspend(unsigned long srec)
|
||||
static inline int
|
||||
HYPERVISOR_suspend(
|
||||
unsigned long srec)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
|
||||
/* NB. On suspend, control software expects a suspend record in %esi. */
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" (__HYPERVISOR_sched_op),
|
||||
_a1 (SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift)),
|
||||
"S" (srec) : "memory" );
|
||||
: "=a" (ret), "=b" (ign1), "=S" (ign2)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"b" (SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift)),
|
||||
"S" (srec) : "memory", "ecx");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
static __inline__ long HYPERVISOR_set_timer_op( u64 timeout )
|
||||
static inline int
|
||||
HYPERVISOR_crash(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_shutdown | (SHUTDOWN_crash << SCHEDOP_reasonshift))
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long
|
||||
HYPERVISOR_set_timer_op(
|
||||
u64 timeout)
|
||||
{
|
||||
int ret;
|
||||
unsigned long timeout_hi = (unsigned long)(timeout>>32);
|
||||
@@ -262,8 +271,516 @@ static __inline__ long HYPERVISOR_set_timer_op( u64 timeout )
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline int
|
||||
HYPERVISOR_dom0_op(
|
||||
dom0_op_t *dom0_op)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1;
|
||||
|
||||
dom0_op->interface_version = DOM0_INTERFACE_VERSION;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_dom0_op), "1" (dom0_op)
|
||||
: "memory");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_set_debugreg(
|
||||
int reg, unsigned long value)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_set_debugreg), "1" (reg), "2" (value)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline unsigned long
|
||||
HYPERVISOR_get_debugreg(
|
||||
int reg)
|
||||
{
|
||||
unsigned long ret;
|
||||
unsigned long ign;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign)
|
||||
: "0" (__HYPERVISOR_get_debugreg), "1" (reg)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_descriptor(
|
||||
u64 ma, u64 desc)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3, ign4;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4)
|
||||
: "0" (__HYPERVISOR_update_descriptor),
|
||||
"1" ((unsigned long)ma), "2" ((unsigned long)(ma>>32)),
|
||||
"3" ((unsigned long)desc), "4" ((unsigned long)(desc>>32))
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_dom_mem_op(
|
||||
unsigned int op, unsigned long *extent_list,
|
||||
unsigned long nr_extents, unsigned int extent_order)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3, ign4, ign5;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4),
|
||||
"=D" (ign5)
|
||||
: "0" (__HYPERVISOR_dom_mem_op), "1" (op), "2" (extent_list),
|
||||
"3" (nr_extents), "4" (extent_order), "5" (DOMID_SELF)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_multicall(
|
||||
void *call_list, int nr_calls)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_multicall), "1" (call_list), "2" (nr_calls)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping(
|
||||
unsigned long va, pte_t new_val, unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3, ign4;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3), "=S" (ign4)
|
||||
: "0" (__HYPERVISOR_update_va_mapping),
|
||||
"1" (va), "2" ((new_val).pte_low),
|
||||
#ifdef CONFIG_X86_PAE
|
||||
"3" ((new_val).pte_high),
|
||||
#else
|
||||
static __inline__ long HYPERVISOR_set_timer_op( u64 timeout )
|
||||
"3" (0),
|
||||
#endif
|
||||
"4" (flags)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_event_channel_op(
|
||||
void *op)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ignore;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ignore)
|
||||
: "0" (__HYPERVISOR_event_channel_op), "1" (op)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_xen_version(
|
||||
int cmd)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ignore;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ignore)
|
||||
: "0" (__HYPERVISOR_xen_version), "1" (cmd)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_console_io(
|
||||
int cmd, int count, char *str)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3)
|
||||
: "0" (__HYPERVISOR_console_io), "1" (cmd), "2" (count), "3" (str)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_physdev_op(
|
||||
void *physdev_op)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign)
|
||||
: "0" (__HYPERVISOR_physdev_op), "1" (physdev_op)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_grant_table_op(
|
||||
unsigned int cmd, void *uop, unsigned int count)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3)
|
||||
: "0" (__HYPERVISOR_grant_table_op), "1" (cmd), "2" (uop), "3" (count)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_update_va_mapping_otherdomain(
|
||||
unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2, ign3, ign4, ign5;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2), "=d" (ign3),
|
||||
"=S" (ign4), "=D" (ign5)
|
||||
: "0" (__HYPERVISOR_update_va_mapping_otherdomain),
|
||||
"1" (va), "2" ((new_val).pte_low),
|
||||
#ifdef CONFIG_X86_PAE
|
||||
"3" ((new_val).pte_high),
|
||||
#else
|
||||
"3" (0),
|
||||
#endif
|
||||
"4" (flags), "5" (domid) :
|
||||
"memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_vm_assist(
|
||||
unsigned int cmd, unsigned int type)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_vm_assist), "1" (cmd), "2" (type)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_boot_vcpu(
|
||||
unsigned long vcpu, vcpu_guest_context_t *ctxt)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_boot_vcpu), "1" (vcpu), "2" (ctxt)
|
||||
: "memory");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_vcpu_down(
|
||||
int vcpu)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1;
|
||||
/* Yes, I really do want to clobber edx here: when we resume a
|
||||
vcpu after unpickling a multi-processor domain, it returns
|
||||
here, but clobbers all of the call clobbered registers. */
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_vcpu_down | (vcpu << SCHEDOP_vcpushift))
|
||||
: "memory", "ecx", "edx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_vcpu_up(
|
||||
int vcpu)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_vcpu_up | (vcpu << SCHEDOP_vcpushift))
|
||||
: "memory", "ecx" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_vcpu_pickle(
|
||||
int vcpu, vcpu_guest_context_t *ctxt)
|
||||
{
|
||||
int ret;
|
||||
unsigned long ign1, ign2;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret), "=b" (ign1), "=c" (ign2)
|
||||
: "0" (__HYPERVISOR_sched_op),
|
||||
"1" (SCHEDOP_vcpu_pickle | (vcpu << SCHEDOP_vcpushift)),
|
||||
"2" (ctxt)
|
||||
: "memory" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
#elif defined(__x86_64__)
|
||||
|
||||
#define __syscall_clobber "r11","rcx","memory"
|
||||
|
||||
/*
|
||||
* Assembler stubs for hyper-calls.
|
||||
*/
|
||||
static inline int
|
||||
HYPERVISOR_set_trap_table(
|
||||
trap_info_t *table)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_set_trap_table), "D" (table)
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_mmu_update(
|
||||
mmu_update_t *req, int count, int *success_count, domid_t domid)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movq %5, %%r10;" TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_mmu_update), "D" (req), "S" ((long)count),
|
||||
"d" (success_count), "g" ((unsigned long)domid)
|
||||
: __syscall_clobber, "r10" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_mmuext_op(
|
||||
struct mmuext_op *op, int count, int *success_count, domid_t domid)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movq %5, %%r10;" TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" (__HYPERVISOR_mmuext_op), "D" (op), "S" ((long)count),
|
||||
"d" (success_count), "g" ((unsigned long)domid)
|
||||
: __syscall_clobber, "r10" );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_set_gdt(
|
||||
unsigned long *frame_list, int entries)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_set_gdt), "D" (frame_list), "S" ((long)entries)
|
||||
: __syscall_clobber );
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
static inline int
|
||||
HYPERVISOR_stack_switch(
|
||||
unsigned long ss, unsigned long esp)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_stack_switch), "D" (ss), "S" (esp)
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_set_callbacks(
|
||||
unsigned long event_address, unsigned long failsafe_address,
|
||||
unsigned long syscall_address)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_set_callbacks), "D" (event_address),
|
||||
"S" (failsafe_address), "d" (syscall_address)
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_fpu_taskswitch(
|
||||
int set)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret) : "0" ((unsigned long)__HYPERVISOR_fpu_taskswitch),
|
||||
"D" ((unsigned long) set) : __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_yield(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_sched_op), "D" ((unsigned long)SCHEDOP_yield)
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_block(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_sched_op), "D" ((unsigned long)SCHEDOP_block)
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_shutdown(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_sched_op),
|
||||
"D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_poweroff << SCHEDOP_reasonshift)))
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_reboot(
|
||||
void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_sched_op),
|
||||
"D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_reboot << SCHEDOP_reasonshift)))
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int
|
||||
HYPERVISOR_suspend(
|
||||
unsigned long srec)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* NB. On suspend, control software expects a suspend record in %esi. */
|
||||
__asm__ __volatile__ (
|
||||
TRAP_INSTR
|
||||
: "=a" (ret)
|
||||
: "0" ((unsigned long)__HYPERVISOR_sched_op),
|
||||
"D" ((unsigned long)(SCHEDOP_shutdown | (SHUTDOWN_suspend << SCHEDOP_reasonshift))),
|
||||
"S" (srec)
|
||||
: __syscall_clobber );
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* We can have the timeout value in a single argument for the hypercall, but
|
||||
* that will break the common code.
|
||||
*/
|
||||
static inline long
|
||||
HYPERVISOR_set_timer_op(
|
||||
u64 timeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
@@ -60,10 +60,22 @@
|
||||
/* printing */
|
||||
#define printk printf
|
||||
#define kprintf printf
|
||||
int printf(const char *fmt, ...);
|
||||
int vprintf(const char *fmt, va_list ap);
|
||||
int sprintf(char *buf, const char *cfmt, ...);
|
||||
int vsprintf(char *buf, const char *cfmt, va_list ap);
|
||||
#define _p(_x) ((void *)(unsigned long)(_x))
|
||||
void printf(const char *fmt, ...);
|
||||
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
|
||||
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args);
|
||||
int snprintf(char * buf, size_t size, const char *fmt, ...);
|
||||
int scnprintf(char * buf, size_t size, const char *fmt, ...);
|
||||
int vsprintf(char *buf, const char *fmt, va_list args);
|
||||
int sprintf(char * buf, const char *fmt, ...);
|
||||
int vsscanf(const char * buf, const char * fmt, va_list args);
|
||||
int sscanf(const char * buf, const char * fmt, ...);
|
||||
|
||||
long simple_strtol(const char *cp,char **endp,unsigned int base);
|
||||
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
|
||||
long long simple_strtoll(const char *cp,char **endp,unsigned int base);
|
||||
unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base);
|
||||
|
||||
|
||||
/* string and memory manipulation */
|
||||
int memcmp(const void *cs, const void *ct, size_t count);
|
||||
@@ -77,6 +89,16 @@ size_t strnlen(const char *s, size_t count);
|
||||
size_t strlen(const char *s);
|
||||
char *strchr(const char *s, int c);
|
||||
char *strstr(const char *s1, const char *s2);
|
||||
char * strcat(char * dest, const char * src);
|
||||
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
struct kvec {
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif /* _LIB_H_ */
|
||||
@@ -25,6 +25,15 @@
|
||||
#ifndef _MM_H_
|
||||
#define _MM_H_
|
||||
|
||||
#ifdef __i386__
|
||||
#include <xen/arch-x86_32.h>
|
||||
#endif
|
||||
|
||||
#ifdef __x86_64__
|
||||
#include <xen/arch-x86_64.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __x86_64__
|
||||
|
||||
#define L1_PAGETABLE_SHIFT 12
|
||||
@@ -56,6 +65,8 @@
|
||||
|
||||
#define L1_PAGETABLE_ENTRIES 1024
|
||||
#define L2_PAGETABLE_ENTRIES 1024
|
||||
|
||||
#elif defined(__x86_64__)
|
||||
#endif
|
||||
|
||||
/* Given a virtual address, get an entry offset into a page table. */
|
||||
@@ -97,13 +108,15 @@
|
||||
|
||||
extern unsigned long *phys_to_machine_mapping;
|
||||
#define pfn_to_mfn(_pfn) (phys_to_machine_mapping[(_pfn)])
|
||||
#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)])
|
||||
static __inline__ unsigned long phys_to_machine(unsigned long phys)
|
||||
{
|
||||
unsigned long machine = pfn_to_mfn(phys >> L1_PAGETABLE_SHIFT);
|
||||
machine = (machine << L1_PAGETABLE_SHIFT) | (phys & ~PAGE_MASK);
|
||||
return machine;
|
||||
}
|
||||
|
||||
|
||||
#define mfn_to_pfn(_mfn) (machine_to_phys_mapping[(_mfn)])
|
||||
static __inline__ unsigned long machine_to_phys(unsigned long machine)
|
||||
{
|
||||
unsigned long phys = mfn_to_pfn(machine >> L1_PAGETABLE_SHIFT);
|
||||
@@ -119,16 +132,15 @@ static __inline__ unsigned long machine_to_phys(unsigned long machine)
|
||||
|
||||
#define to_phys(x) ((unsigned long)(x)-VIRT_START)
|
||||
#define to_virt(x) ((void *)((unsigned long)(x)+VIRT_START))
|
||||
#define __va to_virt
|
||||
#define __pa to_phys
|
||||
|
||||
#define virt_to_pfn(_virt) (PFN_DOWN(to_phys(_virt)))
|
||||
#define mach_to_virt(_mach) (to_virt(machine_to_phys(_mach)))
|
||||
#define mfn_to_virt(_mfn) (mach_to_virt(_mfn << PAGE_SHIFT))
|
||||
|
||||
void init_mm(void);
|
||||
unsigned long alloc_pages(int order);
|
||||
#define alloc_page() alloc_pages(0);
|
||||
void free_pages(void *pointer, int order);
|
||||
//int is_mfn_mapped(unsigned long mfn);
|
||||
|
||||
static __inline__ int get_order(unsigned long size)
|
||||
{
|
||||
|
||||
+247
-90
@@ -15,16 +15,17 @@
|
||||
#define unlikely(x) __builtin_expect((x),0)
|
||||
|
||||
#define smp_processor_id() 0
|
||||
#define preempt_disable() ((void)0)
|
||||
#define preempt_enable() ((void)0)
|
||||
|
||||
#define force_evtchn_callback() ((void)HYPERVISOR_xen_version(0))
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
#include <types.h>
|
||||
#include <hypervisor.h>
|
||||
#endif
|
||||
#include <xen/xen.h>
|
||||
|
||||
|
||||
#define force_evtchn_callback() ((void)HYPERVISOR_xen_version(0))
|
||||
|
||||
#define __KERNEL_CS FLAT_KERNEL_CS
|
||||
#define __KERNEL_DS FLAT_KERNEL_DS
|
||||
#define __KERNEL_SS FLAT_KERNEL_SS
|
||||
@@ -54,8 +55,6 @@
|
||||
/* Everything below this point is not included by assembler (.S) files. */
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#define pt_regs xen_regs
|
||||
|
||||
void trap_init(void);
|
||||
|
||||
/*
|
||||
@@ -69,10 +68,8 @@ void trap_init(void);
|
||||
#define __cli() \
|
||||
do { \
|
||||
vcpu_info_t *_vcpu; \
|
||||
preempt_disable(); \
|
||||
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
|
||||
_vcpu->evtchn_upcall_mask = 1; \
|
||||
preempt_enable_no_resched(); \
|
||||
barrier(); \
|
||||
} while (0)
|
||||
|
||||
@@ -80,13 +77,11 @@ do { \
|
||||
do { \
|
||||
vcpu_info_t *_vcpu; \
|
||||
barrier(); \
|
||||
preempt_disable(); \
|
||||
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
|
||||
_vcpu->evtchn_upcall_mask = 0; \
|
||||
barrier(); /* unmask then check (avoid races) */ \
|
||||
if ( unlikely(_vcpu->evtchn_upcall_pending) ) \
|
||||
force_evtchn_callback(); \
|
||||
preempt_enable(); \
|
||||
} while (0)
|
||||
|
||||
#define __save_flags(x) \
|
||||
@@ -100,15 +95,12 @@ do { \
|
||||
do { \
|
||||
vcpu_info_t *_vcpu; \
|
||||
barrier(); \
|
||||
preempt_disable(); \
|
||||
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
|
||||
if ((_vcpu->evtchn_upcall_mask = (x)) == 0) { \
|
||||
barrier(); /* unmask then check (avoid races) */ \
|
||||
if ( unlikely(_vcpu->evtchn_upcall_pending) ) \
|
||||
force_evtchn_callback(); \
|
||||
preempt_enable(); \
|
||||
} else \
|
||||
preempt_enable_no_resched(); \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
#define safe_halt() ((void)0)
|
||||
@@ -116,11 +108,9 @@ do { \
|
||||
#define __save_and_cli(x) \
|
||||
do { \
|
||||
vcpu_info_t *_vcpu; \
|
||||
preempt_disable(); \
|
||||
_vcpu = &HYPERVISOR_shared_info->vcpu_data[smp_processor_id()]; \
|
||||
(x) = _vcpu->evtchn_upcall_mask; \
|
||||
_vcpu->evtchn_upcall_mask = 1; \
|
||||
preempt_enable_no_resched(); \
|
||||
barrier(); \
|
||||
} while (0)
|
||||
|
||||
@@ -136,6 +126,15 @@ do { \
|
||||
/* This is a barrier for the compiler only, NOT the processor! */
|
||||
#define barrier() __asm__ __volatile__("": : :"memory")
|
||||
|
||||
#if defined(__i386__)
|
||||
#define mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
|
||||
#define rmb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
|
||||
#elif defined(__x86_64__)
|
||||
#define mb() __asm__ __volatile__ ("mfence":::"memory")
|
||||
#define rmb() __asm__ __volatile__ ("lfence":::"memory")
|
||||
#endif
|
||||
|
||||
|
||||
#define LOCK_PREFIX ""
|
||||
#define LOCK ""
|
||||
#define ADDR (*(volatile long *) addr)
|
||||
@@ -147,39 +146,187 @@ do { \
|
||||
typedef struct { volatile int counter; } atomic_t;
|
||||
|
||||
|
||||
#define xchg(ptr,v) \
|
||||
((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
|
||||
/************************** i386 *******************************/
|
||||
#if defined (__i386__)
|
||||
|
||||
#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
|
||||
struct __xchg_dummy { unsigned long a[100]; };
|
||||
#define __xg(x) ((volatile struct __xchg_dummy *)(x))
|
||||
static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr,
|
||||
int size)
|
||||
#define __xg(x) ((struct __xchg_dummy *)(x))
|
||||
static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
__asm__ __volatile__("xchgb %b0,%1"
|
||||
:"=q" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
case 2:
|
||||
__asm__ __volatile__("xchgw %w0,%1"
|
||||
:"=r" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
case 4:
|
||||
__asm__ __volatile__("xchgl %0,%1"
|
||||
:"=r" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
}
|
||||
return x;
|
||||
switch (size) {
|
||||
case 1:
|
||||
__asm__ __volatile__("xchgb %b0,%1"
|
||||
:"=q" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
case 2:
|
||||
__asm__ __volatile__("xchgw %w0,%1"
|
||||
:"=r" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
case 4:
|
||||
__asm__ __volatile__("xchgl %0,%1"
|
||||
:"=r" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* test_and_clear_bit - Clear a bit and return its old value
|
||||
* @nr: Bit to set
|
||||
* @nr: Bit to clear
|
||||
* @addr: Address to count from
|
||||
*
|
||||
* This operation is atomic and cannot be reordered.
|
||||
* It can be reorderdered on other architectures other than x86.
|
||||
* It also implies a memory barrier.
|
||||
*/
|
||||
static inline int test_and_clear_bit(int nr, volatile unsigned long * addr)
|
||||
{
|
||||
int oldbit;
|
||||
|
||||
__asm__ __volatile__( LOCK
|
||||
"btrl %2,%1\n\tsbbl %0,%0"
|
||||
:"=r" (oldbit),"=m" (ADDR)
|
||||
:"Ir" (nr) : "memory");
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static inline int constant_test_bit(int nr, const volatile unsigned long *addr)
|
||||
{
|
||||
return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0;
|
||||
}
|
||||
|
||||
static inline int variable_test_bit(int nr, const volatile unsigned long * addr)
|
||||
{
|
||||
int oldbit;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"btl %2,%1\n\tsbbl %0,%0"
|
||||
:"=r" (oldbit)
|
||||
:"m" (ADDR),"Ir" (nr));
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
#define test_bit(nr,addr) \
|
||||
(__builtin_constant_p(nr) ? \
|
||||
constant_test_bit((nr),(addr)) : \
|
||||
variable_test_bit((nr),(addr)))
|
||||
|
||||
/**
|
||||
* set_bit - Atomically set a bit in memory
|
||||
* @nr: the bit to set
|
||||
* @addr: the address to start counting from
|
||||
*
|
||||
* This function is atomic and may not be reordered. See __set_bit()
|
||||
* if you do not require the atomic guarantees.
|
||||
*
|
||||
* Note: there are no guarantees that this function will not be reordered
|
||||
* on non x86 architectures, so if you are writting portable code,
|
||||
* make sure not to rely on its reordering guarantees.
|
||||
*
|
||||
* Note that @nr may be almost arbitrarily large; this function is not
|
||||
* restricted to acting on a single-word quantity.
|
||||
*/
|
||||
static inline void set_bit(int nr, volatile unsigned long * addr)
|
||||
{
|
||||
__asm__ __volatile__( LOCK
|
||||
"btsl %1,%0"
|
||||
:"=m" (ADDR)
|
||||
:"Ir" (nr));
|
||||
}
|
||||
|
||||
/**
|
||||
* clear_bit - Clears a bit in memory
|
||||
* @nr: Bit to clear
|
||||
* @addr: Address to start counting from
|
||||
*
|
||||
* clear_bit() is atomic and may not be reordered. However, it does
|
||||
* not contain a memory barrier, so if it is used for locking purposes,
|
||||
* you should call smp_mb__before_clear_bit() and/or smp_mb__after_clear_bit()
|
||||
* in order to ensure changes are visible on other processors.
|
||||
*/
|
||||
static inline void clear_bit(int nr, volatile unsigned long * addr)
|
||||
{
|
||||
__asm__ __volatile__( LOCK
|
||||
"btrl %1,%0"
|
||||
:"=m" (ADDR)
|
||||
:"Ir" (nr));
|
||||
}
|
||||
|
||||
/**
|
||||
* __ffs - find first bit in word.
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no bit exists, so code should check against 0 first.
|
||||
*/
|
||||
static inline unsigned long __ffs(unsigned long word)
|
||||
{
|
||||
__asm__("bsfl %1,%0"
|
||||
:"=r" (word)
|
||||
:"rm" (word));
|
||||
return word;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* These have to be done with inline assembly: that way the bit-setting
|
||||
* is guaranteed to be atomic. All bit operations return 0 if the bit
|
||||
* was cleared before the operation and != 0 if it was not.
|
||||
*
|
||||
* bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
|
||||
*/
|
||||
#define ADDR (*(volatile long *) addr)
|
||||
|
||||
#define rdtscll(val) \
|
||||
__asm__ __volatile__("rdtsc" : "=A" (val))
|
||||
|
||||
|
||||
|
||||
#elif defined(__x86_64__)/* ifdef __i386__ */
|
||||
/************************** x86_84 *******************************/
|
||||
|
||||
#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
|
||||
#define __xg(x) ((volatile long *)(x))
|
||||
static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case 1:
|
||||
__asm__ __volatile__("xchgb %b0,%1"
|
||||
:"=q" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
case 2:
|
||||
__asm__ __volatile__("xchgw %w0,%1"
|
||||
:"=r" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
case 4:
|
||||
__asm__ __volatile__("xchgl %k0,%1"
|
||||
:"=r" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
case 8:
|
||||
__asm__ __volatile__("xchgq %0,%1"
|
||||
:"=r" (x)
|
||||
:"m" (*__xg(ptr)), "0" (x)
|
||||
:"memory");
|
||||
break;
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* test_and_clear_bit - Clear a bit and return its old value
|
||||
* @nr: Bit to clear
|
||||
* @addr: Address to count from
|
||||
*
|
||||
* This operation is atomic and cannot be reordered.
|
||||
@@ -187,29 +334,29 @@ static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr,
|
||||
*/
|
||||
static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
|
||||
{
|
||||
int oldbit;
|
||||
int oldbit;
|
||||
|
||||
__asm__ __volatile__( LOCK_PREFIX
|
||||
"btrl %2,%1\n\tsbbl %0,%0"
|
||||
:"=r" (oldbit),"=m" (ADDR)
|
||||
:"Ir" (nr) : "memory");
|
||||
return oldbit;
|
||||
__asm__ __volatile__( LOCK_PREFIX
|
||||
"btrl %2,%1\n\tsbbl %0,%0"
|
||||
:"=r" (oldbit),"=m" (ADDR)
|
||||
:"dIr" (nr) : "memory");
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static __inline__ int constant_test_bit(int nr, const volatile void * addr)
|
||||
{
|
||||
return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
|
||||
return ((1UL << (nr & 31)) & (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
|
||||
}
|
||||
|
||||
static __inline__ int variable_test_bit(int nr, volatile void * addr)
|
||||
static __inline__ int variable_test_bit(int nr, volatile const void * addr)
|
||||
{
|
||||
int oldbit;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"btl %2,%1\n\tsbbl %0,%0"
|
||||
:"=r" (oldbit)
|
||||
:"m" (ADDR),"Ir" (nr));
|
||||
return oldbit;
|
||||
int oldbit;
|
||||
|
||||
__asm__ __volatile__(
|
||||
"btl %2,%1\n\tsbbl %0,%0"
|
||||
:"=r" (oldbit)
|
||||
:"m" (ADDR),"dIr" (nr));
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
#define test_bit(nr,addr) \
|
||||
@@ -230,10 +377,10 @@ static __inline__ int variable_test_bit(int nr, volatile void * addr)
|
||||
*/
|
||||
static __inline__ void set_bit(int nr, volatile void * addr)
|
||||
{
|
||||
__asm__ __volatile__( LOCK_PREFIX
|
||||
"btsl %1,%0"
|
||||
:"=m" (ADDR)
|
||||
:"Ir" (nr));
|
||||
__asm__ __volatile__( LOCK_PREFIX
|
||||
"btsl %1,%0"
|
||||
:"=m" (ADDR)
|
||||
:"dIr" (nr) : "memory");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,41 +395,44 @@ static __inline__ void set_bit(int nr, volatile void * addr)
|
||||
*/
|
||||
static __inline__ void clear_bit(int nr, volatile void * addr)
|
||||
{
|
||||
__asm__ __volatile__( LOCK_PREFIX
|
||||
"btrl %1,%0"
|
||||
:"=m" (ADDR)
|
||||
:"Ir" (nr));
|
||||
__asm__ __volatile__( LOCK_PREFIX
|
||||
"btrl %1,%0"
|
||||
:"=m" (ADDR)
|
||||
:"dIr" (nr));
|
||||
}
|
||||
|
||||
/**
|
||||
* atomic_inc - increment atomic variable
|
||||
* @v: pointer of type atomic_t
|
||||
*
|
||||
* Atomically increments @v by 1. Note that the guaranteed
|
||||
* useful range of an atomic_t is only 24 bits.
|
||||
*/
|
||||
static __inline__ void atomic_inc(atomic_t *v)
|
||||
{
|
||||
__asm__ __volatile__(
|
||||
LOCK "incl %0"
|
||||
:"=m" (v->counter)
|
||||
:"m" (v->counter));
|
||||
}
|
||||
|
||||
|
||||
#define rdtscll(val) \
|
||||
__asm__ __volatile__("rdtsc" : "=A" (val))
|
||||
|
||||
* __ffs - find first bit in word.
|
||||
* @word: The word to search
|
||||
*
|
||||
* Undefined if no bit exists, so code should check against 0 first.
|
||||
*/
|
||||
static __inline__ unsigned long __ffs(unsigned long word)
|
||||
{
|
||||
__asm__("bsfl %1,%0"
|
||||
:"=r" (word)
|
||||
:"rm" (word));
|
||||
return word;
|
||||
__asm__("bsfq %1,%0"
|
||||
:"=r" (word)
|
||||
:"rm" (word));
|
||||
return word;
|
||||
}
|
||||
|
||||
#define ADDR (*(volatile long *) addr)
|
||||
|
||||
#define rdtscll(val) do { \
|
||||
unsigned int __a,__d; \
|
||||
asm volatile("rdtsc" : "=a" (__a), "=d" (__d)); \
|
||||
(val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \
|
||||
} while(0)
|
||||
|
||||
|
||||
#else /* ifdef __x86_64__ */
|
||||
#error "Unsupported architecture"
|
||||
#endif
|
||||
|
||||
|
||||
/********************* common i386 and x86_64 ****************************/
|
||||
|
||||
|
||||
|
||||
static __inline__ void synch_set_bit(int nr, volatile void * addr)
|
||||
{
|
||||
__asm__ __volatile__ (
|
||||
@@ -306,6 +456,14 @@ static __inline__ int synch_test_and_set_bit(int nr, volatile void * addr)
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static __inline__ int synch_test_and_clear_bit(int nr, volatile void * addr)
|
||||
{
|
||||
int oldbit;
|
||||
__asm__ __volatile__ (
|
||||
"lock btrl %2,%1\n\tsbbl %0,%0"
|
||||
: "=r" (oldbit), "=m" (ADDR) : "Ir" (nr) : "memory");
|
||||
return oldbit;
|
||||
}
|
||||
|
||||
static __inline__ int synch_const_test_bit(int nr, const volatile void * addr)
|
||||
{
|
||||
@@ -326,9 +484,8 @@ static __inline__ int synch_var_test_bit(int nr, volatile void * addr)
|
||||
(__builtin_constant_p(nr) ? \
|
||||
synch_const_test_bit((nr),(addr)) : \
|
||||
synch_var_test_bit((nr),(addr)))
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
#define rdtsc(low,high) \
|
||||
__asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
|
||||
|
||||
|
||||
#endif /* not assembly */
|
||||
#endif /* _OS_H_ */
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef __SCHED_H__
|
||||
#define __SCHED_H__
|
||||
|
||||
#include <list.h>
|
||||
|
||||
struct thread
|
||||
{
|
||||
char *name;
|
||||
char *stack;
|
||||
unsigned long eps;
|
||||
unsigned long eip;
|
||||
struct list_head thread_list;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void init_sched(void);
|
||||
void run_idle_thread(void);
|
||||
struct thread* create_thread(char *name, void (*function)(void *), void *data);
|
||||
void schedule(void);
|
||||
|
||||
static inline struct thread* get_current(void)
|
||||
{
|
||||
struct thread **current;
|
||||
#ifdef __i386__
|
||||
__asm__("andl %%esp,%0; ":"=r" (current) : "r" (~8191UL));
|
||||
#endif
|
||||
return *current;
|
||||
}
|
||||
|
||||
#define current get_current()
|
||||
|
||||
|
||||
void wake(struct thread *thread);
|
||||
void block(struct thread *thread);
|
||||
|
||||
#endif /* __SCHED_H__ */
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef _SEMAPHORE_H_
|
||||
#define _SEMAPHORE_H_
|
||||
|
||||
#include <wait.h>
|
||||
|
||||
/*
|
||||
* Implementation of semaphore in Mini-os is simple, because
|
||||
* there are no preemptive threads, the atomicity is guaranteed.
|
||||
*/
|
||||
|
||||
struct semaphore
|
||||
{
|
||||
int count;
|
||||
struct wait_queue_head wait;
|
||||
};
|
||||
|
||||
|
||||
#define __SEMAPHORE_INITIALIZER(name, n) \
|
||||
{ \
|
||||
.count = n, \
|
||||
.wait = __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
|
||||
}
|
||||
|
||||
#define __MUTEX_INITIALIZER(name) \
|
||||
__SEMAPHORE_INITIALIZER(name,1)
|
||||
|
||||
#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
|
||||
struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
|
||||
|
||||
#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
|
||||
|
||||
#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
|
||||
|
||||
static void inline down(struct semaphore *sem)
|
||||
{
|
||||
wait_event(sem->wait, sem->count > 0);
|
||||
sem->count--;
|
||||
}
|
||||
|
||||
static void inline up(struct semaphore *sem)
|
||||
{
|
||||
sem->count++;
|
||||
wake_up(&sem->wait);
|
||||
}
|
||||
|
||||
#endif /* _SEMAPHORE_H */
|
||||
@@ -58,6 +58,6 @@ void init_time(void);
|
||||
s_time_t get_s_time(void);
|
||||
s_time_t get_v_time(void);
|
||||
void gettimeofday(struct timeval *tv);
|
||||
void block(u32 millisecs);
|
||||
void block_domain(u32 millisecs);
|
||||
|
||||
#endif /* _TIME_H_ */
|
||||
@@ -17,6 +17,7 @@
|
||||
#ifndef _TRAPS_H_
|
||||
#define _TRAPS_H_
|
||||
|
||||
#ifdef __i386__
|
||||
struct pt_regs {
|
||||
long ebx;
|
||||
long ecx;
|
||||
@@ -34,7 +35,38 @@ struct pt_regs {
|
||||
long esp;
|
||||
int xss;
|
||||
};
|
||||
#elif __x86_64__
|
||||
|
||||
struct pt_regs {
|
||||
unsigned long r15;
|
||||
unsigned long r14;
|
||||
unsigned long r13;
|
||||
unsigned long r12;
|
||||
unsigned long rbp;
|
||||
unsigned long rbx;
|
||||
/* arguments: non interrupts/non tracing syscalls only save upto here*/
|
||||
unsigned long r11;
|
||||
unsigned long r10;
|
||||
unsigned long r9;
|
||||
unsigned long r8;
|
||||
unsigned long rax;
|
||||
unsigned long rcx;
|
||||
unsigned long rdx;
|
||||
unsigned long rsi;
|
||||
unsigned long rdi;
|
||||
unsigned long orig_rax;
|
||||
/* end of arguments */
|
||||
/* cpu exception frame or undefined */
|
||||
unsigned long rip;
|
||||
unsigned long cs;
|
||||
unsigned long eflags;
|
||||
unsigned long rsp;
|
||||
unsigned long ss;
|
||||
/* top of stack page */
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void dump_regs(struct pt_regs *regs);
|
||||
|
||||
|
||||
@@ -44,11 +44,19 @@ typedef unsigned long u_long;
|
||||
typedef long long quad_t;
|
||||
typedef unsigned long long u_quad_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
|
||||
typedef struct { unsigned long pte_low; } pte_t;
|
||||
#elif defined(__x86_64__)
|
||||
typedef long quad_t;
|
||||
typedef unsigned long u_quad_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
|
||||
typedef struct { unsigned long pte; } pte_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#define INT_MAX ((int)(~0U>>1))
|
||||
#define UINT_MAX (~0U)
|
||||
#endif /* _TYPES_H_ */
|
||||
@@ -0,0 +1,91 @@
|
||||
#ifndef __WAIT_H__
|
||||
#define __WAIT_H__
|
||||
|
||||
#include <sched.h>
|
||||
#include <list.h>
|
||||
#include <lib.h>
|
||||
#include <os.h>
|
||||
|
||||
struct wait_queue
|
||||
{
|
||||
struct thread *thread;
|
||||
struct list_head thread_list;
|
||||
};
|
||||
|
||||
struct wait_queue_head
|
||||
{
|
||||
/* TODO - lock required? */
|
||||
struct list_head thread_list;
|
||||
};
|
||||
|
||||
#define DECLARE_WAIT_QUEUE_HEAD(name) \
|
||||
struct wait_queue_head name = \
|
||||
{ .thread_list = { &(name).thread_list, &(name).thread_list} }
|
||||
|
||||
#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \
|
||||
.thread_list = { &(name).thread_list, &(name).thread_list } }
|
||||
|
||||
|
||||
#define DEFINE_WAIT(name) \
|
||||
struct wait_queue name = { \
|
||||
.thread = current, \
|
||||
.thread_list = LIST_HEAD_INIT((name).thread_list), \
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline void init_waitqueue_entry(struct wait_queue *q, struct thread *thread)
|
||||
{
|
||||
q->thread = thread;
|
||||
}
|
||||
|
||||
|
||||
static inline void add_wait_queue(struct wait_queue_head *h, struct wait_queue *q)
|
||||
{
|
||||
if (list_empty(&q->thread_list))
|
||||
list_add(&q->thread_list, &h->thread_list);
|
||||
}
|
||||
|
||||
static inline void remove_wait_queue(struct wait_queue *q)
|
||||
{
|
||||
list_del(&q->thread_list);
|
||||
}
|
||||
|
||||
static inline void wake_up(struct wait_queue_head *head)
|
||||
{
|
||||
struct list_head *tmp, *next;
|
||||
list_for_each_safe(tmp, next, &head->thread_list)
|
||||
{
|
||||
struct wait_queue *curr;
|
||||
curr = list_entry(tmp, struct wait_queue, thread_list);
|
||||
wake(curr->thread);
|
||||
}
|
||||
}
|
||||
|
||||
#define wait_event(wq, condition) do{ \
|
||||
unsigned long flags; \
|
||||
if(condition) \
|
||||
break; \
|
||||
DEFINE_WAIT(__wait); \
|
||||
for(;;) \
|
||||
{ \
|
||||
/* protect the list */ \
|
||||
local_irq_save(flags); \
|
||||
add_wait_queue(&wq, &__wait); \
|
||||
block(current); \
|
||||
local_irq_restore(flags); \
|
||||
if(condition) \
|
||||
break; \
|
||||
schedule(); \
|
||||
} \
|
||||
local_irq_save(flags); \
|
||||
/* need to wake up */ \
|
||||
wake(current); \
|
||||
remove_wait_queue(&__wait); \
|
||||
local_irq_restore(flags); \
|
||||
} while(0)
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* __WAIT_H__ */
|
||||
@@ -0,0 +1,89 @@
|
||||
/******************************************************************************
|
||||
* xenbus.h
|
||||
*
|
||||
* Talks to Xen Store to figure out what devices we have.
|
||||
*
|
||||
* Copyright (C) 2005 Rusty Russell, IBM Corporation
|
||||
*
|
||||
* This file may be distributed separately from the Linux kernel, or
|
||||
* incorporated into other software packages, subject to the following license:
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this source file (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify,
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_XEN_XENBUS_H
|
||||
#define _ASM_XEN_XENBUS_H
|
||||
|
||||
|
||||
/* Caller must hold this lock to call these functions: it's also held
|
||||
* across watch callbacks. */
|
||||
// TODO
|
||||
//extern struct semaphore xenbus_lock;
|
||||
|
||||
char **xenbus_directory(const char *dir, const char *node, unsigned int *num);
|
||||
void *xenbus_read(const char *dir, const char *node, unsigned int *len);
|
||||
int xenbus_write(const char *dir, const char *node,
|
||||
const char *string, int createflags);
|
||||
int xenbus_mkdir(const char *dir, const char *node);
|
||||
int xenbus_exists(const char *dir, const char *node);
|
||||
int xenbus_rm(const char *dir, const char *node);
|
||||
int xenbus_transaction_start(const char *subtree);
|
||||
int xenbus_transaction_end(int abort);
|
||||
|
||||
/* Single read and scanf: returns -errno or num scanned if > 0. */
|
||||
int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...)
|
||||
__attribute__((format(scanf, 3, 4)));
|
||||
|
||||
/* Single printf and write: returns -errno or 0. */
|
||||
int xenbus_printf(const char *dir, const char *node, const char *fmt, ...)
|
||||
__attribute__((format(printf, 3, 4)));
|
||||
|
||||
/* Generic read function: NULL-terminated triples of name,
|
||||
* sprintf-style type string, and pointer. Returns 0 or errno.*/
|
||||
int xenbus_gather(const char *dir, ...);
|
||||
|
||||
/* Register callback to watch this node. */
|
||||
struct xenbus_watch
|
||||
{
|
||||
struct list_head list;
|
||||
char *node;
|
||||
void (*callback)(struct xenbus_watch *, const char *node);
|
||||
};
|
||||
|
||||
int register_xenbus_watch(struct xenbus_watch *watch);
|
||||
void unregister_xenbus_watch(struct xenbus_watch *watch);
|
||||
void reregister_xenbus_watches(void);
|
||||
|
||||
/* Called from xen core code. */
|
||||
void xenbus_suspend(void);
|
||||
void xenbus_resume(void);
|
||||
|
||||
#define XENBUS_IS_ERR_READ(str) ({ \
|
||||
if (!IS_ERR(str) && strlen(str) == 0) { \
|
||||
kfree(str); \
|
||||
str = ERR_PTR(-ERANGE); \
|
||||
} \
|
||||
IS_ERR(str); \
|
||||
})
|
||||
|
||||
#define XENBUS_EXIST_ERR(err) ((err) == -ENOENT || (err) == -ERANGE)
|
||||
|
||||
int xs_init(void);
|
||||
|
||||
#endif /* _ASM_XEN_XENBUS_H */
|
||||
+13
-12
@@ -33,6 +33,8 @@
|
||||
#include <time.h>
|
||||
#include <types.h>
|
||||
#include <lib.h>
|
||||
#include <sched.h>
|
||||
#include <xenbus.h>
|
||||
|
||||
/*
|
||||
* Shared page for communicating with the hypervisor.
|
||||
@@ -59,10 +61,12 @@ void failsafe_callback(void);
|
||||
|
||||
extern char shared_info[PAGE_SIZE];
|
||||
|
||||
#define __pte(x) ((pte_t) { (0) } )
|
||||
|
||||
static shared_info_t *map_shared_info(unsigned long pa)
|
||||
{
|
||||
if ( HYPERVISOR_update_va_mapping(
|
||||
(unsigned long)shared_info, pa | 7, UVMF_INVLPG) )
|
||||
(unsigned long)shared_info, __pte(pa | 7), UVMF_INVLPG) )
|
||||
{
|
||||
printk("Failed to map shared_info!!\n");
|
||||
*(int*)0=0;
|
||||
@@ -77,7 +81,6 @@ static shared_info_t *map_shared_info(unsigned long pa)
|
||||
void start_kernel(start_info_t *si)
|
||||
{
|
||||
static char hello[] = "Bootstrapping...\n";
|
||||
int i;
|
||||
(void)HYPERVISOR_console_io(CONSOLEIO_write, strlen(hello), hello);
|
||||
|
||||
/* Copy the start_info struct to a globally-accessible area. */
|
||||
@@ -96,7 +99,6 @@ void start_kernel(start_info_t *si)
|
||||
(unsigned long)hypervisor_callback,
|
||||
(unsigned long)failsafe_callback, 0);
|
||||
#endif
|
||||
|
||||
trap_init();
|
||||
|
||||
/* ENABLE EVENT DELIVERY. This is disabled at start of day. */
|
||||
@@ -119,7 +121,6 @@ void start_kernel(start_info_t *si)
|
||||
* If used for porting another OS, start here to figure out your
|
||||
* guest os entry point. Otherwise continue below...
|
||||
*/
|
||||
|
||||
/* init memory management */
|
||||
init_mm();
|
||||
|
||||
@@ -127,15 +128,15 @@ void start_kernel(start_info_t *si)
|
||||
init_events();
|
||||
/* init time and timers */
|
||||
init_time();
|
||||
|
||||
/* init scheduler */
|
||||
init_sched();
|
||||
|
||||
/* do nothing */
|
||||
i = 0;
|
||||
for ( ; ; )
|
||||
{
|
||||
// HYPERVISOR_yield();
|
||||
block(100);
|
||||
i++;
|
||||
}
|
||||
/* init xenbus */
|
||||
xs_init();
|
||||
|
||||
/* Everything initialised, start idle thread */
|
||||
run_idle_thread();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+715
-378
File diff suppressed because it is too large.
Load diff
@@ -107,6 +107,19 @@ size_t strnlen(const char * s, size_t count)
|
||||
return sc - s;
|
||||
}
|
||||
|
||||
|
||||
char * strcat(char * dest, const char * src)
|
||||
{
|
||||
char *tmp = dest;
|
||||
|
||||
while (*dest)
|
||||
dest++;
|
||||
|
||||
while ((*dest++ = *src++) != '\0');
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
size_t strlen(const char * s)
|
||||
{
|
||||
const char *sc;
|
||||
|
||||
+4
-6
@@ -198,7 +198,6 @@ static void print_chunks(void *start, int nr_pages)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Initialise allocator, placing addresses [@min,@max] in free pool.
|
||||
* @min and @max are PHYSICAL addresses.
|
||||
@@ -486,16 +485,17 @@ void init_mm(void)
|
||||
phys_to_machine_mapping = (unsigned long *)start_info.mfn_list;
|
||||
|
||||
/* First page follows page table pages and 3 more pages (store page etc) */
|
||||
start_pfn = PFN_UP(__pa(start_info.pt_base)) + start_info.nr_pt_frames + 3;
|
||||
start_pfn = PFN_UP(to_phys(start_info.pt_base)) + start_info.nr_pt_frames + 3;
|
||||
max_pfn = start_info.nr_pages;
|
||||
|
||||
printk(" start_pfn: %lx\n", start_pfn);
|
||||
printk(" max_pfn: %lx\n", max_pfn);
|
||||
|
||||
|
||||
build_pagetable(&start_pfn, &max_pfn);
|
||||
|
||||
#ifdef __i386__
|
||||
build_pagetable(&start_pfn, &max_pfn);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* now we can initialise the page allocator
|
||||
*/
|
||||
@@ -503,7 +503,5 @@ void init_mm(void)
|
||||
(u_long)to_virt(PFN_PHYS(start_pfn)), PFN_PHYS(start_pfn),
|
||||
(u_long)to_virt(PFN_PHYS(max_pfn)), PFN_PHYS(max_pfn));
|
||||
init_page_allocator(PFN_PHYS(start_pfn), PFN_PHYS(max_pfn));
|
||||
#endif
|
||||
|
||||
printk("MM: done\n");
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
****************************************************************************
|
||||
* (C) 2005 - Grzegorz Milos - Intel Research Cambridge
|
||||
****************************************************************************
|
||||
*
|
||||
* File: sched.c
|
||||
* Author: Grzegorz Milos
|
||||
* Changes:
|
||||
*
|
||||
* Date: Aug 2005
|
||||
*
|
||||
* Environment: Xen Minimal OS
|
||||
* Description: simple scheduler for Mini-Os
|
||||
*
|
||||
* The scheduler is non-preemptive (cooperative), and schedules according
|
||||
* to Round Robin algorithm.
|
||||
*
|
||||
****************************************************************************
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <os.h>
|
||||
#include <hypervisor.h>
|
||||
#include <time.h>
|
||||
#include <mm.h>
|
||||
#include <types.h>
|
||||
#include <lib.h>
|
||||
#include <xmalloc.h>
|
||||
#include <list.h>
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
#ifdef SCHED_DEBUG
|
||||
#define DEBUG(_f, _a...) \
|
||||
printk("MINI_OS(file=sched.c, line=%d) " _f "\n", __LINE__, ## _a)
|
||||
#else
|
||||
#define DEBUG(_f, _a...) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
#define RUNNABLE_FLAG 0x00000001
|
||||
|
||||
#define is_runnable(_thread) (_thread->flags & RUNNABLE_FLAG)
|
||||
#define set_runnable(_thread) (_thread->flags |= RUNNABLE_FLAG)
|
||||
#define clear_runnable(_thread) (_thread->flags &= ~RUNNABLE_FLAG)
|
||||
|
||||
|
||||
struct thread *idle_thread;
|
||||
LIST_HEAD(exited_threads);
|
||||
|
||||
void dump_stack(struct thread *thread)
|
||||
{
|
||||
unsigned long *bottom = (unsigned long *)thread->stack + 2048;
|
||||
unsigned long *pointer = (unsigned long *)thread->eps;
|
||||
int count;
|
||||
printk("The stack for \"%s\"\n", thread->name);
|
||||
for(count = 0; count < 15 && pointer < bottom; count ++)
|
||||
{
|
||||
printk("[0x%lx] 0x%lx\n", pointer, *pointer);
|
||||
pointer++;
|
||||
}
|
||||
|
||||
if(pointer < bottom) printk("Not the whole stack printed\n");
|
||||
}
|
||||
|
||||
#ifdef __i386__
|
||||
#define switch_threads(prev, next) do { \
|
||||
unsigned long esi,edi; \
|
||||
__asm__ __volatile__("pushfl\n\t" \
|
||||
"pushl %%ebp\n\t" \
|
||||
"movl %%esp,%0\n\t" /* save ESP */ \
|
||||
"movl %4,%%esp\n\t" /* restore ESP */ \
|
||||
"movl $1f,%1\n\t" /* save EIP */ \
|
||||
"pushl %5\n\t" /* restore EIP */ \
|
||||
"ret\n\t" \
|
||||
"1:\t" \
|
||||
"popl %%ebp\n\t" \
|
||||
"popfl" \
|
||||
:"=m" (prev->eps),"=m" (prev->eip), \
|
||||
"=S" (esi),"=D" (edi) \
|
||||
:"m" (next->eps),"m" (next->eip), \
|
||||
"2" (prev), "d" (next)); \
|
||||
} while (0)
|
||||
#elif __x86_64__
|
||||
/* FIXME */
|
||||
#endif
|
||||
|
||||
void inline print_runqueue(void)
|
||||
{
|
||||
struct list_head *it;
|
||||
struct thread *th;
|
||||
list_for_each(it, &idle_thread->thread_list)
|
||||
{
|
||||
th = list_entry(it, struct thread, thread_list);
|
||||
printk(" Thread \"%s\", runnable=%d\n", th->name, is_runnable(th));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
|
||||
void schedule(void)
|
||||
{
|
||||
struct thread *prev, *next, *thread;
|
||||
struct list_head *iterator;
|
||||
unsigned long flags;
|
||||
prev = current;
|
||||
local_irq_save(flags);
|
||||
list_for_each(iterator, &exited_threads)
|
||||
{
|
||||
thread = list_entry(iterator, struct thread, thread_list);
|
||||
if(thread != prev)
|
||||
{
|
||||
list_del(&thread->thread_list);
|
||||
free_pages(thread->stack, 1);
|
||||
xfree(thread);
|
||||
}
|
||||
}
|
||||
next = idle_thread;
|
||||
/* Thread list needs to be protected */
|
||||
list_for_each(iterator, &idle_thread->thread_list)
|
||||
{
|
||||
thread = list_entry(iterator, struct thread, thread_list);
|
||||
if(is_runnable(thread))
|
||||
{
|
||||
next = thread;
|
||||
/* Put this thread on the end of the list */
|
||||
list_del(&thread->thread_list);
|
||||
list_add_tail(&thread->thread_list, &idle_thread->thread_list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
/* Interrupting the switch is equivalent to having the next thread
|
||||
inturrupted at the return instruction. And therefore at safe point. */
|
||||
/* The thread switching only works for i386 at the moment */
|
||||
#ifdef __i386__
|
||||
if(prev != next) switch_threads(prev, next);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void exit_thread(struct thread *thread)
|
||||
{
|
||||
unsigned long flags;
|
||||
printk("Thread \"%s\" exited.\n", thread->name);
|
||||
local_irq_save(flags);
|
||||
/* Remove from the thread list */
|
||||
list_del(&thread->thread_list);
|
||||
clear_runnable(thread);
|
||||
/* Put onto exited list */
|
||||
list_add(&thread->thread_list, &exited_threads);
|
||||
local_irq_restore(flags);
|
||||
/* Schedule will free the resources */
|
||||
schedule();
|
||||
}
|
||||
|
||||
|
||||
struct thread* create_thread(char *name, void (*function)(void *), void *data)
|
||||
{
|
||||
struct thread *thread;
|
||||
unsigned long flags;
|
||||
|
||||
thread = xmalloc(struct thread);
|
||||
/* Allocate 2 pages for stack, stack will be 2pages aligned */
|
||||
thread->stack = (char *)alloc_pages(1);
|
||||
thread->name = name;
|
||||
printk("Thread \"%s\": pointer: 0x%lx, stack: 0x%lx\n", name, thread,
|
||||
thread->stack);
|
||||
|
||||
thread->eps = (unsigned long)thread->stack + 4096 * 2 - 4;
|
||||
/* Save pointer to the thread on the stack, used by current macro */
|
||||
*((unsigned long *)thread->stack) = (unsigned long)thread;
|
||||
*((unsigned long *)thread->eps) = (unsigned long)thread;
|
||||
thread->eps -= 4;
|
||||
*((unsigned long *)thread->eps) = (unsigned long)data;
|
||||
|
||||
/* No return address */
|
||||
thread->eps -= 4;
|
||||
*((unsigned long *)thread->eps) = (unsigned long)exit_thread;
|
||||
|
||||
thread->eip = (unsigned long)function;
|
||||
|
||||
/* Not runable, not exited */
|
||||
thread->flags = 0;
|
||||
set_runnable(thread);
|
||||
|
||||
local_irq_save(flags);
|
||||
if(idle_thread != NULL)
|
||||
list_add_tail(&thread->thread_list, &idle_thread->thread_list);
|
||||
local_irq_restore(flags);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
|
||||
void block(struct thread *thread)
|
||||
{
|
||||
clear_runnable(thread);
|
||||
}
|
||||
|
||||
void wake(struct thread *thread)
|
||||
{
|
||||
set_runnable(thread);
|
||||
}
|
||||
|
||||
void idle_thread_fn(void *unused)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
schedule();
|
||||
printk("Blocking the domain\n");
|
||||
block_domain(10000);
|
||||
}
|
||||
}
|
||||
|
||||
void run_idle_thread(void)
|
||||
{
|
||||
/* Switch stacks and run the thread */
|
||||
__asm__ __volatile__("mov %0,%%esp\n\t"
|
||||
"push %1\n\t"
|
||||
"ret"
|
||||
:"=m" (idle_thread->eps)
|
||||
:"m" (idle_thread->eip));
|
||||
}
|
||||
|
||||
|
||||
|
||||
DECLARE_MUTEX(mutex);
|
||||
|
||||
void th_f1(void *data)
|
||||
{
|
||||
struct timeval tv1, tv2;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
down(&mutex);
|
||||
printk("Thread \"%s\" got semaphore, runnable %d\n", current->name, is_runnable(current));
|
||||
schedule();
|
||||
printk("Thread \"%s\" releases the semaphore\n", current->name);
|
||||
up(&mutex);
|
||||
|
||||
|
||||
gettimeofday(&tv1);
|
||||
for(;;)
|
||||
{
|
||||
gettimeofday(&tv2);
|
||||
if(tv2.tv_sec - tv1.tv_sec > 2) break;
|
||||
}
|
||||
|
||||
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
void th_f2(void *data)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
printk("Thread OTHER executing, data 0x%lx\n", data);
|
||||
schedule();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void init_sched(void)
|
||||
{
|
||||
printk("Initialising scheduler\n");
|
||||
|
||||
idle_thread = create_thread("Idle", idle_thread_fn, NULL);
|
||||
INIT_LIST_HEAD(&idle_thread->thread_list);
|
||||
|
||||
|
||||
/* create_thread("1", th_f1, (void *)0x1234);
|
||||
create_thread("2", th_f1, (void *)0x1234);
|
||||
create_thread("3", th_f1, (void *)0x1234);
|
||||
create_thread("4", th_f1, (void *)0x1234);
|
||||
create_thread("5", th_f1, (void *)0x1234);
|
||||
create_thread("6", th_f1, (void *)0x1234);
|
||||
create_thread("second", th_f2, NULL);
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ static void print_current_time(void)
|
||||
}
|
||||
|
||||
|
||||
void block(u32 millisecs)
|
||||
void block_domain(u32 millisecs)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv);
|
||||
@@ -232,5 +232,6 @@ static void timer_handler(int ev, struct pt_regs *regs)
|
||||
|
||||
void init_time(void)
|
||||
{
|
||||
printk("Initialising timer interface\n");
|
||||
bind_virq(VIRQ_TIMER, &timer_handler);
|
||||
}
|
||||
+6
-41
@@ -33,36 +33,7 @@ extern void do_exit(void);
|
||||
|
||||
void dump_regs(struct pt_regs *regs)
|
||||
{
|
||||
unsigned long esp;
|
||||
unsigned short ss;
|
||||
|
||||
#ifdef __x86_64__
|
||||
esp = regs->rsp;
|
||||
ss = regs->xss;
|
||||
#else
|
||||
esp = (unsigned long) (®s->esp);
|
||||
ss = __KERNEL_DS;
|
||||
if (regs->xcs & 2) {
|
||||
printk("CS is true, esp is %x\n", regs->esp);
|
||||
esp = regs->esp;
|
||||
ss = regs->xss & 0xffff;
|
||||
}
|
||||
#endif
|
||||
printf("EIP: %04x:[<%p>]\n",
|
||||
0xffff & regs->xcs , regs->eip);
|
||||
printf("EFLAGS: %p\n",regs->eflags);
|
||||
printf("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
|
||||
regs->eax, regs->ebx, regs->ecx, regs->edx);
|
||||
printf("esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n",
|
||||
regs->esi, regs->edi, regs->ebp, esp);
|
||||
#ifdef __x86_64__
|
||||
printf("r8 : %p r9 : %p r10: %p r11: %p\n",
|
||||
regs->r8, regs->r9, regs->r10, regs->r11);
|
||||
printf("r12: %p r13: %p r14: %p r15: %p\n",
|
||||
regs->r12, regs->r13, regs->r14, regs->r15);
|
||||
#endif
|
||||
printf("ds: %04x es: %04x ss: %04x\n",
|
||||
regs->xds & 0xffff, regs->xes & 0xffff, ss);
|
||||
printk("FIXME: proper register dump (with the stack dump)\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -105,6 +76,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long error_code,
|
||||
printk("Page fault at linear address %p\n", addr);
|
||||
dump_regs(regs);
|
||||
#ifdef __x86_64__
|
||||
/* FIXME: _PAGE_PSE */
|
||||
{
|
||||
unsigned long *tab = (unsigned long *)start_info.pt_base;
|
||||
unsigned long page;
|
||||
@@ -112,23 +84,16 @@ void do_page_fault(struct pt_regs *regs, unsigned long error_code,
|
||||
printk("Pagetable walk from %p:\n", tab);
|
||||
|
||||
page = tab[l4_table_offset(addr)];
|
||||
tab = __va(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
||||
tab = to_virt(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
||||
printk(" L4 = %p (%p)\n", page, tab);
|
||||
if ( !(page & AGERESENT) )
|
||||
goto out;
|
||||
|
||||
page = tab[l3_table_offset(addr)];
|
||||
tab = __va(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
||||
tab = to_virt(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
||||
printk(" L3 = %p (%p)\n", page, tab);
|
||||
if ( !(page & AGERESENT) )
|
||||
goto out;
|
||||
|
||||
page = tab[l2_table_offset(addr)];
|
||||
tab = __va(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
||||
printk(" L2 = %p (%p) %s\n", page, tab,
|
||||
(page & AGESE) ? "(2MB)" : "");
|
||||
if ( !(page & AGERESENT) || (page & AGESE) )
|
||||
goto out;
|
||||
tab = to_virt(mfn_to_pfn(pte_to_mfn(page)) << PAGE_SHIFT);
|
||||
printk(" L2 = %p (%p)\n", page, tab);
|
||||
|
||||
page = tab[l1_table_offset(addr)];
|
||||
printk(" L1 = %p\n", page);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
all: xenstore.h xenbus_comms.o xenbus_xs.o xenbus_probe.o
|
||||
|
||||
xenstore.h:
|
||||
[ -e xenstored.h ] || ln -sf ../../../tools/xenstore/xenstored.h xenstored.h
|
||||
|
||||
clean:
|
||||
#Taken care of by main Makefile
|
||||
#rm xenstored.h
|
||||
#rm *.o
|
||||
@@ -0,0 +1,231 @@
|
||||
/******************************************************************************
|
||||
* xenbus_comms.c
|
||||
*
|
||||
* Low level code to talks to Xen Store: ringbuffer and event channel.
|
||||
*
|
||||
* Copyright (C) 2005 Rusty Russell, IBM Corporation
|
||||
*
|
||||
* This file may be distributed separately from the Linux kernel, or
|
||||
* incorporated into other software packages, subject to the following license:
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this source file (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify,
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#include <types.h>
|
||||
#include <wait.h>
|
||||
#include <mm.h>
|
||||
#include <hypervisor.h>
|
||||
#include <events.h>
|
||||
#include <os.h>
|
||||
#include <lib.h>
|
||||
|
||||
|
||||
#ifdef XENBUS_COMMS_DEBUG
|
||||
#define DEBUG(_f, _a...) \
|
||||
printk("MINI_OS(file=xenbus_comms.c, line=%d) " _f "\n", __LINE__, ## _a)
|
||||
#else
|
||||
#define DEBUG(_f, _a...) ((void)0)
|
||||
#endif
|
||||
|
||||
|
||||
#define RINGBUF_DATASIZE ((PAGE_SIZE / 2) - sizeof(struct ringbuf_head))
|
||||
struct ringbuf_head
|
||||
{
|
||||
u32 write; /* Next place to write to */
|
||||
u32 read; /* Next place to read from */
|
||||
u8 flags;
|
||||
char buf[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
DECLARE_WAIT_QUEUE_HEAD(xb_waitq);
|
||||
|
||||
static inline struct ringbuf_head *outbuf(void)
|
||||
{
|
||||
return mfn_to_virt(start_info.store_mfn);
|
||||
}
|
||||
|
||||
static inline struct ringbuf_head *inbuf(void)
|
||||
{
|
||||
return (struct ringbuf_head *)((char *)mfn_to_virt(start_info.store_mfn) + PAGE_SIZE/2);
|
||||
}
|
||||
|
||||
static void wake_waiting(int port, struct pt_regs *regs)
|
||||
{
|
||||
wake_up(&xb_waitq);
|
||||
}
|
||||
|
||||
static int check_buffer(const struct ringbuf_head *h)
|
||||
{
|
||||
return (h->write < RINGBUF_DATASIZE && h->read < RINGBUF_DATASIZE);
|
||||
}
|
||||
|
||||
/* We can't fill last byte: would look like empty buffer. */
|
||||
static void *get_output_chunk(const struct ringbuf_head *h,
|
||||
void *buf, u32 *len)
|
||||
{
|
||||
u32 read_mark;
|
||||
|
||||
if (h->read == 0)
|
||||
read_mark = RINGBUF_DATASIZE - 1;
|
||||
else
|
||||
read_mark = h->read - 1;
|
||||
|
||||
/* Here to the end of buffer, unless they haven't read some out. */
|
||||
*len = RINGBUF_DATASIZE - h->write;
|
||||
if (read_mark >= h->write)
|
||||
*len = read_mark - h->write;
|
||||
return (void *)((char *)buf + h->write);
|
||||
}
|
||||
|
||||
static const void *get_input_chunk(const struct ringbuf_head *h,
|
||||
const void *buf, u32 *len)
|
||||
{
|
||||
/* Here to the end of buffer, unless they haven't written some. */
|
||||
*len = RINGBUF_DATASIZE - h->read;
|
||||
if (h->write >= h->read)
|
||||
*len = h->write - h->read;
|
||||
return (void *)((char *)buf + h->read);
|
||||
}
|
||||
|
||||
static void update_output_chunk(struct ringbuf_head *h, u32 len)
|
||||
{
|
||||
h->write += len;
|
||||
if (h->write == RINGBUF_DATASIZE)
|
||||
h->write = 0;
|
||||
}
|
||||
|
||||
static void update_input_chunk(struct ringbuf_head *h, u32 len)
|
||||
{
|
||||
h->read += len;
|
||||
if (h->read == RINGBUF_DATASIZE)
|
||||
h->read = 0;
|
||||
}
|
||||
|
||||
static int output_avail(struct ringbuf_head *out)
|
||||
{
|
||||
unsigned int avail;
|
||||
|
||||
get_output_chunk(out, out->buf, &avail);
|
||||
return avail != 0;
|
||||
}
|
||||
|
||||
int xb_write(const void *data, unsigned len)
|
||||
{
|
||||
struct ringbuf_head h;
|
||||
struct ringbuf_head *out = outbuf();
|
||||
|
||||
do {
|
||||
void *dst;
|
||||
unsigned int avail;
|
||||
|
||||
wait_event(xb_waitq, output_avail(out));
|
||||
|
||||
/* Read, then check: not that we don't trust store.
|
||||
* Hell, some of my best friends are daemons. But,
|
||||
* in this post-911 world... */
|
||||
h = *out;
|
||||
mb();
|
||||
if (!check_buffer(&h)) {
|
||||
return -1; /* ETERRORIST! */
|
||||
}
|
||||
|
||||
dst = get_output_chunk(&h, out->buf, &avail);
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
memcpy(dst, data, avail);
|
||||
data = (void *)((char *)data + avail);
|
||||
len -= avail;
|
||||
update_output_chunk(out, avail);
|
||||
notify_via_evtchn(start_info.store_evtchn);
|
||||
} while (len != 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xs_input_avail(void)
|
||||
{
|
||||
unsigned int avail;
|
||||
struct ringbuf_head *in = inbuf();
|
||||
|
||||
get_input_chunk(in, in->buf, &avail);
|
||||
return avail != 0;
|
||||
}
|
||||
|
||||
int xb_read(void *data, unsigned len)
|
||||
{
|
||||
struct ringbuf_head h;
|
||||
struct ringbuf_head *in = inbuf();
|
||||
int was_full;
|
||||
|
||||
while (len != 0) {
|
||||
unsigned int avail;
|
||||
const char *src;
|
||||
|
||||
wait_event(xb_waitq, xs_input_avail());
|
||||
h = *in;
|
||||
mb();
|
||||
if (!check_buffer(&h)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
src = get_input_chunk(&h, in->buf, &avail);
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
was_full = !output_avail(&h);
|
||||
|
||||
memcpy(data, src, avail);
|
||||
data = (void *)((char *)data + avail);
|
||||
len -= avail;
|
||||
update_input_chunk(in, avail);
|
||||
DEBUG("Finished read of %i bytes (%i to go)\n", avail, len);
|
||||
/* If it was full, tell them we've taken some. */
|
||||
if (was_full)
|
||||
notify_via_evtchn(start_info.store_evtchn);
|
||||
}
|
||||
|
||||
/* If we left something, wake watch thread to deal with it. */
|
||||
if (xs_input_avail())
|
||||
wake_up(&xb_waitq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set up interrupt handler off store event channel. */
|
||||
int xb_init_comms(void)
|
||||
{
|
||||
printk("Init xenbus comms, store event channel %d\n", start_info.store_evtchn);
|
||||
if (!start_info.store_evtchn)
|
||||
return 0;
|
||||
printk("Binding virq\n");
|
||||
bind_evtchn(start_info.store_evtchn, &wake_waiting);
|
||||
|
||||
/* FIXME zero out page -- domain builder should probably do this*/
|
||||
memset(mfn_to_virt(start_info.store_mfn), 0, PAGE_SIZE);
|
||||
notify_via_evtchn(start_info.store_evtchn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xb_suspend_comms(void)
|
||||
{
|
||||
|
||||
if (!start_info.store_evtchn)
|
||||
return;
|
||||
|
||||
// TODO
|
||||
//unbind_evtchn_from_irqhandler(xen_start_info.store_evtchn, &xb_waitq);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Private include for xenbus communications.
|
||||
*
|
||||
* Copyright (C) 2005 Rusty Russell, IBM Corporation
|
||||
*
|
||||
* This file may be distributed separately from the Linux kernel, or
|
||||
* incorporated into other software packages, subject to the following license:
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this source file (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify,
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _XENBUS_COMMS_H
|
||||
#define _XENBUS_COMMS_H
|
||||
|
||||
int xb_init_comms(void);
|
||||
void xb_suspend_comms(void);
|
||||
|
||||
/* Low level routines. */
|
||||
int xb_write(const void *data, unsigned len);
|
||||
int xb_read(void *data, unsigned len);
|
||||
int xs_input_avail(void);
|
||||
extern struct wait_queue_head xb_waitq;
|
||||
|
||||
#endif /* _XENBUS_COMMS_H */
|
||||
@@ -0,0 +1,554 @@
|
||||
/******************************************************************************
|
||||
* xenbus_xs.c
|
||||
*
|
||||
* This is the kernel equivalent of the "xs" library. We don't need everything
|
||||
* and we use xenbus_comms for communication.
|
||||
*
|
||||
* Copyright (C) 2005 Rusty Russell, IBM Corporation
|
||||
*
|
||||
* This file may be distributed separately from the Linux kernel, or
|
||||
* incorporated into other software packages, subject to the following license:
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this source file (the "Software"), to deal in the Software without
|
||||
* restriction, including without limitation the rights to use, copy, modify,
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
#include <errno.h>
|
||||
#include <types.h>
|
||||
#include <list.h>
|
||||
#include <lib.h>
|
||||
#include <err.h>
|
||||
#include <os.h>
|
||||
#include <xmalloc.h>
|
||||
#include <fcntl.h>
|
||||
#include <xenbus.h>
|
||||
#include <wait.h>
|
||||
#include <sched.h>
|
||||
#include <semaphore.h>
|
||||
#include "xenstored.h"
|
||||
#include "xenbus_comms.h"
|
||||
|
||||
#define streq(a, b) (strcmp((a), (b)) == 0)
|
||||
|
||||
static char printf_buffer[4096];
|
||||
static LIST_HEAD(watches);
|
||||
//TODO
|
||||
DECLARE_MUTEX(xenbus_lock);
|
||||
|
||||
static int get_error(const char *errorstring)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; !streq(errorstring, xsd_errors[i].errstring); i++) {
|
||||
if (i == ARRAY_SIZE(xsd_errors) - 1) {
|
||||
printk("XENBUS xen store gave: unknown error %s",
|
||||
errorstring);
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
return xsd_errors[i].errnum;
|
||||
}
|
||||
|
||||
static void *read_reply(enum xsd_sockmsg_type *type, unsigned int *len)
|
||||
{
|
||||
struct xsd_sockmsg msg;
|
||||
void *ret;
|
||||
int err;
|
||||
|
||||
err = xb_read(&msg, sizeof(msg));
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
ret = xmalloc_array(char, msg.len + 1);
|
||||
if (!ret)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
err = xb_read(ret, msg.len);
|
||||
if (err) {
|
||||
xfree(ret);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
((char*)ret)[msg.len] = '\0';
|
||||
|
||||
*type = msg.type;
|
||||
if (len)
|
||||
*len = msg.len;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Emergency write. */
|
||||
void xenbus_debug_write(const char *str, unsigned int count)
|
||||
{
|
||||
struct xsd_sockmsg msg;
|
||||
|
||||
msg.type = XS_DEBUG;
|
||||
msg.len = sizeof("print") + count + 1;
|
||||
|
||||
xb_write(&msg, sizeof(msg));
|
||||
xb_write("print", sizeof("print"));
|
||||
xb_write(str, count);
|
||||
xb_write("", 1);
|
||||
}
|
||||
|
||||
/* Send message to xs, get kmalloc'ed reply. ERR_PTR() on error. */
|
||||
static void *xs_talkv(enum xsd_sockmsg_type type,
|
||||
const struct kvec *iovec,
|
||||
unsigned int num_vecs,
|
||||
unsigned int *len)
|
||||
{
|
||||
struct xsd_sockmsg msg;
|
||||
void *ret = NULL;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
//WARN_ON(down_trylock(&xenbus_lock) == 0);
|
||||
|
||||
msg.type = type;
|
||||
msg.len = 0;
|
||||
for (i = 0; i < num_vecs; i++)
|
||||
msg.len += iovec[i].iov_len;
|
||||
|
||||
err = xb_write(&msg, sizeof(msg));
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
for (i = 0; i < num_vecs; i++) {
|
||||
err = xb_write(iovec[i].iov_base, iovec[i].iov_len);;
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
/* Watches can have fired before reply comes: daemon detects
|
||||
* and re-transmits, so we can ignore this. */
|
||||
do {
|
||||
xfree(ret);
|
||||
ret = read_reply(&msg.type, len);
|
||||
if (IS_ERR(ret))
|
||||
return ret;
|
||||
} while (msg.type == XS_WATCH_EVENT);
|
||||
|
||||
if (msg.type == XS_ERROR) {
|
||||
err = get_error(ret);
|
||||
xfree(ret);
|
||||
return ERR_PTR(-err);
|
||||
}
|
||||
|
||||
//BUG_ON(msg.type != type);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Simplified version of xs_talkv: single message. */
|
||||
static void *xs_single(enum xsd_sockmsg_type type,
|
||||
const char *string, unsigned int *len)
|
||||
{
|
||||
struct kvec iovec;
|
||||
|
||||
iovec.iov_base = (void *)string;
|
||||
iovec.iov_len = strlen(string) + 1;
|
||||
return xs_talkv(type, &iovec, 1, len);
|
||||
}
|
||||
|
||||
/* Many commands only need an ack, don't care what it says. */
|
||||
static int xs_error(char *reply)
|
||||
{
|
||||
if (IS_ERR(reply))
|
||||
return PTR_ERR(reply);
|
||||
xfree(reply);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int count_strings(const char *strings, unsigned int len)
|
||||
{
|
||||
unsigned int num;
|
||||
const char *p;
|
||||
|
||||
for (p = strings, num = 0; p < strings + len; p += strlen(p) + 1)
|
||||
num++;
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
/* Return the path to dir with /name appended. */
|
||||
static char *join(const char *dir, const char *name)
|
||||
{
|
||||
static char buffer[4096];
|
||||
|
||||
//BUG_ON(down_trylock(&xenbus_lock) == 0);
|
||||
/* XXX FIXME: might not be correct if name == "" */
|
||||
//BUG_ON(strlen(dir) + strlen("/") + strlen(name) + 1 > sizeof(buffer));
|
||||
|
||||
strcpy(buffer, dir);
|
||||
if (!streq(name, "")) {
|
||||
strcat(buffer, "/");
|
||||
strcat(buffer, name);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char **xenbus_directory(const char *dir, const char *node, unsigned int *num)
|
||||
{
|
||||
char *strings, *p, **ret;
|
||||
unsigned int len;
|
||||
|
||||
strings = xs_single(XS_DIRECTORY, join(dir, node), &len);
|
||||
if (IS_ERR(strings))
|
||||
return (char **)strings;
|
||||
|
||||
/* Count the strings. */
|
||||
*num = count_strings(strings, len);
|
||||
|
||||
/* Transfer to one big alloc for easy freeing. */
|
||||
ret = (char **)xmalloc_array(char, *num * sizeof(char *) + len);
|
||||
if (!ret) {
|
||||
xfree(strings);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
memcpy(&ret[*num], strings, len);
|
||||
xfree(strings);
|
||||
|
||||
strings = (char *)&ret[*num];
|
||||
for (p = strings, *num = 0; p < strings + len; p += strlen(p) + 1)
|
||||
ret[(*num)++] = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Check if a path exists. Return 1 if it does. */
|
||||
int xenbus_exists(const char *dir, const char *node)
|
||||
{
|
||||
char **d;
|
||||
int dir_n;
|
||||
|
||||
d = xenbus_directory(dir, node, &dir_n);
|
||||
if (IS_ERR(d))
|
||||
return 0;
|
||||
xfree(d);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Get the value of a single file.
|
||||
* Returns a kmalloced value: call free() on it after use.
|
||||
* len indicates length in bytes.
|
||||
*/
|
||||
void *xenbus_read(const char *dir, const char *node, unsigned int *len)
|
||||
{
|
||||
return xs_single(XS_READ, join(dir, node), len);
|
||||
}
|
||||
|
||||
/* Write the value of a single file.
|
||||
* Returns -err on failure. createflags can be 0, O_CREAT, or O_CREAT|O_EXCL.
|
||||
*/
|
||||
int xenbus_write(const char *dir, const char *node,
|
||||
const char *string, int createflags)
|
||||
{
|
||||
const char *flags, *path;
|
||||
struct kvec iovec[3];
|
||||
|
||||
path = join(dir, node);
|
||||
/* Format: Flags (as string), path, data. */
|
||||
if (createflags == 0)
|
||||
flags = XS_WRITE_NONE;
|
||||
else if (createflags == O_CREAT)
|
||||
flags = XS_WRITE_CREATE;
|
||||
else if (createflags == (O_CREAT|O_EXCL))
|
||||
flags = XS_WRITE_CREATE_EXCL;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
iovec[0].iov_base = (void *)path;
|
||||
iovec[0].iov_len = strlen(path) + 1;
|
||||
iovec[1].iov_base = (void *)flags;
|
||||
iovec[1].iov_len = strlen(flags) + 1;
|
||||
iovec[2].iov_base = (void *)string;
|
||||
iovec[2].iov_len = strlen(string);
|
||||
|
||||
return xs_error(xs_talkv(XS_WRITE, iovec, ARRAY_SIZE(iovec), NULL));
|
||||
}
|
||||
|
||||
/* Create a new directory. */
|
||||
int xenbus_mkdir(const char *dir, const char *node)
|
||||
{
|
||||
return xs_error(xs_single(XS_MKDIR, join(dir, node), NULL));
|
||||
}
|
||||
|
||||
/* Destroy a file or directory (directories must be empty). */
|
||||
int xenbus_rm(const char *dir, const char *node)
|
||||
{
|
||||
return xs_error(xs_single(XS_RM, join(dir, node), NULL));
|
||||
}
|
||||
|
||||
/* Start a transaction: changes by others will not be seen during this
|
||||
* transaction, and changes will not be visible to others until end.
|
||||
* Transaction only applies to the given subtree.
|
||||
* You can only have one transaction at any time.
|
||||
*/
|
||||
int xenbus_transaction_start(const char *subtree)
|
||||
{
|
||||
return xs_error(xs_single(XS_TRANSACTION_START, subtree, NULL));
|
||||
}
|
||||
|
||||
/* End a transaction.
|
||||
* If abandon is true, transaction is discarded instead of committed.
|
||||
*/
|
||||
int xenbus_transaction_end(int abort)
|
||||
{
|
||||
char abortstr[2];
|
||||
|
||||
if (abort)
|
||||
strcpy(abortstr, "F");
|
||||
else
|
||||
strcpy(abortstr, "T");
|
||||
return xs_error(xs_single(XS_TRANSACTION_END, abortstr, NULL));
|
||||
}
|
||||
|
||||
/* Single read and scanf: returns -errno or num scanned. */
|
||||
int xenbus_scanf(const char *dir, const char *node, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
char *val;
|
||||
|
||||
val = xenbus_read(dir, node, NULL);
|
||||
if (IS_ERR(val))
|
||||
return PTR_ERR(val);
|
||||
|
||||
va_start(ap, fmt);
|
||||
ret = vsscanf(val, fmt, ap);
|
||||
va_end(ap);
|
||||
xfree(val);
|
||||
/* Distinctive errno. */
|
||||
if (ret == 0)
|
||||
return -ERANGE;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Single printf and write: returns -errno or 0. */
|
||||
int xenbus_printf(const char *dir, const char *node, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
//BUG_ON(down_trylock(&xenbus_lock) == 0);
|
||||
va_start(ap, fmt);
|
||||
ret = vsnprintf(printf_buffer, sizeof(printf_buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
//BUG_ON(ret > sizeof(printf_buffer)-1);
|
||||
return xenbus_write(dir, node, printf_buffer, O_CREAT);
|
||||
}
|
||||
|
||||
|
||||
/* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
|
||||
int xenbus_gather(const char *dir, ...)
|
||||
{
|
||||
va_list ap;
|
||||
const char *name;
|
||||
int ret = 0;
|
||||
|
||||
va_start(ap, dir);
|
||||
while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
|
||||
const char *fmt = va_arg(ap, char *);
|
||||
void *result = va_arg(ap, void *);
|
||||
char *p;
|
||||
|
||||
p = xenbus_read(dir, name, NULL);
|
||||
if (IS_ERR(p)) {
|
||||
ret = PTR_ERR(p);
|
||||
break;
|
||||
}
|
||||
if (fmt) {
|
||||
if (sscanf(p, fmt, result) == 0)
|
||||
ret = -EINVAL;
|
||||
xfree(p);
|
||||
} else
|
||||
*(char **)result = p;
|
||||
}
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xs_watch(const char *path, const char *token)
|
||||
{
|
||||
struct kvec iov[2];
|
||||
|
||||
iov[0].iov_base = (void *)path;
|
||||
iov[0].iov_len = strlen(path) + 1;
|
||||
iov[1].iov_base = (void *)token;
|
||||
iov[1].iov_len = strlen(token) + 1;
|
||||
|
||||
return xs_error(xs_talkv(XS_WATCH, iov, ARRAY_SIZE(iov), NULL));
|
||||
}
|
||||
|
||||
static char *xs_read_watch(char **token)
|
||||
{
|
||||
enum xsd_sockmsg_type type;
|
||||
char *ret;
|
||||
|
||||
ret = read_reply(&type, NULL);
|
||||
if (IS_ERR(ret))
|
||||
return ret;
|
||||
|
||||
//BUG_ON(type != XS_WATCH_EVENT);
|
||||
*token = ret + strlen(ret) + 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int xs_acknowledge_watch(const char *token)
|
||||
{
|
||||
return xs_error(xs_single(XS_WATCH_ACK, token, NULL));
|
||||
}
|
||||
|
||||
static int xs_unwatch(const char *path, const char *token)
|
||||
{
|
||||
struct kvec iov[2];
|
||||
|
||||
iov[0].iov_base = (char *)path;
|
||||
iov[0].iov_len = strlen(path) + 1;
|
||||
iov[1].iov_base = (char *)token;
|
||||
iov[1].iov_len = strlen(token) + 1;
|
||||
|
||||
return xs_error(xs_talkv(XS_UNWATCH, iov, ARRAY_SIZE(iov), NULL));
|
||||
}
|
||||
|
||||
/* A little paranoia: we don't just trust token. */
|
||||
static struct xenbus_watch *find_watch(const char *token)
|
||||
{
|
||||
struct xenbus_watch *i, *cmp;
|
||||
|
||||
cmp = (void *)simple_strtoul(token, NULL, 16);
|
||||
|
||||
list_for_each_entry(i, &watches, list)
|
||||
if (i == cmp)
|
||||
return i;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Register callback to watch this node. */
|
||||
int register_xenbus_watch(struct xenbus_watch *watch)
|
||||
{
|
||||
/* Pointer in ascii is the token. */
|
||||
char token[sizeof(watch) * 2 + 1];
|
||||
int err;
|
||||
|
||||
sprintf(token, "%lX", (long)watch);
|
||||
//BUG_ON(find_watch(token));
|
||||
printk("Registered watch for: %s\n", token);
|
||||
err = xs_watch(watch->node, token);
|
||||
if (!err)
|
||||
list_add(&watch->list, &watches);
|
||||
return err;
|
||||
}
|
||||
|
||||
void unregister_xenbus_watch(struct xenbus_watch *watch)
|
||||
{
|
||||
char token[sizeof(watch) * 2 + 1];
|
||||
int err;
|
||||
|
||||
sprintf(token, "%lX", (long)watch);
|
||||
//BUG_ON(!find_watch(token));
|
||||
|
||||
err = xs_unwatch(watch->node, token);
|
||||
list_del(&watch->list);
|
||||
|
||||
if (err)
|
||||
printk("XENBUS Failed to release watch %s: %i\n",
|
||||
watch->node, err);
|
||||
}
|
||||
|
||||
/* Re-register callbacks to all watches. */
|
||||
void reregister_xenbus_watches(void)
|
||||
{
|
||||
struct xenbus_watch *watch;
|
||||
char token[sizeof(watch) * 2 + 1];
|
||||
|
||||
list_for_each_entry(watch, &watches, list) {
|
||||
sprintf(token, "%lX", (long)watch);
|
||||
xs_watch(watch->node, token);
|
||||
}
|
||||
}
|
||||
|
||||
void watch_thread(void *unused)
|
||||
{
|
||||
for (;;) {
|
||||
char *token;
|
||||
char *node = NULL;
|
||||
|
||||
wait_event(xb_waitq, xs_input_avail());
|
||||
|
||||
/* If this is a spurious wakeup caused by someone
|
||||
* doing an op, they'll hold the lock and the buffer
|
||||
* will be empty by the time we get there.
|
||||
*/
|
||||
down(&xenbus_lock);
|
||||
if (xs_input_avail())
|
||||
node = xs_read_watch(&token);
|
||||
|
||||
if (node && !IS_ERR(node)) {
|
||||
struct xenbus_watch *w;
|
||||
int err;
|
||||
|
||||
err = xs_acknowledge_watch(token);
|
||||
if (err)
|
||||
printk("XENBUS ack %s fail %i\n", node, err);
|
||||
w = find_watch(token);
|
||||
//BUG_ON(!w);
|
||||
w->callback(w, node);
|
||||
xfree(node);
|
||||
} else
|
||||
printk("XENBUS xs_read_watch: %li\n", PTR_ERR(node));
|
||||
up(&xenbus_lock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ballon_changed(struct xenbus_watch *watch, const char *node)
|
||||
{
|
||||
unsigned long new_target;
|
||||
int err;
|
||||
err = xenbus_scanf("memory", "target", "%lu", &new_target);
|
||||
|
||||
if(err != 1)
|
||||
{
|
||||
printk("Unable to read memory/target\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printk("Memory target changed to: %ld bytes, ignoring.\n", new_target);
|
||||
}
|
||||
|
||||
|
||||
static struct xenbus_watch ballon_watch = {
|
||||
.node = "memory/target",
|
||||
.callback = ballon_changed,
|
||||
};
|
||||
|
||||
|
||||
|
||||
int xs_init(void)
|
||||
{
|
||||
int err;
|
||||
struct thread *watcher;
|
||||
printk("xb_init_comms\n");
|
||||
err = xb_init_comms();
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
watcher = create_thread("kxwatch", watch_thread, NULL);
|
||||
down(&xenbus_lock);
|
||||
register_xenbus_watch(&ballon_watch);
|
||||
up(&xenbus_lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -776,8 +776,8 @@ static void blkif_completion(struct blk_shadow *s)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < s->req.nr_segments; i++)
|
||||
gnttab_free_grant_reference(
|
||||
blkif_gref_from_fas(s->req.frame_and_sects[i]));
|
||||
gnttab_end_foreign_access(
|
||||
blkif_gref_from_fas(s->req.frame_and_sects[i]), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -29,136 +29,163 @@
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/dst.h>
|
||||
|
||||
static int nloopbacks = 1;
|
||||
module_param(nloopbacks, int, 0);
|
||||
MODULE_PARM_DESC(nloopbacks, "Number of netback-loopback devices to create");
|
||||
|
||||
struct net_private {
|
||||
struct net_device *loopback_dev;
|
||||
struct net_device_stats stats;
|
||||
struct net_device *loopback_dev;
|
||||
struct net_device_stats stats;
|
||||
};
|
||||
|
||||
static int loopback_open(struct net_device *dev)
|
||||
{
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
memset(&np->stats, 0, sizeof(np->stats));
|
||||
netif_start_queue(dev);
|
||||
return 0;
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
memset(&np->stats, 0, sizeof(np->stats));
|
||||
netif_start_queue(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loopback_close(struct net_device *dev)
|
||||
{
|
||||
netif_stop_queue(dev);
|
||||
return 0;
|
||||
netif_stop_queue(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int loopback_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
|
||||
dst_release(skb->dst);
|
||||
skb->dst = NULL;
|
||||
dst_release(skb->dst);
|
||||
skb->dst = NULL;
|
||||
|
||||
skb_orphan(skb);
|
||||
skb_orphan(skb);
|
||||
|
||||
np->stats.tx_bytes += skb->len;
|
||||
np->stats.tx_packets++;
|
||||
np->stats.tx_bytes += skb->len;
|
||||
np->stats.tx_packets++;
|
||||
|
||||
/* Switch to loopback context. */
|
||||
dev = np->loopback_dev;
|
||||
np = netdev_priv(dev);
|
||||
/* Switch to loopback context. */
|
||||
dev = np->loopback_dev;
|
||||
np = netdev_priv(dev);
|
||||
|
||||
np->stats.rx_bytes += skb->len;
|
||||
np->stats.rx_packets++;
|
||||
np->stats.rx_bytes += skb->len;
|
||||
np->stats.rx_packets++;
|
||||
|
||||
if ( skb->ip_summed == CHECKSUM_HW )
|
||||
{
|
||||
/* Defer checksum calculation. */
|
||||
skb->proto_csum_blank = 1;
|
||||
/* Must be a local packet: assert its integrity. */
|
||||
skb->proto_csum_valid = 1;
|
||||
}
|
||||
if (skb->ip_summed == CHECKSUM_HW) {
|
||||
/* Defer checksum calculation. */
|
||||
skb->proto_csum_blank = 1;
|
||||
/* Must be a local packet: assert its integrity. */
|
||||
skb->proto_csum_valid = 1;
|
||||
}
|
||||
|
||||
skb->ip_summed = skb->proto_csum_valid ?
|
||||
CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
|
||||
skb->ip_summed = skb->proto_csum_valid ?
|
||||
CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
|
||||
|
||||
skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
skb->dev = dev;
|
||||
dev->last_rx = jiffies;
|
||||
netif_rx(skb);
|
||||
skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
skb->dev = dev;
|
||||
dev->last_rx = jiffies;
|
||||
netif_rx(skb);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct net_device_stats *loopback_get_stats(struct net_device *dev)
|
||||
{
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
return &np->stats;
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
return &np->stats;
|
||||
}
|
||||
|
||||
static void loopback_construct(struct net_device *dev, struct net_device *lo)
|
||||
{
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
struct net_private *np = netdev_priv(dev);
|
||||
|
||||
np->loopback_dev = lo;
|
||||
np->loopback_dev = lo;
|
||||
|
||||
dev->open = loopback_open;
|
||||
dev->stop = loopback_close;
|
||||
dev->hard_start_xmit = loopback_start_xmit;
|
||||
dev->get_stats = loopback_get_stats;
|
||||
dev->open = loopback_open;
|
||||
dev->stop = loopback_close;
|
||||
dev->hard_start_xmit = loopback_start_xmit;
|
||||
dev->get_stats = loopback_get_stats;
|
||||
|
||||
dev->tx_queue_len = 0;
|
||||
dev->tx_queue_len = 0;
|
||||
|
||||
dev->features = NETIF_F_HIGHDMA | NETIF_F_LLTX;
|
||||
dev->features = NETIF_F_HIGHDMA | NETIF_F_LLTX;
|
||||
|
||||
/*
|
||||
* We do not set a jumbo MTU on the interface. Otherwise the network
|
||||
* stack will try to send large packets that will get dropped by the
|
||||
* Ethernet bridge (unless the physical Ethernet interface is configured
|
||||
* to transfer jumbo packets). If a larger MTU is desired then the system
|
||||
* administrator can specify it using the 'ifconfig' command.
|
||||
*/
|
||||
/*dev->mtu = 16*1024;*/
|
||||
/*
|
||||
* We do not set a jumbo MTU on the interface. Otherwise the network
|
||||
* stack will try to send large packets that will get dropped by the
|
||||
* Ethernet bridge (unless the physical Ethernet interface is
|
||||
* configured to transfer jumbo packets). If a larger MTU is desired
|
||||
* then the system administrator can specify it using the 'ifconfig'
|
||||
* command.
|
||||
*/
|
||||
/*dev->mtu = 16*1024;*/
|
||||
}
|
||||
|
||||
static int __init make_loopback(int i)
|
||||
{
|
||||
struct net_device *dev1, *dev2;
|
||||
char dev_name[IFNAMSIZ];
|
||||
int err = -ENOMEM;
|
||||
|
||||
sprintf(dev_name, "vif0.%d", i);
|
||||
dev1 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
|
||||
sprintf(dev_name, "veth%d", i);
|
||||
dev2 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
|
||||
if ((dev1 == NULL) || (dev2 == NULL))
|
||||
goto fail;
|
||||
|
||||
loopback_construct(dev1, dev2);
|
||||
loopback_construct(dev2, dev1);
|
||||
|
||||
dev1->features |= NETIF_F_NO_CSUM;
|
||||
dev2->features |= NETIF_F_IP_CSUM;
|
||||
|
||||
/*
|
||||
* Initialise a dummy MAC address for the 'dummy backend' interface. We
|
||||
* choose the numerically largest non-broadcast address to prevent the
|
||||
* address getting stolen by an Ethernet bridge for STP purposes.
|
||||
*/
|
||||
memset(dev1->dev_addr, 0xFF, ETH_ALEN);
|
||||
dev1->dev_addr[0] &= ~0x01;
|
||||
|
||||
if ((err = register_netdev(dev1)) != 0)
|
||||
goto fail;
|
||||
|
||||
if ((err = register_netdev(dev2)) != 0) {
|
||||
unregister_netdev(dev1);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (dev1 != NULL)
|
||||
kfree(dev1);
|
||||
if (dev2 != NULL)
|
||||
kfree(dev2);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init loopback_init(void)
|
||||
{
|
||||
struct net_device *dev1, *dev2;
|
||||
int err = -ENOMEM;
|
||||
int i, err = 0;
|
||||
|
||||
dev1 = alloc_netdev(sizeof(struct net_private), "vif0.0", ether_setup);
|
||||
dev2 = alloc_netdev(sizeof(struct net_private), "veth0", ether_setup);
|
||||
if ( (dev1 == NULL) || (dev2 == NULL) )
|
||||
goto fail;
|
||||
for (i = 0; i < nloopbacks; i++)
|
||||
if ((err = make_loopback(i)) != 0)
|
||||
break;
|
||||
|
||||
loopback_construct(dev1, dev2);
|
||||
loopback_construct(dev2, dev1);
|
||||
|
||||
dev1->features |= NETIF_F_NO_CSUM;
|
||||
dev2->features |= NETIF_F_IP_CSUM;
|
||||
|
||||
/*
|
||||
* Initialise a dummy MAC address for the 'dummy backend' interface. We
|
||||
* choose the numerically largest non-broadcast address to prevent the
|
||||
* address getting stolen by an Ethernet bridge for STP purposes.
|
||||
*/
|
||||
memset(dev1->dev_addr, 0xFF, ETH_ALEN);
|
||||
dev1->dev_addr[0] &= ~0x01;
|
||||
|
||||
if ( (err = register_netdev(dev1)) != 0 )
|
||||
goto fail;
|
||||
|
||||
if ( (err = register_netdev(dev2)) != 0 )
|
||||
{
|
||||
unregister_netdev(dev1);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if ( dev1 != NULL )
|
||||
kfree(dev1);
|
||||
if ( dev2 != NULL )
|
||||
kfree(dev2);
|
||||
return err;
|
||||
return err;
|
||||
}
|
||||
|
||||
module_init(loopback_init);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* indent-tabs-mode: t
|
||||
* c-indent-level: 8
|
||||
* c-basic-offset: 8
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
||||
@@ -93,7 +93,9 @@ static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
|
||||
&path))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_read(xh, path, &xsval_n);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval) {
|
||||
val = pyvalue_int(0);
|
||||
goto exit;
|
||||
@@ -140,7 +142,9 @@ static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
flags |= O_CREAT;
|
||||
if (excl)
|
||||
flags |= O_EXCL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_write(xh, path, data, data_n, flags);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
return val;
|
||||
@@ -170,7 +174,9 @@ static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_directory(xh, path, &xsval_n);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval) {
|
||||
val = pyvalue_int(0);
|
||||
goto exit;
|
||||
@@ -204,7 +210,9 @@ static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_mkdir(xh, path);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
return val;
|
||||
@@ -232,7 +240,9 @@ static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_rm(xh, path);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
return val;
|
||||
@@ -263,7 +273,9 @@ static PyObject *xspy_get_permissions(PyObject *self, PyObject *args,
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
perms = xs_get_permissions(xh, path, &perms_n);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!perms) {
|
||||
PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
goto exit;
|
||||
@@ -339,7 +351,9 @@ static PyObject *xspy_set_permissions(PyObject *self, PyObject *args,
|
||||
if (p_write)
|
||||
xsperms[i].perms |= XS_PERM_WRITE;
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_set_permissions(xh, path, xsperms, xsperms_n);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
Py_XDECREF(tuple0);
|
||||
@@ -381,7 +395,9 @@ static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
goto exit;
|
||||
Py_INCREF(token);
|
||||
sprintf(token_str, "%li", (unsigned long)token);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_watch(xh, path, token_str);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval) {
|
||||
val = PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
Py_DECREF(token);
|
||||
@@ -429,7 +445,9 @@ static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_read_watch(xh);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval) {
|
||||
val = PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
goto exit;
|
||||
@@ -479,7 +497,9 @@ static PyObject *xspy_acknowledge_watch(PyObject *self, PyObject *args,
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &token))
|
||||
goto exit;
|
||||
sprintf(token_str, "%li", (unsigned long)token);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_acknowledge_watch(xh, token_str);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval) {
|
||||
val = PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
goto exit;
|
||||
@@ -519,7 +539,9 @@ static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
&token))
|
||||
goto exit;
|
||||
sprintf(token_str, "%li", (unsigned long)token);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_unwatch(xh, path, token_str);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (!xsval)
|
||||
val = PyErr_SetFromErrno(PyExc_RuntimeError);
|
||||
else {
|
||||
@@ -561,7 +583,9 @@ static PyObject *xspy_transaction_start(PyObject *self, PyObject *args,
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_transaction_start(xh, path);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
return val;
|
||||
@@ -591,7 +615,9 @@ static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &abort))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_transaction_end(xh, abort);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
return val;
|
||||
@@ -627,7 +653,9 @@ static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
|
||||
&dom, &page, &port, &path))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_introduce_domain(xh, dom, page, port, path);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
return val;
|
||||
@@ -658,7 +686,9 @@ static PyObject *xspy_release_domain(PyObject *self, PyObject *args,
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
|
||||
&dom))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_release_domain(xh, dom);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
return val;
|
||||
@@ -718,7 +748,9 @@ static PyObject *xspy_shutdown(PyObject *self, PyObject *args, PyObject *kwds)
|
||||
goto exit;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
|
||||
goto exit;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
xsval = xs_shutdown(xh);
|
||||
Py_END_ALLOW_THREADS
|
||||
val = pyvalue_int(xsval);
|
||||
exit:
|
||||
return val;
|
||||
|
||||