mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-09-22 04:31:58 +08:00
Merge branch 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml
Pull UML fixes from Richard Weinberger: "This patch set contains mostly fixes and cleanups. The UML tty driver uses now tty_port and is no longer broken like hell :-)" * 'for-linus-3.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rw/uml: um: Add arch/x86/um to MAINTAINERS um: pass siginfo to guest process um: fix ubd_file_size for read-only files um: pull interrupt_end() into userspace() um: split syscall_trace(), pass pt_regs to it um: switch UPT_SET_RETURN_VALUE and regs_return_value to pt_regs um: set BLK_CGROUP=y in defconfig um: remove count_lock um: fully use tty_port um: Remove dead code um: remove line_ioctl() TTY: um/line, use tty from tty_port TTY: um/line, add tty_port
This commit is contained in:
commit
1871e845e5
@ -7382,6 +7382,7 @@ W: http://user-mode-linux.sourceforge.net
|
|||||||
S: Maintained
|
S: Maintained
|
||||||
F: Documentation/virtual/uml/
|
F: Documentation/virtual/uml/
|
||||||
F: arch/um/
|
F: arch/um/
|
||||||
|
F: arch/x86/um/
|
||||||
F: fs/hostfs/
|
F: fs/hostfs/
|
||||||
F: fs/hppfs/
|
F: fs/hppfs/
|
||||||
|
|
||||||
|
@ -163,7 +163,7 @@ CONFIG_CGROUP_SCHED=y
|
|||||||
CONFIG_FAIR_GROUP_SCHED=y
|
CONFIG_FAIR_GROUP_SCHED=y
|
||||||
# CONFIG_CFS_BANDWIDTH is not set
|
# CONFIG_CFS_BANDWIDTH is not set
|
||||||
# CONFIG_RT_GROUP_SCHED is not set
|
# CONFIG_RT_GROUP_SCHED is not set
|
||||||
CONFIG_BLK_CGROUP=m
|
CONFIG_BLK_CGROUP=y
|
||||||
# CONFIG_DEBUG_BLK_CGROUP is not set
|
# CONFIG_DEBUG_BLK_CGROUP is not set
|
||||||
# CONFIG_CHECKPOINT_RESTORE is not set
|
# CONFIG_CHECKPOINT_RESTORE is not set
|
||||||
CONFIG_NAMESPACES=y
|
CONFIG_NAMESPACES=y
|
||||||
|
@ -150,9 +150,11 @@ void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
|
|||||||
static void line_timer_cb(struct work_struct *work)
|
static void line_timer_cb(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct line *line = container_of(work, struct line, task.work);
|
struct line *line = container_of(work, struct line, task.work);
|
||||||
|
struct tty_struct *tty = tty_port_tty_get(&line->port);
|
||||||
|
|
||||||
if (!line->throttled)
|
if (!line->throttled)
|
||||||
chan_interrupt(line, line->tty, line->driver->read_irq);
|
chan_interrupt(line, tty, line->driver->read_irq);
|
||||||
|
tty_kref_put(tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
int enable_chan(struct line *line)
|
int enable_chan(struct line *line)
|
||||||
|
@ -19,9 +19,11 @@ static irqreturn_t line_interrupt(int irq, void *data)
|
|||||||
{
|
{
|
||||||
struct chan *chan = data;
|
struct chan *chan = data;
|
||||||
struct line *line = chan->line;
|
struct line *line = chan->line;
|
||||||
|
struct tty_struct *tty = tty_port_tty_get(&line->port);
|
||||||
|
|
||||||
if (line)
|
if (line)
|
||||||
chan_interrupt(line, line->tty, irq);
|
chan_interrupt(line, tty, irq);
|
||||||
|
tty_kref_put(tty);
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,92 +221,6 @@ void line_set_termios(struct tty_struct *tty, struct ktermios * old)
|
|||||||
/* nothing */
|
/* nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
|
||||||
int cmd;
|
|
||||||
char *level;
|
|
||||||
char *name;
|
|
||||||
} tty_ioctls[] = {
|
|
||||||
/* don't print these, they flood the log ... */
|
|
||||||
{ TCGETS, NULL, "TCGETS" },
|
|
||||||
{ TCSETS, NULL, "TCSETS" },
|
|
||||||
{ TCSETSW, NULL, "TCSETSW" },
|
|
||||||
{ TCFLSH, NULL, "TCFLSH" },
|
|
||||||
{ TCSBRK, NULL, "TCSBRK" },
|
|
||||||
|
|
||||||
/* general tty stuff */
|
|
||||||
{ TCSETSF, KERN_DEBUG, "TCSETSF" },
|
|
||||||
{ TCGETA, KERN_DEBUG, "TCGETA" },
|
|
||||||
{ TIOCMGET, KERN_DEBUG, "TIOCMGET" },
|
|
||||||
{ TCSBRKP, KERN_DEBUG, "TCSBRKP" },
|
|
||||||
{ TIOCMSET, KERN_DEBUG, "TIOCMSET" },
|
|
||||||
|
|
||||||
/* linux-specific ones */
|
|
||||||
{ TIOCLINUX, KERN_INFO, "TIOCLINUX" },
|
|
||||||
{ KDGKBMODE, KERN_INFO, "KDGKBMODE" },
|
|
||||||
{ KDGKBTYPE, KERN_INFO, "KDGKBTYPE" },
|
|
||||||
{ KDSIGACCEPT, KERN_INFO, "KDSIGACCEPT" },
|
|
||||||
};
|
|
||||||
|
|
||||||
int line_ioctl(struct tty_struct *tty, unsigned int cmd,
|
|
||||||
unsigned long arg)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ret = 0;
|
|
||||||
switch(cmd) {
|
|
||||||
#ifdef TIOCGETP
|
|
||||||
case TIOCGETP:
|
|
||||||
case TIOCSETP:
|
|
||||||
case TIOCSETN:
|
|
||||||
#endif
|
|
||||||
#ifdef TIOCGETC
|
|
||||||
case TIOCGETC:
|
|
||||||
case TIOCSETC:
|
|
||||||
#endif
|
|
||||||
#ifdef TIOCGLTC
|
|
||||||
case TIOCGLTC:
|
|
||||||
case TIOCSLTC:
|
|
||||||
#endif
|
|
||||||
/* Note: these are out of date as we now have TCGETS2 etc but this
|
|
||||||
whole lot should probably go away */
|
|
||||||
case TCGETS:
|
|
||||||
case TCSETSF:
|
|
||||||
case TCSETSW:
|
|
||||||
case TCSETS:
|
|
||||||
case TCGETA:
|
|
||||||
case TCSETAF:
|
|
||||||
case TCSETAW:
|
|
||||||
case TCSETA:
|
|
||||||
case TCXONC:
|
|
||||||
case TCFLSH:
|
|
||||||
case TIOCOUTQ:
|
|
||||||
case TIOCINQ:
|
|
||||||
case TIOCGLCKTRMIOS:
|
|
||||||
case TIOCSLCKTRMIOS:
|
|
||||||
case TIOCPKT:
|
|
||||||
case TIOCGSOFTCAR:
|
|
||||||
case TIOCSSOFTCAR:
|
|
||||||
return -ENOIOCTLCMD;
|
|
||||||
#if 0
|
|
||||||
case TCwhatever:
|
|
||||||
/* do something */
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
for (i = 0; i < ARRAY_SIZE(tty_ioctls); i++)
|
|
||||||
if (cmd == tty_ioctls[i].cmd)
|
|
||||||
break;
|
|
||||||
if (i == ARRAY_SIZE(tty_ioctls)) {
|
|
||||||
printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n",
|
|
||||||
__func__, tty->name, cmd);
|
|
||||||
}
|
|
||||||
ret = -ENOIOCTLCMD;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void line_throttle(struct tty_struct *tty)
|
void line_throttle(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct line *line = tty->driver_data;
|
struct line *line = tty->driver_data;
|
||||||
@ -333,7 +249,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
|
|||||||
{
|
{
|
||||||
struct chan *chan = data;
|
struct chan *chan = data;
|
||||||
struct line *line = chan->line;
|
struct line *line = chan->line;
|
||||||
struct tty_struct *tty = line->tty;
|
struct tty_struct *tty;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -352,10 +268,13 @@ static irqreturn_t line_write_interrupt(int irq, void *data)
|
|||||||
}
|
}
|
||||||
spin_unlock(&line->lock);
|
spin_unlock(&line->lock);
|
||||||
|
|
||||||
|
tty = tty_port_tty_get(&line->port);
|
||||||
if (tty == NULL)
|
if (tty == NULL)
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
tty_wakeup(tty);
|
tty_wakeup(tty);
|
||||||
|
tty_kref_put(tty);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,43 +296,14 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int line_activate(struct tty_port *port, struct tty_struct *tty)
|
||||||
* Normally, a driver like this can rely mostly on the tty layer
|
|
||||||
* locking, particularly when it comes to the driver structure.
|
|
||||||
* However, in this case, mconsole requests can come in "from the
|
|
||||||
* side", and race with opens and closes.
|
|
||||||
*
|
|
||||||
* mconsole config requests will want to be sure the device isn't in
|
|
||||||
* use, and get_config, open, and close will want a stable
|
|
||||||
* configuration. The checking and modification of the configuration
|
|
||||||
* is done under a spinlock. Checking whether the device is in use is
|
|
||||||
* line->tty->count > 1, also under the spinlock.
|
|
||||||
*
|
|
||||||
* line->count serves to decide whether the device should be enabled or
|
|
||||||
* disabled on the host. If it's equal to 0, then we are doing the
|
|
||||||
* first open or last close. Otherwise, open and close just return.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int line_open(struct line *lines, struct tty_struct *tty)
|
|
||||||
{
|
{
|
||||||
struct line *line = &lines[tty->index];
|
int ret;
|
||||||
int err = -ENODEV;
|
struct line *line = tty->driver_data;
|
||||||
|
|
||||||
mutex_lock(&line->count_lock);
|
ret = enable_chan(line);
|
||||||
if (!line->valid)
|
if (ret)
|
||||||
goto out_unlock;
|
return ret;
|
||||||
|
|
||||||
err = 0;
|
|
||||||
if (line->count++)
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
BUG_ON(tty->driver_data);
|
|
||||||
tty->driver_data = line;
|
|
||||||
line->tty = tty;
|
|
||||||
|
|
||||||
err = enable_chan(line);
|
|
||||||
if (err) /* line_close() will be called by our caller */
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
if (!line->sigio) {
|
if (!line->sigio) {
|
||||||
chan_enable_winch(line->chan_out, tty);
|
chan_enable_winch(line->chan_out, tty);
|
||||||
@ -422,43 +312,59 @@ int line_open(struct line *lines, struct tty_struct *tty)
|
|||||||
|
|
||||||
chan_window_size(line, &tty->winsize.ws_row,
|
chan_window_size(line, &tty->winsize.ws_row,
|
||||||
&tty->winsize.ws_col);
|
&tty->winsize.ws_col);
|
||||||
out_unlock:
|
|
||||||
mutex_unlock(&line->count_lock);
|
return 0;
|
||||||
return err;
|
}
|
||||||
|
|
||||||
|
static const struct tty_port_operations line_port_ops = {
|
||||||
|
.activate = line_activate,
|
||||||
|
};
|
||||||
|
|
||||||
|
int line_open(struct tty_struct *tty, struct file *filp)
|
||||||
|
{
|
||||||
|
struct line *line = tty->driver_data;
|
||||||
|
|
||||||
|
return tty_port_open(&line->port, tty, filp);
|
||||||
|
}
|
||||||
|
|
||||||
|
int line_install(struct tty_driver *driver, struct tty_struct *tty,
|
||||||
|
struct line *line)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = tty_standard_install(driver, tty);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
tty->driver_data = line;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void unregister_winch(struct tty_struct *tty);
|
static void unregister_winch(struct tty_struct *tty);
|
||||||
|
|
||||||
void line_close(struct tty_struct *tty, struct file * filp)
|
void line_cleanup(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
struct line *line = tty->driver_data;
|
struct line *line = tty->driver_data;
|
||||||
|
|
||||||
/*
|
|
||||||
* If line_open fails (and tty->driver_data is never set),
|
|
||||||
* tty_open will call line_close. So just return in this case.
|
|
||||||
*/
|
|
||||||
if (line == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* We ignore the error anyway! */
|
|
||||||
flush_buffer(line);
|
|
||||||
|
|
||||||
mutex_lock(&line->count_lock);
|
|
||||||
BUG_ON(!line->valid);
|
|
||||||
|
|
||||||
if (--line->count)
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
line->tty = NULL;
|
|
||||||
tty->driver_data = NULL;
|
|
||||||
|
|
||||||
if (line->sigio) {
|
if (line->sigio) {
|
||||||
unregister_winch(tty);
|
unregister_winch(tty);
|
||||||
line->sigio = 0;
|
line->sigio = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
out_unlock:
|
void line_close(struct tty_struct *tty, struct file * filp)
|
||||||
mutex_unlock(&line->count_lock);
|
{
|
||||||
|
struct line *line = tty->driver_data;
|
||||||
|
|
||||||
|
tty_port_close(&line->port, tty, filp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void line_hangup(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct line *line = tty->driver_data;
|
||||||
|
|
||||||
|
tty_port_hangup(&line->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
void close_lines(struct line *lines, int nlines)
|
void close_lines(struct line *lines, int nlines)
|
||||||
@ -476,9 +382,7 @@ int setup_one_line(struct line *lines, int n, char *init,
|
|||||||
struct tty_driver *driver = line->driver->driver;
|
struct tty_driver *driver = line->driver->driver;
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&line->count_lock);
|
if (line->port.count) {
|
||||||
|
|
||||||
if (line->count) {
|
|
||||||
*error_out = "Device is already open";
|
*error_out = "Device is already open";
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -519,7 +423,6 @@ int setup_one_line(struct line *lines, int n, char *init,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
mutex_unlock(&line->count_lock);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -607,13 +510,17 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
|
|||||||
|
|
||||||
line = &lines[dev];
|
line = &lines[dev];
|
||||||
|
|
||||||
mutex_lock(&line->count_lock);
|
|
||||||
if (!line->valid)
|
if (!line->valid)
|
||||||
CONFIG_CHUNK(str, size, n, "none", 1);
|
CONFIG_CHUNK(str, size, n, "none", 1);
|
||||||
else if (line->tty == NULL)
|
else {
|
||||||
|
struct tty_struct *tty = tty_port_tty_get(&line->port);
|
||||||
|
if (tty == NULL) {
|
||||||
CONFIG_CHUNK(str, size, n, line->init_str, 1);
|
CONFIG_CHUNK(str, size, n, line->init_str, 1);
|
||||||
else n = chan_config_string(line, str, size, error_out);
|
} else {
|
||||||
mutex_unlock(&line->count_lock);
|
n = chan_config_string(line, str, size, error_out);
|
||||||
|
tty_kref_put(tty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@ -663,8 +570,9 @@ int register_lines(struct line_driver *line_driver,
|
|||||||
driver->init_termios = tty_std_termios;
|
driver->init_termios = tty_std_termios;
|
||||||
|
|
||||||
for (i = 0; i < nlines; i++) {
|
for (i = 0; i < nlines; i++) {
|
||||||
|
tty_port_init(&lines[i].port);
|
||||||
|
lines[i].port.ops = &line_port_ops;
|
||||||
spin_lock_init(&lines[i].lock);
|
spin_lock_init(&lines[i].lock);
|
||||||
mutex_init(&lines[i].count_lock);
|
|
||||||
lines[i].driver = line_driver;
|
lines[i].driver = line_driver;
|
||||||
INIT_LIST_HEAD(&lines[i].chan_list);
|
INIT_LIST_HEAD(&lines[i].chan_list);
|
||||||
}
|
}
|
||||||
|
@ -32,9 +32,7 @@ struct line_driver {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct line {
|
struct line {
|
||||||
struct tty_struct *tty;
|
struct tty_port port;
|
||||||
struct mutex count_lock;
|
|
||||||
unsigned long count;
|
|
||||||
int valid;
|
int valid;
|
||||||
|
|
||||||
char *init_str;
|
char *init_str;
|
||||||
@ -59,7 +57,11 @@ struct line {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern void line_close(struct tty_struct *tty, struct file * filp);
|
extern void line_close(struct tty_struct *tty, struct file * filp);
|
||||||
extern int line_open(struct line *lines, struct tty_struct *tty);
|
extern int line_open(struct tty_struct *tty, struct file *filp);
|
||||||
|
extern int line_install(struct tty_driver *driver, struct tty_struct *tty,
|
||||||
|
struct line *line);
|
||||||
|
extern void line_cleanup(struct tty_struct *tty);
|
||||||
|
extern void line_hangup(struct tty_struct *tty);
|
||||||
extern int line_setup(char **conf, unsigned nlines, char **def,
|
extern int line_setup(char **conf, unsigned nlines, char **def,
|
||||||
char *init, char *name);
|
char *init, char *name);
|
||||||
extern int line_write(struct tty_struct *tty, const unsigned char *buf,
|
extern int line_write(struct tty_struct *tty, const unsigned char *buf,
|
||||||
@ -70,8 +72,6 @@ extern int line_chars_in_buffer(struct tty_struct *tty);
|
|||||||
extern void line_flush_buffer(struct tty_struct *tty);
|
extern void line_flush_buffer(struct tty_struct *tty);
|
||||||
extern void line_flush_chars(struct tty_struct *tty);
|
extern void line_flush_chars(struct tty_struct *tty);
|
||||||
extern int line_write_room(struct tty_struct *tty);
|
extern int line_write_room(struct tty_struct *tty);
|
||||||
extern int line_ioctl(struct tty_struct *tty, unsigned int cmd,
|
|
||||||
unsigned long arg);
|
|
||||||
extern void line_throttle(struct tty_struct *tty);
|
extern void line_throttle(struct tty_struct *tty);
|
||||||
extern void line_unthrottle(struct tty_struct *tty);
|
extern void line_unthrottle(struct tty_struct *tty);
|
||||||
|
|
||||||
|
@ -87,40 +87,13 @@ static int ssl_remove(int n, char **error_out)
|
|||||||
error_out);
|
error_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ssl_open(struct tty_struct *tty, struct file *filp)
|
static int ssl_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
int err = line_open(serial_lines, tty);
|
return line_install(driver, tty, &serial_lines[tty->index]);
|
||||||
|
|
||||||
if (err)
|
|
||||||
printk(KERN_ERR "Failed to open serial line %d, err = %d\n",
|
|
||||||
tty->index, err);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void ssl_flush_buffer(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ssl_stop(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
printk(KERN_ERR "Someone should implement ssl_stop\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ssl_start(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
printk(KERN_ERR "Someone should implement ssl_start\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ssl_hangup(struct tty_struct *tty)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const struct tty_operations ssl_ops = {
|
static const struct tty_operations ssl_ops = {
|
||||||
.open = ssl_open,
|
.open = line_open,
|
||||||
.close = line_close,
|
.close = line_close,
|
||||||
.write = line_write,
|
.write = line_write,
|
||||||
.put_char = line_put_char,
|
.put_char = line_put_char,
|
||||||
@ -129,14 +102,11 @@ static const struct tty_operations ssl_ops = {
|
|||||||
.flush_buffer = line_flush_buffer,
|
.flush_buffer = line_flush_buffer,
|
||||||
.flush_chars = line_flush_chars,
|
.flush_chars = line_flush_chars,
|
||||||
.set_termios = line_set_termios,
|
.set_termios = line_set_termios,
|
||||||
.ioctl = line_ioctl,
|
|
||||||
.throttle = line_throttle,
|
.throttle = line_throttle,
|
||||||
.unthrottle = line_unthrottle,
|
.unthrottle = line_unthrottle,
|
||||||
#if 0
|
.install = ssl_install,
|
||||||
.stop = ssl_stop,
|
.cleanup = line_cleanup,
|
||||||
.start = ssl_start,
|
.hangup = line_hangup,
|
||||||
.hangup = ssl_hangup,
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
|
/* Changed by ssl_init and referenced by ssl_exit, which are both serialized
|
||||||
|
@ -89,21 +89,17 @@ static int con_remove(int n, char **error_out)
|
|||||||
return line_remove(vts, ARRAY_SIZE(vts), n, error_out);
|
return line_remove(vts, ARRAY_SIZE(vts), n, error_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int con_open(struct tty_struct *tty, struct file *filp)
|
|
||||||
{
|
|
||||||
int err = line_open(vts, tty);
|
|
||||||
if (err)
|
|
||||||
printk(KERN_ERR "Failed to open console %d, err = %d\n",
|
|
||||||
tty->index, err);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set in an initcall, checked in an exitcall */
|
/* Set in an initcall, checked in an exitcall */
|
||||||
static int con_init_done = 0;
|
static int con_init_done = 0;
|
||||||
|
|
||||||
|
static int con_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
return line_install(driver, tty, &vts[tty->index]);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct tty_operations console_ops = {
|
static const struct tty_operations console_ops = {
|
||||||
.open = con_open,
|
.open = line_open,
|
||||||
|
.install = con_install,
|
||||||
.close = line_close,
|
.close = line_close,
|
||||||
.write = line_write,
|
.write = line_write,
|
||||||
.put_char = line_put_char,
|
.put_char = line_put_char,
|
||||||
@ -112,9 +108,10 @@ static const struct tty_operations console_ops = {
|
|||||||
.flush_buffer = line_flush_buffer,
|
.flush_buffer = line_flush_buffer,
|
||||||
.flush_chars = line_flush_chars,
|
.flush_chars = line_flush_chars,
|
||||||
.set_termios = line_set_termios,
|
.set_termios = line_set_termios,
|
||||||
.ioctl = line_ioctl,
|
|
||||||
.throttle = line_throttle,
|
.throttle = line_throttle,
|
||||||
.unthrottle = line_unthrottle,
|
.unthrottle = line_unthrottle,
|
||||||
|
.cleanup = line_cleanup,
|
||||||
|
.hangup = line_hangup,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void uml_console_write(struct console *console, const char *string,
|
static void uml_console_write(struct console *console, const char *string,
|
||||||
|
@ -514,7 +514,7 @@ static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = os_open_file(ubd_dev->file, global_openflags, 0);
|
fd = os_open_file(ubd_dev->file, of_read(OPENFLAGS()), 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
|
@ -37,6 +37,8 @@ extern int putreg(struct task_struct *child, int regno, unsigned long value);
|
|||||||
|
|
||||||
extern int arch_copy_tls(struct task_struct *new);
|
extern int arch_copy_tls(struct task_struct *new);
|
||||||
extern void clear_flushed_tls(struct task_struct *task);
|
extern void clear_flushed_tls(struct task_struct *task);
|
||||||
|
extern void syscall_trace_enter(struct pt_regs *regs);
|
||||||
|
extern void syscall_trace_leave(struct pt_regs *regs);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -60,7 +60,8 @@ extern unsigned long host_task_size;
|
|||||||
|
|
||||||
extern int linux_main(int argc, char **argv);
|
extern int linux_main(int argc, char **argv);
|
||||||
|
|
||||||
extern void (*sig_info[])(int, struct uml_pt_regs *);
|
struct siginfo;
|
||||||
|
extern void (*sig_info[])(int, struct siginfo *si, struct uml_pt_regs *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -20,7 +20,8 @@ struct irq_fd {
|
|||||||
|
|
||||||
enum { IRQ_READ, IRQ_WRITE };
|
enum { IRQ_READ, IRQ_WRITE };
|
||||||
|
|
||||||
extern void sigio_handler(int sig, struct uml_pt_regs *regs);
|
struct siginfo;
|
||||||
|
extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
||||||
extern void free_irq_by_fd(int fd);
|
extern void free_irq_by_fd(int fd);
|
||||||
extern void reactivate_fd(int fd, int irqnum);
|
extern void reactivate_fd(int fd, int irqnum);
|
||||||
extern void deactivate_fd(int fd, int irqnum);
|
extern void deactivate_fd(int fd, int irqnum);
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#include "sysdep/ptrace.h"
|
#include "sysdep/ptrace.h"
|
||||||
#include "sysdep/faultinfo.h"
|
#include "sysdep/faultinfo.h"
|
||||||
|
|
||||||
|
struct siginfo;
|
||||||
|
|
||||||
extern int uml_exitcode;
|
extern int uml_exitcode;
|
||||||
|
|
||||||
extern int ncpus;
|
extern int ncpus;
|
||||||
@ -22,7 +24,7 @@ extern void free_stack(unsigned long stack, int order);
|
|||||||
|
|
||||||
extern int do_signal(void);
|
extern int do_signal(void);
|
||||||
extern void interrupt_end(void);
|
extern void interrupt_end(void);
|
||||||
extern void relay_signal(int sig, struct uml_pt_regs *regs);
|
extern void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs);
|
||||||
|
|
||||||
extern unsigned long segv(struct faultinfo fi, unsigned long ip,
|
extern unsigned long segv(struct faultinfo fi, unsigned long ip,
|
||||||
int is_user, struct uml_pt_regs *regs);
|
int is_user, struct uml_pt_regs *regs);
|
||||||
@ -33,9 +35,8 @@ extern unsigned int do_IRQ(int irq, struct uml_pt_regs *regs);
|
|||||||
extern int smp_sigio_handler(void);
|
extern int smp_sigio_handler(void);
|
||||||
extern void initial_thread_cb(void (*proc)(void *), void *arg);
|
extern void initial_thread_cb(void (*proc)(void *), void *arg);
|
||||||
extern int is_syscall(unsigned long addr);
|
extern int is_syscall(unsigned long addr);
|
||||||
extern void timer_handler(int sig, struct uml_pt_regs *regs);
|
|
||||||
|
|
||||||
extern void timer_handler(int sig, struct uml_pt_regs *regs);
|
extern void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
||||||
|
|
||||||
extern int start_uml(void);
|
extern int start_uml(void);
|
||||||
extern void paging_init(void);
|
extern void paging_init(void);
|
||||||
@ -59,9 +60,9 @@ extern unsigned long from_irq_stack(int nested);
|
|||||||
extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
|
extern void syscall_trace(struct uml_pt_regs *regs, int entryexit);
|
||||||
extern int singlestepping(void *t);
|
extern int singlestepping(void *t);
|
||||||
|
|
||||||
extern void segv_handler(int sig, struct uml_pt_regs *regs);
|
extern void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
||||||
extern void bus_handler(int sig, struct uml_pt_regs *regs);
|
extern void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs);
|
||||||
extern void winch(int sig, struct uml_pt_regs *regs);
|
extern void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
|
||||||
extern void fatal_sigsegv(void) __attribute__ ((noreturn));
|
extern void fatal_sigsegv(void) __attribute__ ((noreturn));
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ static struct irq_fd **last_irq_ptr = &active_fds;
|
|||||||
|
|
||||||
extern void free_irqs(void);
|
extern void free_irqs(void);
|
||||||
|
|
||||||
void sigio_handler(int sig, struct uml_pt_regs *regs)
|
void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct irq_fd *irq_fd;
|
struct irq_fd *irq_fd;
|
||||||
int n;
|
int n;
|
||||||
|
@ -151,12 +151,10 @@ void new_thread_handler(void)
|
|||||||
* 0 if it just exits
|
* 0 if it just exits
|
||||||
*/
|
*/
|
||||||
n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf);
|
n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf);
|
||||||
if (n == 1) {
|
if (n == 1)
|
||||||
/* Handle any immediate reschedules or signals */
|
|
||||||
interrupt_end();
|
|
||||||
userspace(¤t->thread.regs.regs);
|
userspace(¤t->thread.regs.regs);
|
||||||
}
|
else
|
||||||
else do_exit(0);
|
do_exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called magically, see new_thread_handler above */
|
/* Called magically, see new_thread_handler above */
|
||||||
@ -175,9 +173,6 @@ void fork_handler(void)
|
|||||||
|
|
||||||
current->thread.prev_sched = NULL;
|
current->thread.prev_sched = NULL;
|
||||||
|
|
||||||
/* Handle any immediate reschedules or signals */
|
|
||||||
interrupt_end();
|
|
||||||
|
|
||||||
userspace(¤t->thread.regs.regs);
|
userspace(¤t->thread.regs.regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +188,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp,
|
|||||||
if (current->thread.forking) {
|
if (current->thread.forking) {
|
||||||
memcpy(&p->thread.regs.regs, ®s->regs,
|
memcpy(&p->thread.regs.regs, ®s->regs,
|
||||||
sizeof(p->thread.regs.regs));
|
sizeof(p->thread.regs.regs));
|
||||||
UPT_SET_SYSCALL_RETURN(&p->thread.regs.regs, 0);
|
PT_REGS_SET_SYSCALL_RETURN(&p->thread.regs, 0);
|
||||||
if (sp != 0)
|
if (sp != 0)
|
||||||
REGS_SP(p->thread.regs.regs.gp) = sp;
|
REGS_SP(p->thread.regs.regs.gp) = sp;
|
||||||
|
|
||||||
|
@ -3,11 +3,12 @@
|
|||||||
* Licensed under the GPL
|
* Licensed under the GPL
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "linux/audit.h"
|
#include <linux/audit.h>
|
||||||
#include "linux/ptrace.h"
|
#include <linux/ptrace.h>
|
||||||
#include "linux/sched.h"
|
#include <linux/sched.h>
|
||||||
#include "asm/uaccess.h"
|
#include <linux/tracehook.h>
|
||||||
#include "skas_ptrace.h"
|
#include <asm/uaccess.h>
|
||||||
|
#include <skas_ptrace.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -162,48 +163,36 @@ static void send_sigtrap(struct task_struct *tsk, struct uml_pt_regs *regs,
|
|||||||
* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
|
* XXX Check PT_DTRACE vs TIF_SINGLESTEP for singlestepping check and
|
||||||
* PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
|
* PT_PTRACED vs TIF_SYSCALL_TRACE for syscall tracing check
|
||||||
*/
|
*/
|
||||||
void syscall_trace(struct uml_pt_regs *regs, int entryexit)
|
void syscall_trace_enter(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
int is_singlestep = (current->ptrace & PT_DTRACE) && entryexit;
|
|
||||||
int tracesysgood;
|
|
||||||
|
|
||||||
if (!entryexit)
|
|
||||||
audit_syscall_entry(HOST_AUDIT_ARCH,
|
audit_syscall_entry(HOST_AUDIT_ARCH,
|
||||||
UPT_SYSCALL_NR(regs),
|
UPT_SYSCALL_NR(®s->regs),
|
||||||
UPT_SYSCALL_ARG1(regs),
|
UPT_SYSCALL_ARG1(®s->regs),
|
||||||
UPT_SYSCALL_ARG2(regs),
|
UPT_SYSCALL_ARG2(®s->regs),
|
||||||
UPT_SYSCALL_ARG3(regs),
|
UPT_SYSCALL_ARG3(®s->regs),
|
||||||
UPT_SYSCALL_ARG4(regs));
|
UPT_SYSCALL_ARG4(®s->regs));
|
||||||
else
|
|
||||||
audit_syscall_exit(regs);
|
|
||||||
|
|
||||||
/* Fake a debug trap */
|
|
||||||
if (is_singlestep)
|
|
||||||
send_sigtrap(current, regs, 0);
|
|
||||||
|
|
||||||
if (!test_thread_flag(TIF_SYSCALL_TRACE))
|
if (!test_thread_flag(TIF_SYSCALL_TRACE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(current->ptrace & PT_PTRACED))
|
tracehook_report_syscall_entry(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
void syscall_trace_leave(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
int ptraced = current->ptrace;
|
||||||
|
|
||||||
|
audit_syscall_exit(regs);
|
||||||
|
|
||||||
|
/* Fake a debug trap */
|
||||||
|
if (ptraced & PT_DTRACE)
|
||||||
|
send_sigtrap(current, ®s->regs, 0);
|
||||||
|
|
||||||
|
if (!test_thread_flag(TIF_SYSCALL_TRACE))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
tracehook_report_syscall_exit(regs, 0);
|
||||||
* the 0x80 provides a way for the tracing parent to distinguish
|
/* force do_signal() --> is_syscall() */
|
||||||
* between a syscall stop and SIGTRAP delivery
|
if (ptraced & PT_PTRACED)
|
||||||
*/
|
|
||||||
tracesysgood = (current->ptrace & PT_TRACESYSGOOD);
|
|
||||||
ptrace_notify(SIGTRAP | (tracesysgood ? 0x80 : 0));
|
|
||||||
|
|
||||||
if (entryexit) /* force do_signal() --> is_syscall() */
|
|
||||||
set_thread_flag(TIF_SIGPENDING);
|
set_thread_flag(TIF_SIGPENDING);
|
||||||
|
|
||||||
/*
|
|
||||||
* this isn't the same as continuing with a signal, but it will do
|
|
||||||
* for normal use. strace only continues with a signal if the
|
|
||||||
* stopping signal is not SIGTRAP. -brl
|
|
||||||
*/
|
|
||||||
if (current->exit_code) {
|
|
||||||
send_sig(current->exit_code, current, 1);
|
|
||||||
current->exit_code = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ void handle_syscall(struct uml_pt_regs *r)
|
|||||||
long result;
|
long result;
|
||||||
int syscall;
|
int syscall;
|
||||||
|
|
||||||
syscall_trace(r, 0);
|
syscall_trace_enter(regs);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This should go in the declaration of syscall, but when I do that,
|
* This should go in the declaration of syscall, but when I do that,
|
||||||
@ -34,7 +34,7 @@ void handle_syscall(struct uml_pt_regs *r)
|
|||||||
result = -ENOSYS;
|
result = -ENOSYS;
|
||||||
else result = EXECUTE_SYSCALL(syscall, regs);
|
else result = EXECUTE_SYSCALL(syscall, regs);
|
||||||
|
|
||||||
UPT_SET_SYSCALL_RETURN(r, result);
|
PT_REGS_SET_SYSCALL_RETURN(regs, result);
|
||||||
|
|
||||||
syscall_trace(r, 1);
|
syscall_trace_leave(regs);
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include "kern_util.h"
|
#include "kern_util.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
|
|
||||||
void timer_handler(int sig, struct uml_pt_regs *regs)
|
void timer_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ void fatal_sigsegv(void)
|
|||||||
os_dump_core();
|
os_dump_core();
|
||||||
}
|
}
|
||||||
|
|
||||||
void segv_handler(int sig, struct uml_pt_regs *regs)
|
void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct faultinfo * fi = UPT_FAULTINFO(regs);
|
struct faultinfo * fi = UPT_FAULTINFO(regs);
|
||||||
|
|
||||||
@ -258,8 +258,11 @@ unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void relay_signal(int sig, struct uml_pt_regs *regs)
|
void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)
|
||||||
{
|
{
|
||||||
|
struct faultinfo *fi;
|
||||||
|
struct siginfo clean_si;
|
||||||
|
|
||||||
if (!UPT_IS_USER(regs)) {
|
if (!UPT_IS_USER(regs)) {
|
||||||
if (sig == SIGBUS)
|
if (sig == SIGBUS)
|
||||||
printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
|
printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
|
||||||
@ -269,18 +272,40 @@ void relay_signal(int sig, struct uml_pt_regs *regs)
|
|||||||
|
|
||||||
arch_examine_signal(sig, regs);
|
arch_examine_signal(sig, regs);
|
||||||
|
|
||||||
current->thread.arch.faultinfo = *UPT_FAULTINFO(regs);
|
memset(&clean_si, 0, sizeof(clean_si));
|
||||||
force_sig(sig, current);
|
clean_si.si_signo = si->si_signo;
|
||||||
|
clean_si.si_errno = si->si_errno;
|
||||||
|
clean_si.si_code = si->si_code;
|
||||||
|
switch (sig) {
|
||||||
|
case SIGILL:
|
||||||
|
case SIGFPE:
|
||||||
|
case SIGSEGV:
|
||||||
|
case SIGBUS:
|
||||||
|
case SIGTRAP:
|
||||||
|
fi = UPT_FAULTINFO(regs);
|
||||||
|
clean_si.si_addr = (void __user *) FAULT_ADDRESS(*fi);
|
||||||
|
current->thread.arch.faultinfo = *fi;
|
||||||
|
#ifdef __ARCH_SI_TRAPNO
|
||||||
|
clean_si.si_trapno = si->si_trapno;
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d)\n",
|
||||||
|
sig, si->si_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
force_sig_info(sig, &clean_si, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bus_handler(int sig, struct uml_pt_regs *regs)
|
void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs)
|
||||||
{
|
{
|
||||||
if (current->thread.fault_catcher != NULL)
|
if (current->thread.fault_catcher != NULL)
|
||||||
UML_LONGJMP(current->thread.fault_catcher, 1);
|
UML_LONGJMP(current->thread.fault_catcher, 1);
|
||||||
else relay_signal(sig, regs);
|
else
|
||||||
|
relay_signal(sig, si, regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void winch(int sig, struct uml_pt_regs *regs)
|
void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
|
||||||
{
|
{
|
||||||
do_IRQ(WINCH_IRQ, regs);
|
do_IRQ(WINCH_IRQ, regs);
|
||||||
}
|
}
|
||||||
|
@ -1 +1 @@
|
|||||||
void alarm_handler(int, mcontext_t *);
|
void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc);
|
||||||
|
@ -13,8 +13,9 @@
|
|||||||
#include "kern_util.h"
|
#include "kern_util.h"
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "sysdep/mcontext.h"
|
#include "sysdep/mcontext.h"
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
|
void (*sig_info[NSIG])(int, siginfo_t *, struct uml_pt_regs *) = {
|
||||||
[SIGTRAP] = relay_signal,
|
[SIGTRAP] = relay_signal,
|
||||||
[SIGFPE] = relay_signal,
|
[SIGFPE] = relay_signal,
|
||||||
[SIGILL] = relay_signal,
|
[SIGILL] = relay_signal,
|
||||||
@ -24,7 +25,7 @@ void (*sig_info[NSIG])(int, struct uml_pt_regs *) = {
|
|||||||
[SIGIO] = sigio_handler,
|
[SIGIO] = sigio_handler,
|
||||||
[SIGVTALRM] = timer_handler };
|
[SIGVTALRM] = timer_handler };
|
||||||
|
|
||||||
static void sig_handler_common(int sig, mcontext_t *mc)
|
static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc)
|
||||||
{
|
{
|
||||||
struct uml_pt_regs r;
|
struct uml_pt_regs r;
|
||||||
int save_errno = errno;
|
int save_errno = errno;
|
||||||
@ -40,7 +41,7 @@ static void sig_handler_common(int sig, mcontext_t *mc)
|
|||||||
if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
|
if ((sig != SIGIO) && (sig != SIGWINCH) && (sig != SIGVTALRM))
|
||||||
unblock_signals();
|
unblock_signals();
|
||||||
|
|
||||||
(*sig_info[sig])(sig, &r);
|
(*sig_info[sig])(sig, si, &r);
|
||||||
|
|
||||||
errno = save_errno;
|
errno = save_errno;
|
||||||
}
|
}
|
||||||
@ -60,7 +61,7 @@ static void sig_handler_common(int sig, mcontext_t *mc)
|
|||||||
static int signals_enabled;
|
static int signals_enabled;
|
||||||
static unsigned int signals_pending;
|
static unsigned int signals_pending;
|
||||||
|
|
||||||
void sig_handler(int sig, mcontext_t *mc)
|
void sig_handler(int sig, siginfo_t *si, mcontext_t *mc)
|
||||||
{
|
{
|
||||||
int enabled;
|
int enabled;
|
||||||
|
|
||||||
@ -72,7 +73,7 @@ void sig_handler(int sig, mcontext_t *mc)
|
|||||||
|
|
||||||
block_signals();
|
block_signals();
|
||||||
|
|
||||||
sig_handler_common(sig, mc);
|
sig_handler_common(sig, si, mc);
|
||||||
|
|
||||||
set_signals(enabled);
|
set_signals(enabled);
|
||||||
}
|
}
|
||||||
@ -85,10 +86,10 @@ static void real_alarm_handler(mcontext_t *mc)
|
|||||||
get_regs_from_mc(®s, mc);
|
get_regs_from_mc(®s, mc);
|
||||||
regs.is_user = 0;
|
regs.is_user = 0;
|
||||||
unblock_signals();
|
unblock_signals();
|
||||||
timer_handler(SIGVTALRM, ®s);
|
timer_handler(SIGVTALRM, NULL, ®s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void alarm_handler(int sig, mcontext_t *mc)
|
void alarm_handler(int sig, struct siginfo *unused_si, mcontext_t *mc)
|
||||||
{
|
{
|
||||||
int enabled;
|
int enabled;
|
||||||
|
|
||||||
@ -119,7 +120,7 @@ void set_sigstack(void *sig_stack, int size)
|
|||||||
panic("enabling signal stack failed, errno = %d\n", errno);
|
panic("enabling signal stack failed, errno = %d\n", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = {
|
static void (*handlers[_NSIG])(int sig, siginfo_t *si, mcontext_t *mc) = {
|
||||||
[SIGSEGV] = sig_handler,
|
[SIGSEGV] = sig_handler,
|
||||||
[SIGBUS] = sig_handler,
|
[SIGBUS] = sig_handler,
|
||||||
[SIGILL] = sig_handler,
|
[SIGILL] = sig_handler,
|
||||||
@ -132,7 +133,7 @@ static void (*handlers[_NSIG])(int sig, mcontext_t *mc) = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void hard_handler(int sig, siginfo_t *info, void *p)
|
static void hard_handler(int sig, siginfo_t *si, void *p)
|
||||||
{
|
{
|
||||||
struct ucontext *uc = p;
|
struct ucontext *uc = p;
|
||||||
mcontext_t *mc = &uc->uc_mcontext;
|
mcontext_t *mc = &uc->uc_mcontext;
|
||||||
@ -161,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *info, void *p)
|
|||||||
while ((sig = ffs(pending)) != 0){
|
while ((sig = ffs(pending)) != 0){
|
||||||
sig--;
|
sig--;
|
||||||
pending &= ~(1 << sig);
|
pending &= ~(1 << sig);
|
||||||
(*handlers[sig])(sig, mc);
|
(*handlers[sig])(sig, si, mc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -273,9 +274,12 @@ void unblock_signals(void)
|
|||||||
* Deal with SIGIO first because the alarm handler might
|
* Deal with SIGIO first because the alarm handler might
|
||||||
* schedule, leaving the pending SIGIO stranded until we come
|
* schedule, leaving the pending SIGIO stranded until we come
|
||||||
* back here.
|
* back here.
|
||||||
|
*
|
||||||
|
* SIGIO's handler doesn't use siginfo or mcontext,
|
||||||
|
* so they can be NULL.
|
||||||
*/
|
*/
|
||||||
if (save_pending & SIGIO_MASK)
|
if (save_pending & SIGIO_MASK)
|
||||||
sig_handler_common(SIGIO, NULL);
|
sig_handler_common(SIGIO, NULL, NULL);
|
||||||
|
|
||||||
if (save_pending & SIGVTALRM_MASK)
|
if (save_pending & SIGVTALRM_MASK)
|
||||||
real_alarm_handler(NULL);
|
real_alarm_handler(NULL);
|
||||||
|
@ -346,6 +346,10 @@ void userspace(struct uml_pt_regs *regs)
|
|||||||
int err, status, op, pid = userspace_pid[0];
|
int err, status, op, pid = userspace_pid[0];
|
||||||
/* To prevent races if using_sysemu changes under us.*/
|
/* To prevent races if using_sysemu changes under us.*/
|
||||||
int local_using_sysemu;
|
int local_using_sysemu;
|
||||||
|
siginfo_t si;
|
||||||
|
|
||||||
|
/* Handle any immediate reschedules or signals */
|
||||||
|
interrupt_end();
|
||||||
|
|
||||||
if (getitimer(ITIMER_VIRTUAL, &timer))
|
if (getitimer(ITIMER_VIRTUAL, &timer))
|
||||||
printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno);
|
printk(UM_KERN_ERR "Failed to get itimer, errno = %d\n", errno);
|
||||||
@ -404,13 +408,17 @@ void userspace(struct uml_pt_regs *regs)
|
|||||||
|
|
||||||
if (WIFSTOPPED(status)) {
|
if (WIFSTOPPED(status)) {
|
||||||
int sig = WSTOPSIG(status);
|
int sig = WSTOPSIG(status);
|
||||||
|
|
||||||
|
ptrace(PTRACE_GETSIGINFO, pid, 0, &si);
|
||||||
|
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
case SIGSEGV:
|
case SIGSEGV:
|
||||||
if (PTRACE_FULL_FAULTINFO ||
|
if (PTRACE_FULL_FAULTINFO ||
|
||||||
!ptrace_faultinfo) {
|
!ptrace_faultinfo) {
|
||||||
get_skas_faultinfo(pid,
|
get_skas_faultinfo(pid,
|
||||||
®s->faultinfo);
|
®s->faultinfo);
|
||||||
(*sig_info[SIGSEGV])(SIGSEGV, regs);
|
(*sig_info[SIGSEGV])(SIGSEGV, &si,
|
||||||
|
regs);
|
||||||
}
|
}
|
||||||
else handle_segv(pid, regs);
|
else handle_segv(pid, regs);
|
||||||
break;
|
break;
|
||||||
@ -418,14 +426,14 @@ void userspace(struct uml_pt_regs *regs)
|
|||||||
handle_trap(pid, regs, local_using_sysemu);
|
handle_trap(pid, regs, local_using_sysemu);
|
||||||
break;
|
break;
|
||||||
case SIGTRAP:
|
case SIGTRAP:
|
||||||
relay_signal(SIGTRAP, regs);
|
relay_signal(SIGTRAP, &si, regs);
|
||||||
break;
|
break;
|
||||||
case SIGVTALRM:
|
case SIGVTALRM:
|
||||||
now = os_nsecs();
|
now = os_nsecs();
|
||||||
if (now < nsecs)
|
if (now < nsecs)
|
||||||
break;
|
break;
|
||||||
block_signals();
|
block_signals();
|
||||||
(*sig_info[sig])(sig, regs);
|
(*sig_info[sig])(sig, &si, regs);
|
||||||
unblock_signals();
|
unblock_signals();
|
||||||
nsecs = timer.it_value.tv_sec *
|
nsecs = timer.it_value.tv_sec *
|
||||||
UM_NSEC_PER_SEC +
|
UM_NSEC_PER_SEC +
|
||||||
@ -439,7 +447,7 @@ void userspace(struct uml_pt_regs *regs)
|
|||||||
case SIGFPE:
|
case SIGFPE:
|
||||||
case SIGWINCH:
|
case SIGWINCH:
|
||||||
block_signals();
|
block_signals();
|
||||||
(*sig_info[sig])(sig, regs);
|
(*sig_info[sig])(sig, &si, regs);
|
||||||
unblock_signals();
|
unblock_signals();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -87,7 +87,7 @@ static int after_sleep_interval(struct timespec *ts)
|
|||||||
|
|
||||||
static void deliver_alarm(void)
|
static void deliver_alarm(void)
|
||||||
{
|
{
|
||||||
alarm_handler(SIGVTALRM, NULL);
|
alarm_handler(SIGVTALRM, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned long long sleep_time(unsigned long long nsecs)
|
static unsigned long long sleep_time(unsigned long long nsecs)
|
||||||
|
@ -30,10 +30,10 @@
|
|||||||
#define profile_pc(regs) PT_REGS_IP(regs)
|
#define profile_pc(regs) PT_REGS_IP(regs)
|
||||||
|
|
||||||
#define UPT_RESTART_SYSCALL(r) (UPT_IP(r) -= 2)
|
#define UPT_RESTART_SYSCALL(r) (UPT_IP(r) -= 2)
|
||||||
#define UPT_SET_SYSCALL_RETURN(r, res) (UPT_AX(r) = (res))
|
#define PT_REGS_SET_SYSCALL_RETURN(r, res) (PT_REGS_AX(r) = (res))
|
||||||
|
|
||||||
static inline long regs_return_value(struct uml_pt_regs *regs)
|
static inline long regs_return_value(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
return UPT_AX(regs);
|
return PT_REGS_AX(regs);
|
||||||
}
|
}
|
||||||
#endif /* __UM_X86_PTRACE_H */
|
#endif /* __UM_X86_PTRACE_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user