Commit 611088c3 authored by Danilo Sabato's avatar Danilo Sabato Committed by Alessandro Rubini

arch-bare-x86-64: a copy of arch-bare-linux

parent a75b2d88
# Alessandro Rubini for CERN, 2011 -- public domain
CFLAGS += -ffreestanding -Os -fno-stack-protector
ARCH_LDFLAGS = -nostdlib -static -T $(ARCH).lds
# All files are under A (short for ARCH): I'm lazy
A := arch-$(ARCH)
LIBARCH := $A/libarch.a
OBJ-libarch := $A/bare-startup.o \
$A/main-loop.o \
$A/bare-socket.o \
$A/bare-timer.o \
$A/bare-io.o \
$A/syscalls.o \
lib/div64.o
$(LIBARCH): $(OBJ-libarch)
$(AR) r $@ $^
all: $(TARGET)
# to build the target, we need -lstd again, in case we call functions that
# were not selected yet (e.g., pp_open_instance() ).
$(TARGET): $(TARGET).o $A/crt0.o $(LIBARCH)
$(CC) -Wl,-Map,$(TARGET).map2 $(ARCH_LDFLAGS) -o $@ $A/crt0.o \
$(TARGET).o -L$A -larch -L$D -lstd
/*
* Alessandro Rubini for CERN, 2011 -- GPL 2 or later (it includes u-boot code)
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include "bare-linux.h"
const Integer32 PP_ADJ_FREQ_MAX = 512000;
void pp_puts(const char *s)
{
sys_write(0, s, pp_strnlen(s, 300));
}
int pp_strnlen(const char *s, int maxlen)
{
int len = 0;
while (*(s++))
len++;
return len;
}
void *pp_memcpy(void *dest, const void *src, int count)
{
/* from u-boot-1.1.2 */
char *tmp = (char *) dest, *s = (char *) src;
while (count--)
*tmp++ = *s++;
return dest;
}
void bare_get_tstamp(TimeInternal *t)
{
struct bare_timeval tv;
if (sys_gettimeofday(&tv, NULL) < 0) {
PP_PRINTF("gettimeofday error");
sys_exit(0);
}
t->seconds = tv.tv_sec;
t->nanoseconds = (tv.tv_usec % 1000) * 1000;
}
int32_t bare_set_tstamp(TimeInternal *t)
{
struct bare_timeval tv_orig;
struct bare_timeval tv;
if (sys_gettimeofday(&tv_orig, NULL) < 0) {
PP_PRINTF("gettimeofday error");
sys_exit(0);
}
tv.tv_sec = t->seconds;
tv.tv_usec = t->nanoseconds / 1000;
if (sys_settimeofday(&tv, NULL) < 0) {
PP_PRINTF("settimeofday error");
sys_exit(0);
}
return tv.tv_sec - tv_orig.tv_sec;
}
int pp_memcmp(const void *cs, const void *ct, int count)
{
/* from u-boot-1.1.2 */
const unsigned char *su1, *su2;
int res = 0;
for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
if ((res = *su1 - *su2) != 0)
break;
return res;
}
void *pp_memset(void *s, int c, int count)
{
/* from u-boot-1.1.2 */
char *xs = (char *) s;
while (count--)
*xs++ = c;
return s;
}
/* What follows has no prefix because it's only used by arch code */
char *strcpy(char *dest, const char *src)
{
/* from u-boot-1.1.2 */
char *tmp = dest;
while ((*dest++ = *src++) != '\0')
/* nothing */;
return tmp;
}
void *memset(void *s, int c, int count)
__attribute__((alias("pp_memset")));
void *memcpy(void *dest, const void *src, int count)
__attribute__((alias("pp_memcpy")));
int bare_adj_freq(Integer32 adj)
{
struct bare_timex t;
if (adj > PP_ADJ_FREQ_MAX)
adj = PP_ADJ_FREQ_MAX;
else if (adj < -PP_ADJ_FREQ_MAX)
adj = -PP_ADJ_FREQ_MAX;
t.modes = MOD_FREQUENCY;
t.freq = adj * ((1 << 16) / 1000);
return !sys_adjtimex(&t);
}
int32_t pp_set_tstamp(TimeInternal *t)
__attribute__((alias("bare_set_tstamp")));
void pp_get_tstamp(TimeInternal *t)
__attribute__((alias("bare_get_tstamp")));
int pp_adj_freq(Integer32 adj)
__attribute__((alias("bare_adj_freq")));
/*
* Alessandro Rubini for CERN, 2011 -- GNU LGPL v2.1 or later
*/
/*
* These are the functions provided by the various bare files
*/
extern int bare_open_ch(struct pp_instance *ppi, char *name);
extern int bare_recv_packet(struct pp_instance *ppi, void *pkt, int len,
TimeInternal *t);
extern int bare_send_packet(struct pp_instance *ppi, void *pkt, int len,
int chtype, int use_pdelay_addr);
extern void bare_main_loop(struct pp_instance *ppi);
/* basics */
extern void *memset(void *s, int c, int count);
extern char *strcpy(char *dest, const char *src);
extern void *memcpy(void *dest, const void *src, int count);
/* syscalls */
struct bare_sockaddr;
extern int sys_write(int fd, const void *buf, int count);
extern void sys_exit(int exitval);
extern int sys_time(int tz);
extern int sys_select(int max, void *in, void *out, void *exc, void *tout);
extern int sys_ioctl(int fd, int cmd, void *arg);
extern int sys_socket(int domain, int type, int proto);
extern int sys_bind(int fd, const struct bare_sockaddr *addr, int addrlen);
extern int sys_recv(int fd, void *pkt, int plen, int flags);
extern int sys_send(int fd, void *pkt, int plen, int flags);
extern int sys_shutdown(int fd, int flags);
extern int sys_gettimeofday(void *tv, void *z);
extern int sys_settimeofday(void *tv, void *z);
extern int sys_adjtimex(void *tv);
extern int bare_errno;
/* structures passed to syscalls */
#define IFNAMSIZ 16
struct bare_sockaddr {
uint16_t sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
struct bare_ifreq {
union {
char ifrn_name[IFNAMSIZ];
} ifr_ifrn;
union {
struct bare_sockaddr ifru_hwaddr;
int index;
} ifr_ifru;
};
struct bare_sockaddr_ll {
unsigned short int sll_family;
unsigned short int sll_protocol;
int sll_ifindex;
unsigned short int sll_hatype;
unsigned char sll_pkttype;
unsigned char sll_halen;
unsigned char sll_addr[8];
};
#define SIOCGIFINDEX 0x8933
#define SIOCGIFHWADDR 0x8927
/* other network stuff, bah.... */
struct bare_ethhdr {
unsigned char h_dest[6];
unsigned char h_source[6];
uint16_t h_proto;
} __attribute__((packed));
struct bare_timeval {
unsigned long tv_sec;
unsigned long tv_usec;
};
#ifndef NULL
#define NULL 0
#endif
/* from linux/timex.h */
/*
* Mode codes (timex.mode)
*/
#define ADJ_OFFSET 0x0001 /* time offset */
#define ADJ_FREQUENCY 0x0002 /* frequency offset */
#define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_ESTERROR 0x0008 /* estimated time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
#define ADJ_TAI 0x0080 /* set TAI offset */
#define ADJ_MICRO 0x1000 /* select microsecond resolution */
#define ADJ_NANO 0x2000 /* select nanosecond resolution */
#define ADJ_TICK 0x4000 /* tick value */
#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */
#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */
/* xntp 3.4 compatibility names */
#define MOD_OFFSET ADJ_OFFSET
#define MOD_FREQUENCY ADJ_FREQUENCY
#define MOD_MAXERROR ADJ_MAXERROR
#define MOD_ESTERROR ADJ_ESTERROR
#define MOD_STATUS ADJ_STATUS
#define MOD_TIMECONST ADJ_TIMECONST
struct bare_timex {
unsigned int modes; /* mode selector */
long offset; /* time offset (usec) */
long freq; /* frequency offset (scaled ppm) */
long maxerror; /* maximum error (usec) */
long esterror; /* estimated error (usec) */
int status; /* clock command/status */
long constant; /* pll time constant */
long precision; /* clock precision (usec) (read only) */
long tolerance; /* clock frequency tolerance (ppm)
* (read only)
*/
struct bare_timeval time; /* (read only) */
long tick; /* (modified) usecs between clock ticks */
long ppsfreq; /* pps frequency (scaled ppm) (ro) */
long jitter; /* pps jitter (us) (ro) */
int shift; /* interval duration (s) (shift) (ro) */
long stabil; /* pps stability (scaled ppm) (ro) */
long jitcnt; /* jitter limit exceeded (ro) */
long calcnt; /* calibration intervals (ro) */
long errcnt; /* calibration errors (ro) */
long stbcnt; /* stability limit exceeded (ro) */
int tai; /* TAI offset (ro) */
int :32; int :32; int :32; int :32;
int :32; int :32; int :32; int :32;
int :32; int :32; int :32;
};
OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_ppsi_start)
SECTIONS
{
. = 0x10000000; /* A random address, non-standard by choice*/
.text : {
_ppsi_start = .;
*(.boot)
*(.text)
}
.rodata : { *(.rodata) }
.data : { *(.data) }
.bss : {
. = ALIGN(16);
__bss_start = .;
*(.bss);
. = ALIGN(16);
__bss_end = .;
}
}
/*
* Alessandro Rubini for CERN, 2011 -- public domain
*/
/* Socket interface for bare Linux */
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include "bare-linux.h"
/* 14 is ppi->proto_ofst for ethernet mode */
Octet buffer_out[PP_PACKET_SIZE + 14];
/* FIXME: which socket we receive and send with? */
int bare_recv_packet(struct pp_instance *ppi, void *pkt, int len,
TimeInternal *t)
{
return sys_recv(NP(ppi)->ch[PP_NP_GEN].fd, pkt, len, 0);
}
int bare_send_packet(struct pp_instance *ppi, void *pkt, int len, int chtype,
int use_pdelay_addr)
{
return sys_send(NP(ppi)->ch[chtype].fd, pkt, len, 0);
}
int pp_recv_packet(struct pp_instance *ppi, void *pkt, int len, TimeInternal *t)
__attribute__((alias("bare_recv_packet")));
int pp_send_packet(struct pp_instance *ppi, void *pkt, int len,
TimeInternal *t, int chtype, int use_pdelay_addr)
__attribute__((alias("bare_send_packet")));
#define SHUT_RD 0
#define SHUT_WR 1
#define SHUT_RDWR 2
#define PF_PACKET 17
#define SOCK_RAW 3
/* To open a channel we must bind to an interface and so on */
int bare_open_ch(struct pp_instance *ppi, char *ifname)
{
int sock, iindex;
struct bare_ifreq ifr;
struct bare_sockaddr_ll addr;
/* open socket */
sock = sys_socket(PF_PACKET, SOCK_RAW, PP_ETHERTYPE);
if (sock < 0) {
pp_diag_error(ppi, bare_errno);
pp_diag_fatal(ppi, "socket()", "");
}
/* hw interface information */
memset(&ifr, 0, sizeof(ifr));
strcpy(ifr.ifr_ifrn.ifrn_name, ifname);
if (sys_ioctl(sock, SIOCGIFINDEX, &ifr) < 0) {
pp_diag_error(ppi, bare_errno);
pp_diag_fatal(ppi, "ioctl(GIFINDEX)", "");
}
iindex = ifr.ifr_ifru.index;
if (sys_ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
pp_diag_error(ppi, bare_errno);
pp_diag_fatal(ppi, "ioctl(GIFHWADDR)", "");
}
memcpy(NP(ppi)->ch[PP_NP_GEN].addr,
ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);
memcpy(NP(ppi)->ch[PP_NP_EVT].addr,
ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);
/* bind and setsockopt */
memset(&addr, 0, sizeof(addr));
addr.sll_family = PF_PACKET;
addr.sll_protocol = htons(PP_ETHERTYPE);
addr.sll_ifindex = iindex;
if (sys_bind(sock, (struct bare_sockaddr *)&addr, sizeof(addr)) < 0) {
pp_diag_error(ppi, bare_errno);
pp_diag_fatal(ppi, "bind", "");
}
NP(ppi)->ch[PP_NP_GEN].fd = sock;
NP(ppi)->ch[PP_NP_EVT].fd = sock;
return 0;
}
int bare_net_init(struct pp_instance *ppi)
{
ppi->buf_out = buffer_out;
ppi->buf_out = PROTO_PAYLOAD(ppi->buf_out);
if (OPTS(ppi)->ethernet_mode) {
PP_PRINTF("bare_net_init IEEE 802.3\n");
/* raw sockets implementation always use gen socket */
return bare_open_ch(ppi, OPTS(ppi)->iface_name);
}
/* else: UDP */
PP_PRINTF("bare_net_init UDP\n");
return 0;
}
int pp_net_init(struct pp_instance *ppi)
__attribute__((alias("bare_net_init")));
int bare_net_shutdown(struct pp_instance *ppi)
{
return sys_shutdown(NP(ppi)->ch[PP_NP_GEN].fd, SHUT_RDWR);
}
int pp_net_shutdown(struct pp_instance *ppi)
__attribute__((alias("bare_net_shutdown")));
/*
* Alessandro Rubini for CERN, 2011 -- GNU LGPL v2.1 or later
*/
/*
* This is the startup thing for "freestanding" stuff under Linux.
* It must also clear the BSS as I'm too lazy to do that in asm
*/
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include "bare-linux.h"
void ppsi_clear_bss(void)
{
int *ptr;
extern int __bss_start, __bss_end;
for (ptr = &__bss_start; ptr < &__bss_end; ptr++)
*ptr = 0;
}
static struct pp_instance ppi_static;
static struct pp_net_path net_path_static;
int pp_diag_verbosity = 0;
/* ppi fields */
static UInteger16 sent_seq_id[16];
static DSDefault defaultDS;
static DSCurrent currentDS;
static DSParent parentDS;
static DSPort portDS;
static DSTimeProperties timePropertiesDS;
static struct pp_servo servo;
static struct pp_frgn_master frgn_master;
void ppsi_main(void)
{
struct pp_instance *ppi = &ppi_static; /* no malloc, one instance */
PP_PRINTF("bare: starting. Compiled on %s\n", __DATE__);
ppi->net_path = &net_path_static;
ppi->sent_seq_id = sent_seq_id;
ppi->defaultDS = &defaultDS;
ppi->currentDS = &currentDS;
ppi->parentDS = &parentDS;
ppi->portDS = &portDS;
ppi->timePropertiesDS = &timePropertiesDS;
ppi->servo = &servo;
ppi->frgn_master = &frgn_master;
ppi->arch_data = NULL;
if (bare_open_ch(ppi, "eth0")) {
pp_diag_error(ppi, bare_errno);
pp_diag_fatal(ppi, "open_ch", "");
}
pp_open_instance(ppi, NULL);
OPTS(ppi)->iface_name = "eth0";
#ifdef PPSI_SLAVE
OPTS(ppi)->slave_only = 1;
#endif
bare_main_loop(ppi);
}
#include <ppsi/ppsi.h>
#include <ppsi/diag.h>
#include "bare-linux.h"
#include <unistd.h>
static struct pp_timer bare_timers[PP_TIMER_ARRAY_SIZE];
int bare_timer_init(struct pp_instance *ppi)
{
uint32_t i;
for(i =0; i<PP_TIMER_ARRAY_SIZE; i++)
ppi->timers[i] = &bare_timers[i];
return 0;
}
int bare_timer_start(uint32_t interval, struct pp_timer *tm)
{
tm->start = (uint32_t)sys_time(0);
tm->interval = interval;
return 0;
}
int bare_timer_stop(struct pp_timer *tm)
{
tm->interval = 0;
tm->start = 0;
return 0;
}
int bare_timer_expired(struct pp_timer *tm)
{
uint32_t now;
if (tm->start == 0) {
PP_PRINTF("%p Warning: bare_timer_expired: timer not started\n",tm);
return 0;
}
now = (uint32_t)sys_time(0);
if (tm->start + tm->interval <= (uint32_t)now) {
tm->start = (uint32_t)now;
return 1;
}
return 0;
}
void bare_timer_adjust_all(struct pp_instance *ppi, int32_t diff)
{
int i;
for (i = 0; i < PP_TIMER_ARRAY_SIZE; i++) {
ppi->timers[i]->start += diff;
}
}
int pp_timer_init(struct pp_instance *ppi)
__attribute__((alias("bare_timer_init")));
int pp_timer_start(uint32_t interval, struct pp_timer *tm)
__attribute__((alias("bare_timer_start")));
int pp_timer_stop(struct pp_timer *tm)
__attribute__((alias("bare_timer_stop")));
int pp_timer_expired(struct pp_timer *tm)
__attribute__((alias("bare_timer_expired")));
void pp_timer_adjust_all(struct pp_instance *ppi, int32_t diff)
__attribute__((alias("bare_timer_adjust_all")));
/*
* A stupid crt0.S for "freestanding" stuff on gnu/linux
* Alessandro Rubini for CERN, 2011 -- GNU GPL v2 or later
*/
.section .boot, "ax"
.extern ppsi_main
call ppsi_clear_bss /* In C, lazy me */
call ppsi_main
.end
\ No newline at end of file
#ifndef __ARCH_H__
#define __ARCH_H__
/* Architecture-specific defines, included by top-level stuff */
/* please note that these have multiple evaluation of the argument */
#define htons(x) __bswap_16(x)
#define __bswap_16(x) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8))
#define htonl(x) __bswap_32(x)
#define __bswap_32(x) ( \
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24))
#define ntohs htons
#define ntohl htonl
#define abs(x) ((x >= 0) ? x : -x)
#endif /* __ARCH_H__ */
#ifndef __PPSI_ARCH_CONSTANTS_H__
#define __PPSI_ARCH_CONSTANTS_H__
#ifndef __PPSI_CONSTANTS_H__
#Warning "Please include <ppsi/constants.h> before <arch/constants.h>"
#endif
#undef PP_DEFAULT_ETHERNET_MODE
#define PP_DEFAULT_ETHERNET_MODE 1 /* We only use raw ethernet */
#endif /* __PPSI_ARCH_CONSTANTS_H__ */
/*
* Alessandro Rubini for CERN, 2011 -- GNU LGPL v2.1 or later
*/
/*
* This is the main loop for "freestanding" stuff under Linux.
*/
#include <ppsi/ppsi.h>
#include "bare-linux.h"
/* Define other hackish stuff */
struct bare_fd_set {
unsigned long bits[1024/32];
};
#define FD_ZERO(p) memset(p, 0, sizeof(p))
#define FD_SET(bit, p) ((p)->bits[0] |= (1 << (bit)))
void bare_main_loop(struct pp_instance *ppi)
{
int delay_ms;
set_TimeInternal(&ppi->last_rcv_time, 0, 0);
/*
* The main loop here is based on select. While we are not
* doing anything else but the protocol, this allows extra stuff
* to fit.
*/
delay_ms = pp_state_machine(ppi, NULL, 0);
while (1) {
struct bare_fd_set set;
int i, maxfd;
struct bare_timeval tv;
unsigned char packet[1500];
/* Wait for a packet or for the timeout */
tv.tv_sec = delay_ms / 1000;
tv.tv_usec = (delay_ms % 1000) * 1000;
again:
FD_ZERO(&set);
FD_SET(NP(ppi)->ch[PP_NP_GEN].fd, &set);
FD_SET(NP(ppi)->ch[PP_NP_EVT].fd, &set);
maxfd = NP(ppi)->ch[PP_NP_GEN].fd;
if (NP(ppi)->ch[PP_NP_EVT].fd > maxfd)
maxfd = NP(ppi)->ch[PP_NP_EVT].fd;
i = sys_select(maxfd + 1, &set, NULL, NULL, &tv);
if (i < 0 && bare_errno != 4 /* EINTR */)
sys_exit(__LINE__);
if (i < 0)
continue;
if (i == 0) {
delay_ms = pp_state_machine(ppi, NULL, 0);
continue;
}
/*
* We got a packet. If it's not ours, continue consuming
* the pending timeout.
*
* FIXME: we don't know which socket to receive from
*/
i = bare_recv_packet(ppi, packet, sizeof(packet),
&ppi->last_rcv_time);
ppi->last_rcv_time.seconds += DSPRO(ppi)->currentUtcOffset;
if (((struct bare_ethhdr *)packet)->h_proto
!= htons(PP_ETHERTYPE))
goto again;
delay_ms = pp_state_machine(ppi, packet, i);
}
}
/*
* Alessandro Rubini for CERN, 2011 -- public domain
*/
#include <linux/unistd.h>
#include <ppsi/ppsi.h>
#include "bare-linux.h"
#include "syscalls.h"
int bare_errno;
struct sel_arg_struct {
unsigned long n;
void *inp, *outp, *exp;
void *tvp;
};
/*
* The following lines use defines from Torvalds (linux-2.4.0: see syscalls.h)
*/
_syscall3(int, write, int, fd, const void *, buf, int, count)
_syscall1(int, exit, int, exitcode)
_syscall1(int, time, void *, tz)
_syscall3(int, ioctl, int, fd, int, cmd, void *, arg)
_syscall1(int, select, struct sel_arg_struct *, as)
static _syscall2(int, socketcall, int, call, unsigned long *, args)
_syscall2(int, gettimeofday, void *, tv, void *,z);
_syscall2(int, settimeofday, void *, tv, void *,z);
_syscall1(int, adjtimex, void *, tv);
/*
* In the bare arch I'd better use sys_ prefixed names
*/
int sys_write(int fd, const void *buf, int count)
__attribute__((alias("write")));
void sys_exit(int exitval)
__attribute__((alias("exit")));
int sys_time(int tz)
__attribute__((alias("time")));
int sys_ioctl(int fd, int cmd, void *arg)
__attribute__((alias("ioctl")));
static struct sel_arg_struct as; /* declared as local, it won't work */
int sys_select(int max, void *in, void *out, void *exc, void *tout)
{
as.n = max;
as.inp = in;
as.outp = out;
as.exp = exc;
as.tvp = tout;
return select(&as);
}
int sys_gettimeofday(void *tv, void *z)
{
return gettimeofday(tv, z);
}
int sys_settimeofday(void *tv, void *z)
{
return settimeofday(tv, z);
}
int sys_adjtimex(void *tv)
{
return adjtimex(tv);
}
/* i386 has the socketcall thing. Bah! */
#define SYS_SOCKET 1 /* sys_socket(2) */
#define SYS_BIND 2 /* sys_bind(2) */
#define SYS_CONNECT 3 /* sys_connect(2) */
#define SYS_LISTEN 4 /* sys_listen(2) */
#define SYS_ACCEPT 5 /* sys_accept(2) */
#define SYS_GETSOCKNAME 6 /* sys_getsockname(2) */
#define SYS_GETPEERNAME 7 /* sys_getpeername(2) */
#define SYS_SOCKETPAIR 8 /* sys_socketpair(2) */
#define SYS_SEND 9 /* sys_send(2) */
#define SYS_RECV 10 /* sys_recv(2) */
#define SYS_SENDTO 11 /* sys_sendto(2) */
#define SYS_RECVFROM 12 /* sys_recvfrom(2) */
#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */
#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */
#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */
#define SYS_SENDMSG 16 /* sys_sendmsg(2) */
#define SYS_RECVMSG 17 /* sys_recvmsg(2) */
#define SYS_PACCEPT 18 /* sys_paccept(2) */
static unsigned long args[4];
int sys_socket(int domain, int type, int proto)
{
/*
* Strangely, this is not working for me:
* unsigned long args[3] = {domain, type, proto};
* So let's use an external thing. Who knows why...
*/
args[0] = domain;
args[1] = type;
args[2] = proto;
return socketcall(SYS_SOCKET, args);
}
int sys_bind(int fd, const struct bare_sockaddr *addr, int addrlen)
{
args[0] = fd;
args[1] = (unsigned long)addr;
args[2] = addrlen;
return socketcall(SYS_BIND, args);
}
int sys_recv(int fd, void *pkt, int plen, int flags)
{
args[0] = fd;
args[1] = (unsigned long)pkt;
args[2] = plen;
args[3] = flags;
return socketcall(SYS_RECV, args);
}
int sys_send(int fd, void *pkt, int plen, int flags)
{
args[0] = fd;
args[1] = (unsigned long)pkt;
args[2] = plen;
args[3] = flags;
return socketcall(SYS_SEND, args);
}
int sys_shutdown(int fd, int flags)
{
args[0] = fd;
args[1] = flags;
return socketcall(SYS_SHUTDOWN, args);
}
/*
* From: linux-2.4.0::include/asm-i386/unistd.h
*/
extern int bare_errno;
/*
* user-visible error numbers are in the range -1 - -4096
*/
#define __syscall_return(type, res) \
do { \
if ((unsigned long)(res) >= (unsigned long)(-4096)) { \
bare_errno = -(res); \
res = -1; \
} \
return (type) (res); \
} while (0)
/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */
#define _syscall0(type,name) \
type name(void) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name)); \
__syscall_return(type,__res); \
}
#define _syscall1(type,name,type1,arg1) \
type name(type1 arg1) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1))); \
__syscall_return(type,__res); \
}
#define _syscall2(type,name,type1,arg1,type2,arg2) \
type name(type1 arg1,type2 arg2) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2))); \
__syscall_return(type,__res); \
}
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3))); \
__syscall_return(type,__res); \
}
#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3)),"S" ((long)(arg4))); \
__syscall_return(type,__res); \
}
#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
type5,arg5) \
type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
: "=a" (__res) \
: "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5))); \
__syscall_return(type,__res); \
}
#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \
type5,arg5,type6,arg6) \
type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5,type6 arg6) \
{ \
long __res; \
__asm__ volatile ("push %%ebp ; movl %%eax,%%ebp ; movl %1,%%eax ; int $0x80 ; pop %%ebp" \
: "=a" (__res) \
: "i" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
"d" ((long)(arg3)),"S" ((long)(arg4)),"D" ((long)(arg5)), \
"0" ((long)(arg6))); \
__syscall_return(type,__res); \
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment