Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
This commit is contained in:
13
arch/um/os-Linux/Makefile
Normal file
13
arch/um/os-Linux/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
|
||||
# Licensed under the GPL
|
||||
#
|
||||
|
||||
obj-y = elf_aux.o file.o process.o signal.o time.o tty.o user_syms.o drivers/ \
|
||||
sys-$(SUBARCH)/
|
||||
|
||||
USER_OBJS := elf_aux.o file.o process.o signal.o time.o tty.o
|
||||
|
||||
CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
13
arch/um/os-Linux/drivers/Makefile
Normal file
13
arch/um/os-Linux/drivers/Makefile
Normal file
@@ -0,0 +1,13 @@
|
||||
#
|
||||
# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com)
|
||||
# Licensed under the GPL
|
||||
#
|
||||
|
||||
ethertap-objs := ethertap_kern.o ethertap_user.o
|
||||
tuntap-objs := tuntap_kern.o tuntap_user.o
|
||||
|
||||
obj-y =
|
||||
obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o
|
||||
obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
27
arch/um/os-Linux/drivers/etap.h
Normal file
27
arch/um/os-Linux/drivers/etap.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "net_user.h"
|
||||
|
||||
struct ethertap_data {
|
||||
char *dev_name;
|
||||
char *gate_addr;
|
||||
int data_fd;
|
||||
int control_fd;
|
||||
void *dev;
|
||||
};
|
||||
|
||||
extern struct net_user_info ethertap_user_info;
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
119
arch/um/os-Linux/drivers/ethertap_kern.c
Normal file
119
arch/um/os-Linux/drivers/ethertap_kern.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
|
||||
* James Leu (jleu@mindspring.net).
|
||||
* Copyright (C) 2001 by various other people who didn't put their name here.
|
||||
* Licensed under the GPL.
|
||||
*/
|
||||
|
||||
#include "linux/init.h"
|
||||
#include "linux/netdevice.h"
|
||||
#include "linux/etherdevice.h"
|
||||
#include "net_kern.h"
|
||||
#include "net_user.h"
|
||||
#include "etap.h"
|
||||
|
||||
struct ethertap_init {
|
||||
char *dev_name;
|
||||
char *gate_addr;
|
||||
};
|
||||
|
||||
static void etap_init(struct net_device *dev, void *data)
|
||||
{
|
||||
struct uml_net_private *pri;
|
||||
struct ethertap_data *epri;
|
||||
struct ethertap_init *init = data;
|
||||
|
||||
pri = dev->priv;
|
||||
epri = (struct ethertap_data *) pri->user;
|
||||
epri->dev_name = init->dev_name;
|
||||
epri->gate_addr = init->gate_addr;
|
||||
epri->data_fd = -1;
|
||||
epri->control_fd = -1;
|
||||
epri->dev = dev;
|
||||
|
||||
printk("ethertap backend - %s", epri->dev_name);
|
||||
if (epri->gate_addr != NULL)
|
||||
printk(", IP = %s", epri->gate_addr);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp)
|
||||
{
|
||||
int len;
|
||||
|
||||
*skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP);
|
||||
if(*skb == NULL) return(-ENOMEM);
|
||||
len = net_recvfrom(fd, (*skb)->mac.raw,
|
||||
(*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP);
|
||||
if(len <= 0) return(len);
|
||||
skb_pull(*skb, 2);
|
||||
len -= 2;
|
||||
return(len);
|
||||
}
|
||||
|
||||
static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
|
||||
{
|
||||
if(skb_headroom(*skb) < 2){
|
||||
struct sk_buff *skb2;
|
||||
|
||||
skb2 = skb_realloc_headroom(*skb, 2);
|
||||
dev_kfree_skb(*skb);
|
||||
if (skb2 == NULL) return(-ENOMEM);
|
||||
*skb = skb2;
|
||||
}
|
||||
skb_push(*skb, 2);
|
||||
return(net_send(fd, (*skb)->data, (*skb)->len));
|
||||
}
|
||||
|
||||
struct net_kern_info ethertap_kern_info = {
|
||||
.init = etap_init,
|
||||
.protocol = eth_protocol,
|
||||
.read = etap_read,
|
||||
.write = etap_write,
|
||||
};
|
||||
|
||||
int ethertap_setup(char *str, char **mac_out, void *data)
|
||||
{
|
||||
struct ethertap_init *init = data;
|
||||
|
||||
*init = ((struct ethertap_init)
|
||||
{ .dev_name = NULL,
|
||||
.gate_addr = NULL });
|
||||
if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out,
|
||||
&init->gate_addr))
|
||||
return(0);
|
||||
if(init->dev_name == NULL){
|
||||
printk("ethertap_setup : Missing tap device name\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static struct transport ethertap_transport = {
|
||||
.list = LIST_HEAD_INIT(ethertap_transport.list),
|
||||
.name = "ethertap",
|
||||
.setup = ethertap_setup,
|
||||
.user = ðertap_user_info,
|
||||
.kern = ðertap_kern_info,
|
||||
.private_size = sizeof(struct ethertap_data),
|
||||
};
|
||||
|
||||
static int register_ethertap(void)
|
||||
{
|
||||
register_transport(ðertap_transport);
|
||||
return(1);
|
||||
}
|
||||
|
||||
__initcall(register_ethertap);
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
240
arch/um/os-Linux/drivers/ethertap_user.c
Normal file
240
arch/um/os-Linux/drivers/ethertap_user.c
Normal file
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and
|
||||
* James Leu (jleu@mindspring.net).
|
||||
* Copyright (C) 2001 by various other people who didn't put their name here.
|
||||
* Licensed under the GPL.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/un.h>
|
||||
#include <net/if.h>
|
||||
#include "user.h"
|
||||
#include "kern_util.h"
|
||||
#include "user_util.h"
|
||||
#include "net_user.h"
|
||||
#include "etap.h"
|
||||
#include "helper.h"
|
||||
#include "os.h"
|
||||
|
||||
#define MAX_PACKET ETH_MAX_PACKET
|
||||
|
||||
void etap_user_init(void *data, void *dev)
|
||||
{
|
||||
struct ethertap_data *pri = data;
|
||||
|
||||
pri->dev = dev;
|
||||
}
|
||||
|
||||
struct addr_change {
|
||||
enum { ADD_ADDR, DEL_ADDR } what;
|
||||
unsigned char addr[4];
|
||||
unsigned char netmask[4];
|
||||
};
|
||||
|
||||
static void etap_change(int op, unsigned char *addr, unsigned char *netmask,
|
||||
int fd)
|
||||
{
|
||||
struct addr_change change;
|
||||
void *output;
|
||||
int n;
|
||||
|
||||
change.what = op;
|
||||
memcpy(change.addr, addr, sizeof(change.addr));
|
||||
memcpy(change.netmask, netmask, sizeof(change.netmask));
|
||||
n = os_write_file(fd, &change, sizeof(change));
|
||||
if(n != sizeof(change))
|
||||
printk("etap_change - request failed, err = %d\n", -n);
|
||||
output = um_kmalloc(page_size());
|
||||
if(output == NULL)
|
||||
printk("etap_change : Failed to allocate output buffer\n");
|
||||
read_output(fd, output, page_size());
|
||||
if(output != NULL){
|
||||
printk("%s", output);
|
||||
kfree(output);
|
||||
}
|
||||
}
|
||||
|
||||
static void etap_open_addr(unsigned char *addr, unsigned char *netmask,
|
||||
void *arg)
|
||||
{
|
||||
etap_change(ADD_ADDR, addr, netmask, *((int *) arg));
|
||||
}
|
||||
|
||||
static void etap_close_addr(unsigned char *addr, unsigned char *netmask,
|
||||
void *arg)
|
||||
{
|
||||
etap_change(DEL_ADDR, addr, netmask, *((int *) arg));
|
||||
}
|
||||
|
||||
struct etap_pre_exec_data {
|
||||
int control_remote;
|
||||
int control_me;
|
||||
int data_me;
|
||||
};
|
||||
|
||||
static void etap_pre_exec(void *arg)
|
||||
{
|
||||
struct etap_pre_exec_data *data = arg;
|
||||
|
||||
dup2(data->control_remote, 1);
|
||||
os_close_file(data->data_me);
|
||||
os_close_file(data->control_me);
|
||||
}
|
||||
|
||||
static int etap_tramp(char *dev, char *gate, int control_me,
|
||||
int control_remote, int data_me, int data_remote)
|
||||
{
|
||||
struct etap_pre_exec_data pe_data;
|
||||
int pid, status, err, n;
|
||||
char version_buf[sizeof("nnnnn\0")];
|
||||
char data_fd_buf[sizeof("nnnnnn\0")];
|
||||
char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")];
|
||||
char *setup_args[] = { "uml_net", version_buf, "ethertap", dev,
|
||||
data_fd_buf, gate_buf, NULL };
|
||||
char *nosetup_args[] = { "uml_net", version_buf, "ethertap",
|
||||
dev, data_fd_buf, NULL };
|
||||
char **args, c;
|
||||
|
||||
sprintf(data_fd_buf, "%d", data_remote);
|
||||
sprintf(version_buf, "%d", UML_NET_VERSION);
|
||||
if(gate != NULL){
|
||||
strcpy(gate_buf, gate);
|
||||
args = setup_args;
|
||||
}
|
||||
else args = nosetup_args;
|
||||
|
||||
err = 0;
|
||||
pe_data.control_remote = control_remote;
|
||||
pe_data.control_me = control_me;
|
||||
pe_data.data_me = data_me;
|
||||
pid = run_helper(etap_pre_exec, &pe_data, args, NULL);
|
||||
|
||||
if(pid < 0) err = pid;
|
||||
os_close_file(data_remote);
|
||||
os_close_file(control_remote);
|
||||
n = os_read_file(control_me, &c, sizeof(c));
|
||||
if(n != sizeof(c)){
|
||||
printk("etap_tramp : read of status failed, err = %d\n", -n);
|
||||
return(-EINVAL);
|
||||
}
|
||||
if(c != 1){
|
||||
printk("etap_tramp : uml_net failed\n");
|
||||
err = -EINVAL;
|
||||
CATCH_EINTR(n = waitpid(pid, &status, 0));
|
||||
if(n < 0)
|
||||
err = -errno;
|
||||
else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1))
|
||||
printk("uml_net didn't exit with status 1\n");
|
||||
}
|
||||
return(err);
|
||||
}
|
||||
|
||||
static int etap_open(void *data)
|
||||
{
|
||||
struct ethertap_data *pri = data;
|
||||
char *output;
|
||||
int data_fds[2], control_fds[2], err, output_len;
|
||||
|
||||
err = tap_open_common(pri->dev, pri->gate_addr);
|
||||
if(err) return(err);
|
||||
|
||||
err = os_pipe(data_fds, 0, 0);
|
||||
if(err < 0){
|
||||
printk("data os_pipe failed - err = %d\n", -err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
err = os_pipe(control_fds, 1, 0);
|
||||
if(err < 0){
|
||||
printk("control os_pipe failed - err = %d\n", -err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0],
|
||||
control_fds[1], data_fds[0], data_fds[1]);
|
||||
output_len = page_size();
|
||||
output = um_kmalloc(output_len);
|
||||
read_output(control_fds[0], output, output_len);
|
||||
|
||||
if(output == NULL)
|
||||
printk("etap_open : failed to allocate output buffer\n");
|
||||
else {
|
||||
printk("%s", output);
|
||||
kfree(output);
|
||||
}
|
||||
|
||||
if(err < 0){
|
||||
printk("etap_tramp failed - err = %d\n", -err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
pri->data_fd = data_fds[0];
|
||||
pri->control_fd = control_fds[0];
|
||||
iter_addresses(pri->dev, etap_open_addr, &pri->control_fd);
|
||||
return(data_fds[0]);
|
||||
}
|
||||
|
||||
static void etap_close(int fd, void *data)
|
||||
{
|
||||
struct ethertap_data *pri = data;
|
||||
|
||||
iter_addresses(pri->dev, etap_close_addr, &pri->control_fd);
|
||||
os_close_file(fd);
|
||||
os_shutdown_socket(pri->data_fd, 1, 1);
|
||||
os_close_file(pri->data_fd);
|
||||
pri->data_fd = -1;
|
||||
os_close_file(pri->control_fd);
|
||||
pri->control_fd = -1;
|
||||
}
|
||||
|
||||
static int etap_set_mtu(int mtu, void *data)
|
||||
{
|
||||
return(mtu);
|
||||
}
|
||||
|
||||
static void etap_add_addr(unsigned char *addr, unsigned char *netmask,
|
||||
void *data)
|
||||
{
|
||||
struct ethertap_data *pri = data;
|
||||
|
||||
tap_check_ips(pri->gate_addr, addr);
|
||||
if(pri->control_fd == -1) return;
|
||||
etap_open_addr(addr, netmask, &pri->control_fd);
|
||||
}
|
||||
|
||||
static void etap_del_addr(unsigned char *addr, unsigned char *netmask,
|
||||
void *data)
|
||||
{
|
||||
struct ethertap_data *pri = data;
|
||||
|
||||
if(pri->control_fd == -1) return;
|
||||
etap_close_addr(addr, netmask, &pri->control_fd);
|
||||
}
|
||||
|
||||
struct net_user_info ethertap_user_info = {
|
||||
.init = etap_user_init,
|
||||
.open = etap_open,
|
||||
.close = etap_close,
|
||||
.remove = NULL,
|
||||
.set_mtu = etap_set_mtu,
|
||||
.add_address = etap_add_addr,
|
||||
.delete_address = etap_del_addr,
|
||||
.max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP
|
||||
};
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
32
arch/um/os-Linux/drivers/tuntap.h
Normal file
32
arch/um/os-Linux/drivers/tuntap.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#ifndef __UM_TUNTAP_H
|
||||
#define __UM_TUNTAP_H
|
||||
|
||||
#include "net_user.h"
|
||||
|
||||
struct tuntap_data {
|
||||
char *dev_name;
|
||||
int fixed_config;
|
||||
char *gate_addr;
|
||||
int fd;
|
||||
void *dev;
|
||||
};
|
||||
|
||||
extern struct net_user_info tuntap_user_info;
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
104
arch/um/os-Linux/drivers/tuntap_kern.c
Normal file
104
arch/um/os-Linux/drivers/tuntap_kern.c
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2001 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include "linux/stddef.h"
|
||||
#include "linux/netdevice.h"
|
||||
#include "linux/etherdevice.h"
|
||||
#include "linux/skbuff.h"
|
||||
#include "linux/init.h"
|
||||
#include "asm/errno.h"
|
||||
#include "net_kern.h"
|
||||
#include "net_user.h"
|
||||
#include "tuntap.h"
|
||||
|
||||
struct tuntap_init {
|
||||
char *dev_name;
|
||||
char *gate_addr;
|
||||
};
|
||||
|
||||
static void tuntap_init(struct net_device *dev, void *data)
|
||||
{
|
||||
struct uml_net_private *pri;
|
||||
struct tuntap_data *tpri;
|
||||
struct tuntap_init *init = data;
|
||||
|
||||
pri = dev->priv;
|
||||
tpri = (struct tuntap_data *) pri->user;
|
||||
tpri->dev_name = init->dev_name;
|
||||
tpri->fixed_config = (init->dev_name != NULL);
|
||||
tpri->gate_addr = init->gate_addr;
|
||||
tpri->fd = -1;
|
||||
tpri->dev = dev;
|
||||
|
||||
printk("TUN/TAP backend - ");
|
||||
if (tpri->gate_addr != NULL)
|
||||
printk("IP = %s", tpri->gate_addr);
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static int tuntap_read(int fd, struct sk_buff **skb,
|
||||
struct uml_net_private *lp)
|
||||
{
|
||||
*skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
|
||||
if(*skb == NULL) return(-ENOMEM);
|
||||
return(net_read(fd, (*skb)->mac.raw,
|
||||
(*skb)->dev->mtu + ETH_HEADER_OTHER));
|
||||
}
|
||||
|
||||
static int tuntap_write(int fd, struct sk_buff **skb,
|
||||
struct uml_net_private *lp)
|
||||
{
|
||||
return(net_write(fd, (*skb)->data, (*skb)->len));
|
||||
}
|
||||
|
||||
struct net_kern_info tuntap_kern_info = {
|
||||
.init = tuntap_init,
|
||||
.protocol = eth_protocol,
|
||||
.read = tuntap_read,
|
||||
.write = tuntap_write,
|
||||
};
|
||||
|
||||
int tuntap_setup(char *str, char **mac_out, void *data)
|
||||
{
|
||||
struct tuntap_init *init = data;
|
||||
|
||||
*init = ((struct tuntap_init)
|
||||
{ .dev_name = NULL,
|
||||
.gate_addr = NULL });
|
||||
if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out,
|
||||
&init->gate_addr))
|
||||
return(0);
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
static struct transport tuntap_transport = {
|
||||
.list = LIST_HEAD_INIT(tuntap_transport.list),
|
||||
.name = "tuntap",
|
||||
.setup = tuntap_setup,
|
||||
.user = &tuntap_user_info,
|
||||
.kern = &tuntap_kern_info,
|
||||
.private_size = sizeof(struct tuntap_data),
|
||||
.setup_size = sizeof(struct tuntap_init),
|
||||
};
|
||||
|
||||
static int register_tuntap(void)
|
||||
{
|
||||
register_transport(&tuntap_transport);
|
||||
return(1);
|
||||
}
|
||||
|
||||
__initcall(register_tuntap);
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
225
arch/um/os-Linux/drivers/tuntap_user.c
Normal file
225
arch/um/os-Linux/drivers/tuntap_user.c
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include "net_user.h"
|
||||
#include "tuntap.h"
|
||||
#include "kern_util.h"
|
||||
#include "user_util.h"
|
||||
#include "user.h"
|
||||
#include "helper.h"
|
||||
#include "os.h"
|
||||
|
||||
#define MAX_PACKET ETH_MAX_PACKET
|
||||
|
||||
void tuntap_user_init(void *data, void *dev)
|
||||
{
|
||||
struct tuntap_data *pri = data;
|
||||
|
||||
pri->dev = dev;
|
||||
}
|
||||
|
||||
static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask,
|
||||
void *data)
|
||||
{
|
||||
struct tuntap_data *pri = data;
|
||||
|
||||
tap_check_ips(pri->gate_addr, addr);
|
||||
if((pri->fd == -1) || pri->fixed_config) return;
|
||||
open_addr(addr, netmask, pri->dev_name);
|
||||
}
|
||||
|
||||
static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask,
|
||||
void *data)
|
||||
{
|
||||
struct tuntap_data *pri = data;
|
||||
|
||||
if((pri->fd == -1) || pri->fixed_config) return;
|
||||
close_addr(addr, netmask, pri->dev_name);
|
||||
}
|
||||
|
||||
struct tuntap_pre_exec_data {
|
||||
int stdout;
|
||||
int close_me;
|
||||
};
|
||||
|
||||
static void tuntap_pre_exec(void *arg)
|
||||
{
|
||||
struct tuntap_pre_exec_data *data = arg;
|
||||
|
||||
dup2(data->stdout, 1);
|
||||
os_close_file(data->close_me);
|
||||
}
|
||||
|
||||
static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote,
|
||||
char *buffer, int buffer_len, int *used_out)
|
||||
{
|
||||
struct tuntap_pre_exec_data data;
|
||||
char version_buf[sizeof("nnnnn\0")];
|
||||
char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate,
|
||||
NULL };
|
||||
char buf[CMSG_SPACE(sizeof(*fd_out))];
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec iov;
|
||||
int pid, n;
|
||||
|
||||
sprintf(version_buf, "%d", UML_NET_VERSION);
|
||||
|
||||
data.stdout = remote;
|
||||
data.close_me = me;
|
||||
|
||||
pid = run_helper(tuntap_pre_exec, &data, argv, NULL);
|
||||
|
||||
if(pid < 0) return(-pid);
|
||||
|
||||
os_close_file(remote);
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
if(buffer != NULL){
|
||||
iov = ((struct iovec) { buffer, buffer_len });
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
}
|
||||
else {
|
||||
msg.msg_iov = NULL;
|
||||
msg.msg_iovlen = 0;
|
||||
}
|
||||
msg.msg_control = buf;
|
||||
msg.msg_controllen = sizeof(buf);
|
||||
msg.msg_flags = 0;
|
||||
n = recvmsg(me, &msg, 0);
|
||||
*used_out = n;
|
||||
if(n < 0){
|
||||
printk("tuntap_open_tramp : recvmsg failed - errno = %d\n",
|
||||
errno);
|
||||
return(-errno);
|
||||
}
|
||||
CATCH_EINTR(waitpid(pid, NULL, 0));
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if(cmsg == NULL){
|
||||
printk("tuntap_open_tramp : didn't receive a message\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
if((cmsg->cmsg_level != SOL_SOCKET) ||
|
||||
(cmsg->cmsg_type != SCM_RIGHTS)){
|
||||
printk("tuntap_open_tramp : didn't receive a descriptor\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
*fd_out = ((int *) CMSG_DATA(cmsg))[0];
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int tuntap_open(void *data)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct tuntap_data *pri = data;
|
||||
char *output, *buffer;
|
||||
int err, fds[2], len, used;
|
||||
|
||||
err = tap_open_common(pri->dev, pri->gate_addr);
|
||||
if(err < 0)
|
||||
return(err);
|
||||
|
||||
if(pri->fixed_config){
|
||||
pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0);
|
||||
if(pri->fd < 0){
|
||||
printk("Failed to open /dev/net/tun, err = %d\n",
|
||||
-pri->fd);
|
||||
return(pri->fd);
|
||||
}
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
strlcpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name));
|
||||
if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){
|
||||
printk("TUNSETIFF failed, errno = %d\n", errno);
|
||||
os_close_file(pri->fd);
|
||||
return(-errno);
|
||||
}
|
||||
}
|
||||
else {
|
||||
err = os_pipe(fds, 0, 0);
|
||||
if(err < 0){
|
||||
printk("tuntap_open : os_pipe failed - err = %d\n",
|
||||
-err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
buffer = get_output_buffer(&len);
|
||||
if(buffer != NULL) len--;
|
||||
used = 0;
|
||||
|
||||
err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0],
|
||||
fds[1], buffer, len, &used);
|
||||
|
||||
output = buffer;
|
||||
if(err < 0) {
|
||||
printk("%s", output);
|
||||
free_output_buffer(buffer);
|
||||
printk("tuntap_open_tramp failed - err = %d\n", -err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
pri->dev_name = uml_strdup(buffer);
|
||||
output += IFNAMSIZ;
|
||||
printk("%s", output);
|
||||
free_output_buffer(buffer);
|
||||
|
||||
os_close_file(fds[0]);
|
||||
iter_addresses(pri->dev, open_addr, pri->dev_name);
|
||||
}
|
||||
|
||||
return(pri->fd);
|
||||
}
|
||||
|
||||
static void tuntap_close(int fd, void *data)
|
||||
{
|
||||
struct tuntap_data *pri = data;
|
||||
|
||||
if(!pri->fixed_config)
|
||||
iter_addresses(pri->dev, close_addr, pri->dev_name);
|
||||
os_close_file(fd);
|
||||
pri->fd = -1;
|
||||
}
|
||||
|
||||
static int tuntap_set_mtu(int mtu, void *data)
|
||||
{
|
||||
return(mtu);
|
||||
}
|
||||
|
||||
struct net_user_info tuntap_user_info = {
|
||||
.init = tuntap_user_init,
|
||||
.open = tuntap_open,
|
||||
.close = tuntap_close,
|
||||
.remove = NULL,
|
||||
.set_mtu = tuntap_set_mtu,
|
||||
.add_address = tuntap_add_addr,
|
||||
.delete_address = tuntap_del_addr,
|
||||
.max_packet = MAX_PACKET
|
||||
};
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
66
arch/um/os-Linux/elf_aux.c
Normal file
66
arch/um/os-Linux/elf_aux.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* arch/um/kernel/elf_aux.c
|
||||
*
|
||||
* Scan the Elf auxiliary vector provided by the host to extract
|
||||
* information about vsyscall-page, etc.
|
||||
*
|
||||
* Copyright (C) 2004 Fujitsu Siemens Computers GmbH
|
||||
* Author: Bodo Stroesser (bodo.stroesser@fujitsu-siemens.com)
|
||||
*/
|
||||
#include <elf.h>
|
||||
#include <stddef.h>
|
||||
#include "init.h"
|
||||
#include "elf_user.h"
|
||||
|
||||
#if ELF_CLASS == ELFCLASS32
|
||||
typedef Elf32_auxv_t elf_auxv_t;
|
||||
#else
|
||||
typedef Elf64_auxv_t elf_auxv_t;
|
||||
#endif
|
||||
|
||||
char * elf_aux_platform;
|
||||
long elf_aux_hwcap;
|
||||
|
||||
unsigned long vsyscall_ehdr;
|
||||
unsigned long vsyscall_end;
|
||||
|
||||
unsigned long __kernel_vsyscall;
|
||||
|
||||
__init void scan_elf_aux( char **envp)
|
||||
{
|
||||
long page_size = 0;
|
||||
elf_auxv_t * auxv;
|
||||
|
||||
while ( *envp++ != NULL) ;
|
||||
|
||||
for ( auxv = (elf_auxv_t *)envp; auxv->a_type != AT_NULL; auxv++) {
|
||||
switch ( auxv->a_type ) {
|
||||
case AT_SYSINFO:
|
||||
__kernel_vsyscall = auxv->a_un.a_val;
|
||||
break;
|
||||
case AT_SYSINFO_EHDR:
|
||||
vsyscall_ehdr = auxv->a_un.a_val;
|
||||
break;
|
||||
case AT_HWCAP:
|
||||
elf_aux_hwcap = auxv->a_un.a_val;
|
||||
break;
|
||||
case AT_PLATFORM:
|
||||
elf_aux_platform = auxv->a_un.a_ptr;
|
||||
break;
|
||||
case AT_PAGESZ:
|
||||
page_size = auxv->a_un.a_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! __kernel_vsyscall || ! vsyscall_ehdr ||
|
||||
! elf_aux_hwcap || ! elf_aux_platform ||
|
||||
! page_size || (vsyscall_ehdr % page_size) ) {
|
||||
__kernel_vsyscall = 0;
|
||||
vsyscall_ehdr = 0;
|
||||
elf_aux_hwcap = 0;
|
||||
elf_aux_platform = "i586";
|
||||
}
|
||||
else {
|
||||
vsyscall_end = vsyscall_ehdr + page_size;
|
||||
}
|
||||
}
|
680
arch/um/os-Linux/file.c
Normal file
680
arch/um/os-Linux/file.c
Normal file
@@ -0,0 +1,680 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/uio.h>
|
||||
#include "os.h"
|
||||
#include "user.h"
|
||||
#include "kern_util.h"
|
||||
|
||||
static void copy_stat(struct uml_stat *dst, struct stat64 *src)
|
||||
{
|
||||
*dst = ((struct uml_stat) {
|
||||
.ust_dev = src->st_dev, /* device */
|
||||
.ust_ino = src->st_ino, /* inode */
|
||||
.ust_mode = src->st_mode, /* protection */
|
||||
.ust_nlink = src->st_nlink, /* number of hard links */
|
||||
.ust_uid = src->st_uid, /* user ID of owner */
|
||||
.ust_gid = src->st_gid, /* group ID of owner */
|
||||
.ust_size = src->st_size, /* total size, in bytes */
|
||||
.ust_blksize = src->st_blksize, /* blocksize for filesys I/O */
|
||||
.ust_blocks = src->st_blocks, /* number of blocks allocated */
|
||||
.ust_atime = src->st_atime, /* time of last access */
|
||||
.ust_mtime = src->st_mtime, /* time of last modification */
|
||||
.ust_ctime = src->st_ctime, /* time of last change */
|
||||
});
|
||||
}
|
||||
|
||||
int os_stat_fd(const int fd, struct uml_stat *ubuf)
|
||||
{
|
||||
struct stat64 sbuf;
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = fstat64(fd, &sbuf);
|
||||
} while((err < 0) && (errno == EINTR)) ;
|
||||
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
|
||||
if(ubuf != NULL)
|
||||
copy_stat(ubuf, &sbuf);
|
||||
return(err);
|
||||
}
|
||||
|
||||
int os_stat_file(const char *file_name, struct uml_stat *ubuf)
|
||||
{
|
||||
struct stat64 sbuf;
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = stat64(file_name, &sbuf);
|
||||
} while((err < 0) && (errno == EINTR)) ;
|
||||
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
|
||||
if(ubuf != NULL)
|
||||
copy_stat(ubuf, &sbuf);
|
||||
return(err);
|
||||
}
|
||||
|
||||
int os_access(const char* file, int mode)
|
||||
{
|
||||
int amode, err;
|
||||
|
||||
amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) |
|
||||
(mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ;
|
||||
|
||||
err = access(file, amode);
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void os_print_error(int error, const char* str)
|
||||
{
|
||||
errno = error < 0 ? -error : error;
|
||||
|
||||
perror(str);
|
||||
}
|
||||
|
||||
/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */
|
||||
int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ioctl(fd, cmd, arg);
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
int os_window_size(int fd, int *rows, int *cols)
|
||||
{
|
||||
struct winsize size;
|
||||
|
||||
if(ioctl(fd, TIOCGWINSZ, &size) < 0)
|
||||
return(-errno);
|
||||
|
||||
*rows = size.ws_row;
|
||||
*cols = size.ws_col;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_new_tty_pgrp(int fd, int pid)
|
||||
{
|
||||
if(ioctl(fd, TIOCSCTTY, 0) < 0){
|
||||
printk("TIOCSCTTY failed, errno = %d\n", errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
if(tcsetpgrp(fd, pid) < 0){
|
||||
printk("tcsetpgrp failed, errno = %d\n", errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* FIXME: ensure namebuf in os_get_if_name is big enough */
|
||||
int os_get_ifname(int fd, char* namebuf)
|
||||
{
|
||||
if(ioctl(fd, SIOCGIFNAME, namebuf) < 0)
|
||||
return(-errno);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_set_slip(int fd)
|
||||
{
|
||||
int disc, sencap;
|
||||
|
||||
disc = N_SLIP;
|
||||
if(ioctl(fd, TIOCSETD, &disc) < 0){
|
||||
printk("Failed to set slip line discipline - "
|
||||
"errno = %d\n", errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
sencap = 0;
|
||||
if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){
|
||||
printk("Failed to set slip encapsulation - "
|
||||
"errno = %d\n", errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_set_owner(int fd, int pid)
|
||||
{
|
||||
if(fcntl(fd, F_SETOWN, pid) < 0){
|
||||
int save_errno = errno;
|
||||
|
||||
if(fcntl(fd, F_GETOWN, 0) != pid)
|
||||
return(-save_errno);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */
|
||||
int os_sigio_async(int master, int slave)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(master, F_GETFL);
|
||||
if(flags < 0) {
|
||||
printk("fcntl F_GETFL failed, errno = %d\n", errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) ||
|
||||
(fcntl(master, F_SETOWN, os_getpid()) < 0)){
|
||||
printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n",
|
||||
errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){
|
||||
printk("fcntl F_SETFL failed, errno = %d\n", errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_mode_fd(int fd, int mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
do {
|
||||
err = fchmod(fd, mode);
|
||||
} while((err < 0) && (errno==EINTR)) ;
|
||||
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_file_type(char *file)
|
||||
{
|
||||
struct uml_stat buf;
|
||||
int err;
|
||||
|
||||
err = os_stat_file(file, &buf);
|
||||
if(err < 0)
|
||||
return(err);
|
||||
|
||||
if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR);
|
||||
else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK);
|
||||
else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV);
|
||||
else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV);
|
||||
else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO);
|
||||
else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK);
|
||||
else return(OS_TYPE_FILE);
|
||||
}
|
||||
|
||||
int os_file_mode(char *file, struct openflags *mode_out)
|
||||
{
|
||||
int err;
|
||||
|
||||
*mode_out = OPENFLAGS();
|
||||
|
||||
err = os_access(file, OS_ACC_W_OK);
|
||||
if((err < 0) && (err != -EACCES))
|
||||
return(err);
|
||||
|
||||
*mode_out = of_write(*mode_out);
|
||||
|
||||
err = os_access(file, OS_ACC_R_OK);
|
||||
if((err < 0) && (err != -EACCES))
|
||||
return(err);
|
||||
|
||||
*mode_out = of_read(*mode_out);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_open_file(char *file, struct openflags flags, int mode)
|
||||
{
|
||||
int fd, f = 0;
|
||||
|
||||
if(flags.r && flags.w) f = O_RDWR;
|
||||
else if(flags.r) f = O_RDONLY;
|
||||
else if(flags.w) f = O_WRONLY;
|
||||
else f = 0;
|
||||
|
||||
if(flags.s) f |= O_SYNC;
|
||||
if(flags.c) f |= O_CREAT;
|
||||
if(flags.t) f |= O_TRUNC;
|
||||
if(flags.e) f |= O_EXCL;
|
||||
|
||||
fd = open64(file, f, mode);
|
||||
if(fd < 0)
|
||||
return(-errno);
|
||||
|
||||
if(flags.cl && fcntl(fd, F_SETFD, 1)){
|
||||
os_close_file(fd);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
return(fd);
|
||||
}
|
||||
|
||||
int os_connect_socket(char *name)
|
||||
{
|
||||
struct sockaddr_un sock;
|
||||
int fd, err;
|
||||
|
||||
sock.sun_family = AF_UNIX;
|
||||
snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name);
|
||||
|
||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if(fd < 0)
|
||||
return(fd);
|
||||
|
||||
err = connect(fd, (struct sockaddr *) &sock, sizeof(sock));
|
||||
if(err)
|
||||
return(-errno);
|
||||
|
||||
return(fd);
|
||||
}
|
||||
|
||||
void os_close_file(int fd)
|
||||
{
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int os_seek_file(int fd, __u64 offset)
|
||||
{
|
||||
__u64 actual;
|
||||
|
||||
actual = lseek64(fd, offset, SEEK_SET);
|
||||
if(actual != offset)
|
||||
return(-errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int fault_buffer(void *start, int len,
|
||||
int (*copy_proc)(void *addr, void *buf, int len))
|
||||
{
|
||||
int page = getpagesize(), i;
|
||||
char c;
|
||||
|
||||
for(i = 0; i < len; i += page){
|
||||
if((*copy_proc)(start + i, &c, sizeof(c)))
|
||||
return(-EFAULT);
|
||||
}
|
||||
if((len % page) != 0){
|
||||
if((*copy_proc)(start + len - 1, &c, sizeof(c)))
|
||||
return(-EFAULT);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int file_io(int fd, void *buf, int len,
|
||||
int (*io_proc)(int fd, void *buf, int len),
|
||||
int (*copy_user_proc)(void *addr, void *buf, int len))
|
||||
{
|
||||
int n, err;
|
||||
|
||||
do {
|
||||
n = (*io_proc)(fd, buf, len);
|
||||
if((n < 0) && (errno == EFAULT)){
|
||||
err = fault_buffer(buf, len, copy_user_proc);
|
||||
if(err)
|
||||
return(err);
|
||||
n = (*io_proc)(fd, buf, len);
|
||||
}
|
||||
} while((n < 0) && (errno == EINTR));
|
||||
|
||||
if(n < 0)
|
||||
return(-errno);
|
||||
return(n);
|
||||
}
|
||||
|
||||
int os_read_file(int fd, void *buf, int len)
|
||||
{
|
||||
return(file_io(fd, buf, len, (int (*)(int, void *, int)) read,
|
||||
copy_from_user_proc));
|
||||
}
|
||||
|
||||
int os_write_file(int fd, const void *buf, int len)
|
||||
{
|
||||
return(file_io(fd, (void *) buf, len,
|
||||
(int (*)(int, void *, int)) write, copy_to_user_proc));
|
||||
}
|
||||
|
||||
int os_file_size(char *file, long long *size_out)
|
||||
{
|
||||
struct uml_stat buf;
|
||||
int err;
|
||||
|
||||
err = os_stat_file(file, &buf);
|
||||
if(err < 0){
|
||||
printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
if(S_ISBLK(buf.ust_mode)){
|
||||
int fd, blocks;
|
||||
|
||||
fd = os_open_file(file, of_read(OPENFLAGS()), 0);
|
||||
if(fd < 0){
|
||||
printk("Couldn't open \"%s\", errno = %d\n", file, -fd);
|
||||
return(fd);
|
||||
}
|
||||
if(ioctl(fd, BLKGETSIZE, &blocks) < 0){
|
||||
printk("Couldn't get the block size of \"%s\", "
|
||||
"errno = %d\n", file, errno);
|
||||
err = -errno;
|
||||
os_close_file(fd);
|
||||
return(err);
|
||||
}
|
||||
*size_out = ((long long) blocks) * 512;
|
||||
os_close_file(fd);
|
||||
return(0);
|
||||
}
|
||||
*size_out = buf.ust_size;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_file_modtime(char *file, unsigned long *modtime)
|
||||
{
|
||||
struct uml_stat buf;
|
||||
int err;
|
||||
|
||||
err = os_stat_file(file, &buf);
|
||||
if(err < 0){
|
||||
printk("Couldn't stat \"%s\" : err = %d\n", file, -err);
|
||||
return(err);
|
||||
}
|
||||
|
||||
*modtime = buf.ust_mtime;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_get_exec_close(int fd, int* close_on_exec)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = fcntl(fd, F_GETFD);
|
||||
} while((ret < 0) && (errno == EINTR)) ;
|
||||
|
||||
if(ret < 0)
|
||||
return(-errno);
|
||||
|
||||
*close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
int os_set_exec_close(int fd, int close_on_exec)
|
||||
{
|
||||
int flag, err;
|
||||
|
||||
if(close_on_exec) flag = FD_CLOEXEC;
|
||||
else flag = 0;
|
||||
|
||||
do {
|
||||
err = fcntl(fd, F_SETFD, flag);
|
||||
} while((err < 0) && (errno == EINTR)) ;
|
||||
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
return(err);
|
||||
}
|
||||
|
||||
int os_pipe(int *fds, int stream, int close_on_exec)
|
||||
{
|
||||
int err, type = stream ? SOCK_STREAM : SOCK_DGRAM;
|
||||
|
||||
err = socketpair(AF_UNIX, type, 0, fds);
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
|
||||
if(!close_on_exec)
|
||||
return(0);
|
||||
|
||||
err = os_set_exec_close(fds[0], 1);
|
||||
if(err < 0)
|
||||
goto error;
|
||||
|
||||
err = os_set_exec_close(fds[1], 1);
|
||||
if(err < 0)
|
||||
goto error;
|
||||
|
||||
return(0);
|
||||
|
||||
error:
|
||||
printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err);
|
||||
os_close_file(fds[1]);
|
||||
os_close_file(fds[0]);
|
||||
return(err);
|
||||
}
|
||||
|
||||
int os_set_fd_async(int fd, int owner)
|
||||
{
|
||||
/* XXX This should do F_GETFL first */
|
||||
if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){
|
||||
printk("os_set_fd_async : failed to set O_ASYNC and "
|
||||
"O_NONBLOCK on fd # %d, errno = %d\n", fd, errno);
|
||||
return(-errno);
|
||||
}
|
||||
#ifdef notdef
|
||||
if(fcntl(fd, F_SETFD, 1) < 0){
|
||||
printk("os_set_fd_async : Setting FD_CLOEXEC failed, "
|
||||
"errno = %d\n", errno);
|
||||
}
|
||||
#endif
|
||||
|
||||
if((fcntl(fd, F_SETSIG, SIGIO) < 0) ||
|
||||
(fcntl(fd, F_SETOWN, owner) < 0)){
|
||||
printk("os_set_fd_async : Failed to fcntl F_SETOWN "
|
||||
"(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd,
|
||||
owner, errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_clear_fd_async(int fd)
|
||||
{
|
||||
int flags = fcntl(fd, F_GETFL);
|
||||
|
||||
flags &= ~(O_ASYNC | O_NONBLOCK);
|
||||
if(fcntl(fd, F_SETFL, flags) < 0)
|
||||
return(-errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_set_fd_block(int fd, int blocking)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
|
||||
if(blocking) flags &= ~O_NONBLOCK;
|
||||
else flags |= O_NONBLOCK;
|
||||
|
||||
if(fcntl(fd, F_SETFL, flags) < 0){
|
||||
printk("Failed to change blocking on fd # %d, errno = %d\n",
|
||||
fd, errno);
|
||||
return(-errno);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_accept_connection(int fd)
|
||||
{
|
||||
int new;
|
||||
|
||||
new = accept(fd, NULL, 0);
|
||||
if(new < 0)
|
||||
return(-errno);
|
||||
return(new);
|
||||
}
|
||||
|
||||
#ifndef SHUT_RD
|
||||
#define SHUT_RD 0
|
||||
#endif
|
||||
|
||||
#ifndef SHUT_WR
|
||||
#define SHUT_WR 1
|
||||
#endif
|
||||
|
||||
#ifndef SHUT_RDWR
|
||||
#define SHUT_RDWR 2
|
||||
#endif
|
||||
|
||||
int os_shutdown_socket(int fd, int r, int w)
|
||||
{
|
||||
int what, err;
|
||||
|
||||
if(r && w) what = SHUT_RDWR;
|
||||
else if(r) what = SHUT_RD;
|
||||
else if(w) what = SHUT_WR;
|
||||
else {
|
||||
printk("os_shutdown_socket : neither r or w was set\n");
|
||||
return(-EINVAL);
|
||||
}
|
||||
err = shutdown(fd, what);
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_rcv_fd(int fd, int *helper_pid_out)
|
||||
{
|
||||
int new, n;
|
||||
char buf[CMSG_SPACE(sizeof(new))];
|
||||
struct msghdr msg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec iov;
|
||||
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
iov = ((struct iovec) { .iov_base = helper_pid_out,
|
||||
.iov_len = sizeof(*helper_pid_out) });
|
||||
msg.msg_iov = &iov;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_control = buf;
|
||||
msg.msg_controllen = sizeof(buf);
|
||||
msg.msg_flags = 0;
|
||||
|
||||
n = recvmsg(fd, &msg, 0);
|
||||
if(n < 0)
|
||||
return(-errno);
|
||||
|
||||
else if(n != sizeof(iov.iov_len))
|
||||
*helper_pid_out = -1;
|
||||
|
||||
cmsg = CMSG_FIRSTHDR(&msg);
|
||||
if(cmsg == NULL){
|
||||
printk("rcv_fd didn't receive anything, error = %d\n", errno);
|
||||
return(-1);
|
||||
}
|
||||
if((cmsg->cmsg_level != SOL_SOCKET) ||
|
||||
(cmsg->cmsg_type != SCM_RIGHTS)){
|
||||
printk("rcv_fd didn't receive a descriptor\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
new = ((int *) CMSG_DATA(cmsg))[0];
|
||||
return(new);
|
||||
}
|
||||
|
||||
int os_create_unix_socket(char *file, int len, int close_on_exec)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
int sock, err;
|
||||
|
||||
sock = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
if (sock < 0){
|
||||
printk("create_unix_socket - socket failed, errno = %d\n",
|
||||
errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
if(close_on_exec) {
|
||||
err = os_set_exec_close(sock, 1);
|
||||
if(err < 0)
|
||||
printk("create_unix_socket : close_on_exec failed, "
|
||||
"err = %d", -err);
|
||||
}
|
||||
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
/* XXX Be more careful about overflow */
|
||||
snprintf(addr.sun_path, len, "%s", file);
|
||||
|
||||
err = bind(sock, (struct sockaddr *) &addr, sizeof(addr));
|
||||
if (err < 0){
|
||||
printk("create_listening_socket at '%s' - bind failed, "
|
||||
"errno = %d\n", file, errno);
|
||||
return(-errno);
|
||||
}
|
||||
|
||||
return(sock);
|
||||
}
|
||||
|
||||
void os_flush_stdout(void)
|
||||
{
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int os_lock_file(int fd, int excl)
|
||||
{
|
||||
int type = excl ? F_WRLCK : F_RDLCK;
|
||||
struct flock lock = ((struct flock) { .l_type = type,
|
||||
.l_whence = SEEK_SET,
|
||||
.l_start = 0,
|
||||
.l_len = 0 } );
|
||||
int err, save;
|
||||
|
||||
err = fcntl(fd, F_SETLK, &lock);
|
||||
if(!err)
|
||||
goto out;
|
||||
|
||||
save = -errno;
|
||||
err = fcntl(fd, F_GETLK, &lock);
|
||||
if(err){
|
||||
err = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid);
|
||||
err = save;
|
||||
out:
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
22
arch/um/os-Linux/include/file.h
Normal file
22
arch/um/os-Linux/include/file.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#ifndef __OS_FILE_H__
|
||||
#define __OS_FILE_H__
|
||||
|
||||
#define DEV_NULL "/dev/null"
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
171
arch/um/os-Linux/process.c
Normal file
171
arch/um/os-Linux/process.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@addtoit.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/wait.h>
|
||||
#include "ptrace_user.h"
|
||||
#include "os.h"
|
||||
#include "user.h"
|
||||
#include "user_util.h"
|
||||
|
||||
#define ARBITRARY_ADDR -1
|
||||
#define FAILURE_PID -1
|
||||
|
||||
#define STAT_PATH_LEN sizeof("/proc/#######/stat\0")
|
||||
#define COMM_SCANF "%*[^)])"
|
||||
|
||||
unsigned long os_process_pc(int pid)
|
||||
{
|
||||
char proc_stat[STAT_PATH_LEN], buf[256];
|
||||
unsigned long pc;
|
||||
int fd, err;
|
||||
|
||||
sprintf(proc_stat, "/proc/%d/stat", pid);
|
||||
fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0);
|
||||
if(fd < 0){
|
||||
printk("os_process_pc - couldn't open '%s', err = %d\n",
|
||||
proc_stat, -fd);
|
||||
return(ARBITRARY_ADDR);
|
||||
}
|
||||
err = os_read_file(fd, buf, sizeof(buf));
|
||||
if(err < 0){
|
||||
printk("os_process_pc - couldn't read '%s', err = %d\n",
|
||||
proc_stat, -err);
|
||||
os_close_file(fd);
|
||||
return(ARBITRARY_ADDR);
|
||||
}
|
||||
os_close_file(fd);
|
||||
pc = ARBITRARY_ADDR;
|
||||
if(sscanf(buf, "%*d " COMM_SCANF " %*c %*d %*d %*d %*d %*d %*d %*d "
|
||||
"%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "
|
||||
"%*d %*d %*d %*d %*d %lu", &pc) != 1){
|
||||
printk("os_process_pc - couldn't find pc in '%s'\n", buf);
|
||||
}
|
||||
return(pc);
|
||||
}
|
||||
|
||||
int os_process_parent(int pid)
|
||||
{
|
||||
char stat[STAT_PATH_LEN];
|
||||
char data[256];
|
||||
int parent, n, fd;
|
||||
|
||||
if(pid == -1) return(-1);
|
||||
|
||||
snprintf(stat, sizeof(stat), "/proc/%d/stat", pid);
|
||||
fd = os_open_file(stat, of_read(OPENFLAGS()), 0);
|
||||
if(fd < 0){
|
||||
printk("Couldn't open '%s', err = %d\n", stat, -fd);
|
||||
return(FAILURE_PID);
|
||||
}
|
||||
|
||||
n = os_read_file(fd, data, sizeof(data));
|
||||
os_close_file(fd);
|
||||
|
||||
if(n < 0){
|
||||
printk("Couldn't read '%s', err = %d\n", stat, -n);
|
||||
return(FAILURE_PID);
|
||||
}
|
||||
|
||||
parent = FAILURE_PID;
|
||||
n = sscanf(data, "%*d " COMM_SCANF " %*c %d", &parent);
|
||||
if(n != 1)
|
||||
printk("Failed to scan '%s'\n", data);
|
||||
|
||||
return(parent);
|
||||
}
|
||||
|
||||
void os_stop_process(int pid)
|
||||
{
|
||||
kill(pid, SIGSTOP);
|
||||
}
|
||||
|
||||
void os_kill_process(int pid, int reap_child)
|
||||
{
|
||||
kill(pid, SIGKILL);
|
||||
if(reap_child)
|
||||
CATCH_EINTR(waitpid(pid, NULL, 0));
|
||||
|
||||
}
|
||||
|
||||
/* Kill off a ptraced child by all means available. kill it normally first,
|
||||
* then PTRACE_KILL it, then PTRACE_CONT it in case it's in a run state from
|
||||
* which it can't exit directly.
|
||||
*/
|
||||
|
||||
void os_kill_ptraced_process(int pid, int reap_child)
|
||||
{
|
||||
kill(pid, SIGKILL);
|
||||
ptrace(PTRACE_KILL, pid);
|
||||
ptrace(PTRACE_CONT, pid);
|
||||
if(reap_child)
|
||||
CATCH_EINTR(waitpid(pid, NULL, 0));
|
||||
}
|
||||
|
||||
void os_usr1_process(int pid)
|
||||
{
|
||||
kill(pid, SIGUSR1);
|
||||
}
|
||||
|
||||
/*Don't use the glibc version, which caches the result in TLS. It misses some
|
||||
* syscalls, and also breaks with clone(), which does not unshare the TLS.*/
|
||||
inline _syscall0(pid_t, getpid)
|
||||
|
||||
int os_getpid(void)
|
||||
{
|
||||
return(getpid());
|
||||
}
|
||||
|
||||
int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len,
|
||||
int r, int w, int x)
|
||||
{
|
||||
void *loc;
|
||||
int prot;
|
||||
|
||||
prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
|
||||
(x ? PROT_EXEC : 0);
|
||||
|
||||
loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED,
|
||||
fd, off);
|
||||
if(loc == MAP_FAILED)
|
||||
return(-errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_protect_memory(void *addr, unsigned long len, int r, int w, int x)
|
||||
{
|
||||
int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
|
||||
(x ? PROT_EXEC : 0));
|
||||
|
||||
if(mprotect(addr, len, prot) < 0)
|
||||
return(-errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int os_unmap_memory(void *addr, int len)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = munmap(addr, len);
|
||||
if(err < 0)
|
||||
return(-errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
48
arch/um/os-Linux/signal.c
Normal file
48
arch/um/os-Linux/signal.c
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2004 PathScale, Inc
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include "time_user.h"
|
||||
#include "mode.h"
|
||||
#include "sysdep/signal.h"
|
||||
|
||||
void sig_handler(int sig)
|
||||
{
|
||||
struct sigcontext *sc;
|
||||
|
||||
ARCH_GET_SIGCONTEXT(sc, sig);
|
||||
CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
|
||||
sig, sc);
|
||||
}
|
||||
|
||||
extern int timer_irq_inited;
|
||||
|
||||
void alarm_handler(int sig)
|
||||
{
|
||||
struct sigcontext *sc;
|
||||
|
||||
ARCH_GET_SIGCONTEXT(sc, sig);
|
||||
if(!timer_irq_inited) return;
|
||||
|
||||
if(sig == SIGALRM)
|
||||
switch_timers(0);
|
||||
|
||||
CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas,
|
||||
sig, sc);
|
||||
|
||||
if(sig == SIGALRM)
|
||||
switch_timers(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
10
arch/um/os-Linux/sys-i386/Makefile
Normal file
10
arch/um/os-Linux/sys-i386/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
|
||||
# Licensed under the GPL
|
||||
#
|
||||
|
||||
obj-$(CONFIG_MODE_SKAS) = registers.o
|
||||
|
||||
USER_OBJS := $(obj-y)
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
132
arch/um/os-Linux/sys-i386/registers.c
Normal file
132
arch/um/os-Linux/sys-i386/registers.c
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (C) 2004 PathScale, Inc
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "sysdep/ptrace_user.h"
|
||||
#include "sysdep/ptrace.h"
|
||||
#include "uml-config.h"
|
||||
#include "skas_ptregs.h"
|
||||
#include "registers.h"
|
||||
#include "user.h"
|
||||
|
||||
/* These are set once at boot time and not changed thereafter */
|
||||
|
||||
static unsigned long exec_regs[HOST_FRAME_SIZE];
|
||||
static unsigned long exec_fp_regs[HOST_FP_SIZE];
|
||||
static unsigned long exec_fpx_regs[HOST_XFP_SIZE];
|
||||
static int have_fpx_regs = 1;
|
||||
|
||||
void init_thread_registers(union uml_pt_regs *to)
|
||||
{
|
||||
memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs));
|
||||
memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp));
|
||||
if(have_fpx_regs)
|
||||
memcpy(to->skas.xfp, exec_fpx_regs, sizeof(to->skas.xfp));
|
||||
}
|
||||
|
||||
/* XXX These need to use [GS]ETFPXREGS and copy_sc_{to,from}_user_skas needs
|
||||
* to pass in a sufficiently large buffer
|
||||
*/
|
||||
int save_fp_registers(int pid, unsigned long *fp_regs)
|
||||
{
|
||||
if(ptrace(PTRACE_GETFPREGS, pid, 0, fp_regs) < 0)
|
||||
return(-errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
int restore_fp_registers(int pid, unsigned long *fp_regs)
|
||||
{
|
||||
if(ptrace(PTRACE_SETFPREGS, pid, 0, fp_regs) < 0)
|
||||
return(-errno);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int move_registers(int pid, int int_op, union uml_pt_regs *regs,
|
||||
int fp_op, unsigned long *fp_regs)
|
||||
{
|
||||
if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
|
||||
return(-errno);
|
||||
|
||||
if(ptrace(fp_op, pid, 0, fp_regs) < 0)
|
||||
return(-errno);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void save_registers(int pid, union uml_pt_regs *regs)
|
||||
{
|
||||
unsigned long *fp_regs;
|
||||
int err, fp_op;
|
||||
|
||||
if(have_fpx_regs){
|
||||
fp_op = PTRACE_GETFPXREGS;
|
||||
fp_regs = regs->skas.xfp;
|
||||
}
|
||||
else {
|
||||
fp_op = PTRACE_GETFPREGS;
|
||||
fp_regs = regs->skas.fp;
|
||||
}
|
||||
|
||||
err = move_registers(pid, PTRACE_GETREGS, regs, fp_op, fp_regs);
|
||||
if(err)
|
||||
panic("save_registers - saving registers failed, errno = %d\n",
|
||||
-err);
|
||||
}
|
||||
|
||||
void restore_registers(int pid, union uml_pt_regs *regs)
|
||||
{
|
||||
unsigned long *fp_regs;
|
||||
int err, fp_op;
|
||||
|
||||
if(have_fpx_regs){
|
||||
fp_op = PTRACE_SETFPXREGS;
|
||||
fp_regs = regs->skas.xfp;
|
||||
}
|
||||
else {
|
||||
fp_op = PTRACE_SETFPREGS;
|
||||
fp_regs = regs->skas.fp;
|
||||
}
|
||||
|
||||
err = move_registers(pid, PTRACE_SETREGS, regs, fp_op, fp_regs);
|
||||
if(err)
|
||||
panic("restore_registers - saving registers failed, "
|
||||
"errno = %d\n", -err);
|
||||
}
|
||||
|
||||
void init_registers(int pid)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
|
||||
if(err)
|
||||
panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
|
||||
err);
|
||||
|
||||
err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs);
|
||||
if(!err)
|
||||
return;
|
||||
|
||||
have_fpx_regs = 0;
|
||||
if(err != EIO)
|
||||
panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d",
|
||||
err);
|
||||
|
||||
err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
|
||||
if(err)
|
||||
panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
|
||||
err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
10
arch/um/os-Linux/sys-x86_64/Makefile
Normal file
10
arch/um/os-Linux/sys-x86_64/Makefile
Normal file
@@ -0,0 +1,10 @@
|
||||
#
|
||||
# Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
|
||||
# Licensed under the GPL
|
||||
#
|
||||
|
||||
obj-$(CONFIG_MODE_SKAS) = registers.o
|
||||
|
||||
USER_OBJS := $(obj-y)
|
||||
|
||||
include arch/um/scripts/Makefile.rules
|
81
arch/um/os-Linux/sys-x86_64/registers.c
Normal file
81
arch/um/os-Linux/sys-x86_64/registers.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2004 PathScale, Inc
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include "ptrace_user.h"
|
||||
#include "uml-config.h"
|
||||
#include "skas_ptregs.h"
|
||||
#include "registers.h"
|
||||
#include "user.h"
|
||||
|
||||
/* These are set once at boot time and not changed thereafter */
|
||||
|
||||
static unsigned long exec_regs[HOST_FRAME_SIZE];
|
||||
static unsigned long exec_fp_regs[HOST_FP_SIZE];
|
||||
|
||||
void init_thread_registers(union uml_pt_regs *to)
|
||||
{
|
||||
memcpy(to->skas.regs, exec_regs, sizeof(to->skas.regs));
|
||||
memcpy(to->skas.fp, exec_fp_regs, sizeof(to->skas.fp));
|
||||
}
|
||||
|
||||
static int move_registers(int pid, int int_op, int fp_op,
|
||||
union uml_pt_regs *regs)
|
||||
{
|
||||
if(ptrace(int_op, pid, 0, regs->skas.regs) < 0)
|
||||
return(-errno);
|
||||
|
||||
if(ptrace(fp_op, pid, 0, regs->skas.fp) < 0)
|
||||
return(-errno);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
void save_registers(int pid, union uml_pt_regs *regs)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = move_registers(pid, PTRACE_GETREGS, PTRACE_GETFPREGS, regs);
|
||||
if(err)
|
||||
panic("save_registers - saving registers failed, errno = %d\n",
|
||||
-err);
|
||||
}
|
||||
|
||||
void restore_registers(int pid, union uml_pt_regs *regs)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = move_registers(pid, PTRACE_SETREGS, PTRACE_SETFPREGS, regs);
|
||||
if(err)
|
||||
panic("restore_registers - saving registers failed, "
|
||||
"errno = %d\n", -err);
|
||||
}
|
||||
|
||||
void init_registers(int pid)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ptrace(PTRACE_GETREGS, pid, 0, exec_regs);
|
||||
if(err)
|
||||
panic("check_ptrace : PTRACE_GETREGS failed, errno = %d",
|
||||
err);
|
||||
|
||||
err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs);
|
||||
if(err)
|
||||
panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d",
|
||||
err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
21
arch/um/os-Linux/time.c
Normal file
21
arch/um/os-Linux/time.c
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
unsigned long long os_usecs(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
return((unsigned long long) tv.tv_sec * 1000000 + tv.tv_usec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
61
arch/um/os-Linux/tty.c
Normal file
61
arch/um/os-Linux/tty.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include "os.h"
|
||||
#include "user.h"
|
||||
#include "kern_util.h"
|
||||
|
||||
struct grantpt_info {
|
||||
int fd;
|
||||
int res;
|
||||
int err;
|
||||
};
|
||||
|
||||
static void grantpt_cb(void *arg)
|
||||
{
|
||||
struct grantpt_info *info = arg;
|
||||
|
||||
info->res = grantpt(info->fd);
|
||||
info->err = errno;
|
||||
}
|
||||
|
||||
int get_pty(void)
|
||||
{
|
||||
struct grantpt_info info;
|
||||
int fd;
|
||||
|
||||
fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0);
|
||||
if(fd < 0){
|
||||
printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd);
|
||||
return(fd);
|
||||
}
|
||||
|
||||
info.fd = fd;
|
||||
initial_thread_cb(grantpt_cb, &info);
|
||||
|
||||
if(info.res < 0){
|
||||
printk("get_pty : Couldn't grant pty - errno = %d\n",
|
||||
-info.err);
|
||||
return(-1);
|
||||
}
|
||||
if(unlockpt(fd) < 0){
|
||||
printk("get_pty : Couldn't unlock pty - errno = %d\n", errno);
|
||||
return(-1);
|
||||
}
|
||||
return(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
95
arch/um/os-Linux/user_syms.c
Normal file
95
arch/um/os-Linux/user_syms.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "linux/types.h"
|
||||
#include "linux/module.h"
|
||||
|
||||
/* Some of this are builtin function (some are not but could in the future),
|
||||
* so I *must* declare good prototypes for them and then EXPORT them.
|
||||
* The kernel code uses the macro defined by include/linux/string.h,
|
||||
* so I undef macros; the userspace code does not include that and I
|
||||
* add an EXPORT for the glibc one.*/
|
||||
|
||||
#undef strlen
|
||||
#undef strstr
|
||||
#undef memcpy
|
||||
#undef memset
|
||||
|
||||
extern size_t strlen(const char *);
|
||||
extern void *memcpy(void *, const void *, size_t);
|
||||
extern void *memmove(void *, const void *, size_t);
|
||||
extern void *memset(void *, int, size_t);
|
||||
extern int printf(const char *, ...);
|
||||
|
||||
EXPORT_SYMBOL(strlen);
|
||||
EXPORT_SYMBOL(memcpy);
|
||||
EXPORT_SYMBOL(memmove);
|
||||
EXPORT_SYMBOL(memset);
|
||||
EXPORT_SYMBOL(printf);
|
||||
|
||||
EXPORT_SYMBOL(strstr);
|
||||
|
||||
/* Here, instead, I can provide a fake prototype. Yes, someone cares: genksyms.
|
||||
* However, the modules will use the CRC defined *here*, no matter if it is
|
||||
* good; so the versions of these symbols will always match
|
||||
*/
|
||||
#define EXPORT_SYMBOL_PROTO(sym) \
|
||||
int sym(void); \
|
||||
EXPORT_SYMBOL(sym);
|
||||
|
||||
#ifdef SUBARCH_i386
|
||||
EXPORT_SYMBOL(vsyscall_ehdr);
|
||||
EXPORT_SYMBOL(vsyscall_end);
|
||||
#endif
|
||||
|
||||
EXPORT_SYMBOL_PROTO(__errno_location);
|
||||
|
||||
EXPORT_SYMBOL_PROTO(access);
|
||||
EXPORT_SYMBOL_PROTO(open);
|
||||
EXPORT_SYMBOL_PROTO(open64);
|
||||
EXPORT_SYMBOL_PROTO(close);
|
||||
EXPORT_SYMBOL_PROTO(read);
|
||||
EXPORT_SYMBOL_PROTO(write);
|
||||
EXPORT_SYMBOL_PROTO(dup2);
|
||||
EXPORT_SYMBOL_PROTO(__xstat);
|
||||
EXPORT_SYMBOL_PROTO(__lxstat);
|
||||
EXPORT_SYMBOL_PROTO(__lxstat64);
|
||||
EXPORT_SYMBOL_PROTO(lseek);
|
||||
EXPORT_SYMBOL_PROTO(lseek64);
|
||||
EXPORT_SYMBOL_PROTO(chown);
|
||||
EXPORT_SYMBOL_PROTO(truncate);
|
||||
EXPORT_SYMBOL_PROTO(utime);
|
||||
EXPORT_SYMBOL_PROTO(chmod);
|
||||
EXPORT_SYMBOL_PROTO(rename);
|
||||
EXPORT_SYMBOL_PROTO(__xmknod);
|
||||
|
||||
EXPORT_SYMBOL_PROTO(symlink);
|
||||
EXPORT_SYMBOL_PROTO(link);
|
||||
EXPORT_SYMBOL_PROTO(unlink);
|
||||
EXPORT_SYMBOL_PROTO(readlink);
|
||||
|
||||
EXPORT_SYMBOL_PROTO(mkdir);
|
||||
EXPORT_SYMBOL_PROTO(rmdir);
|
||||
EXPORT_SYMBOL_PROTO(opendir);
|
||||
EXPORT_SYMBOL_PROTO(readdir);
|
||||
EXPORT_SYMBOL_PROTO(closedir);
|
||||
EXPORT_SYMBOL_PROTO(seekdir);
|
||||
EXPORT_SYMBOL_PROTO(telldir);
|
||||
|
||||
EXPORT_SYMBOL_PROTO(ioctl);
|
||||
|
||||
EXPORT_SYMBOL_PROTO(pread64);
|
||||
EXPORT_SYMBOL_PROTO(pwrite64);
|
||||
|
||||
EXPORT_SYMBOL_PROTO(statfs);
|
||||
EXPORT_SYMBOL_PROTO(statfs64);
|
||||
|
||||
EXPORT_SYMBOL_PROTO(getuid);
|
||||
|
||||
/*
|
||||
* Overrides for Emacs so that we follow Linus's tabbing style.
|
||||
* Emacs will notice this stuff at the end of the file and automatically
|
||||
* adjust the settings for this buffer only. This must remain at the end
|
||||
* of the file.
|
||||
* ---------------------------------------------------------------------------
|
||||
* Local variables:
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
4
arch/um/os-Linux/util/Makefile
Normal file
4
arch/um/os-Linux/util/Makefile
Normal file
@@ -0,0 +1,4 @@
|
||||
hostprogs-y := mk_user_constants
|
||||
always := $(hostprogs-y)
|
||||
|
||||
mk_user_constants-objs := mk_user_constants.o
|
29
arch/um/os-Linux/util/mk_user_constants.c
Normal file
29
arch/um/os-Linux/util/mk_user_constants.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
#include <asm/types.h>
|
||||
/* For some reason, x86_64 nowhere defines u64 and u32, even though they're
|
||||
* used throughout the headers.
|
||||
*/
|
||||
typedef __u64 u64;
|
||||
typedef __u32 u32;
|
||||
#include <asm/user.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("/*\n");
|
||||
printf(" * Generated by mk_user_constants\n");
|
||||
printf(" */\n");
|
||||
printf("\n");
|
||||
printf("#ifndef __UM_USER_CONSTANTS_H\n");
|
||||
printf("#define __UM_USER_CONSTANTS_H\n");
|
||||
printf("\n");
|
||||
/* I'd like to use FRAME_SIZE from ptrace.h here, but that's wrong on
|
||||
* x86_64 (216 vs 168 bytes). user_regs_struct is the correct size on
|
||||
* both x86_64 and i386.
|
||||
*/
|
||||
printf("#define UM_FRAME_SIZE %d\n", (int) sizeof(struct user_regs_struct));
|
||||
|
||||
printf("\n");
|
||||
printf("#endif\n");
|
||||
|
||||
return(0);
|
||||
}
|
Reference in New Issue
Block a user