Commit 2801106b authored by Aurelio Colosimo's avatar Aurelio Colosimo

code fromt ptp-proposal version 56d97349

code was pruned from specific "ptp-proposal" protocol and the
skeleton of IEEE-1588 states was made. Next step is to insert,
step by step, the structs defined in ptpd. Still something needs
to be removed or renamed, but this should be a fair starting point.
parents
*.map*
*.o
*.a
pproto.bin
*.patch
This diff is collapsed.
This diff is collapsed.
#!/bin/sh
# This trivially compiles all known-good configurations
function build_one () {
make -s clean
echo "####################"
echo "Build for " "$1"
make -s -k $2
test -f pproto.o && size pproto.o
test -f pproto && size pproto
}
function build_diags () {
build_one "arch \"$ARCH\", ext \"$PROTO_EXT\", no diag"
build_one "arch \"$ARCH\", ext \"$PROTO_EXT\", mini diag" HAS_DIAG=y
build_one "arch \"$ARCH\", ext \"$PROTO_EXT\", full diag" HAS_FULL_DIAG=y
}
function build_ext () {
unset PROTO_EXT
build_diags
#export PROTO_EXT=one
#build_diags
}
for var in HAS_DIAG HAS_FULL_DIAG CROSS_COMPILE ARCH; do
unset $var
done
# Build for default ARCH first
unset ARCH
build_ext
# Finally, loop over all archs, using our local names for compilers
PREFIX_bare_linux=""
PREFIX_spec="/opt/gcc-lm32/bin/lm32-elf-"
for a in bare-linux spec; do
export ARCH=$a
ARCH_=""
eval export CROSS_COMPILE="\${PREFIX_$(echo $ARCH | sed 's/-/_/g')}"
build_ext
done
#
# Alessandro Rubini for CERN, 2011 -- public domain
#
# classic cross-compilation tool-set
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
# Instead of repeating "proto-daemon" over and over, bless it TARGET
TARGET = pproto
# The main target is the big object file.
all: $(TARGET).o
# CFLAGS to use. Both this Makefile (later) and app-makefile may grow CFLAGS
CFLAGS += -Wall -O2 -ggdb -Iinclude
# to avoid ifdef as much as possible, I use the kernel trick for OBJ variables
OBJ-y := state-machine.o
# include diagnostic objects
include diag/Makefile
# proto-standard is always included
include proto-standard/Makefile
# including the extension Makefile, if an extension is there
ifdef PROTO_EXT
include proto-ext-$(PROTO_EXT)/Makefile
endif
# Include arch code, the default is hosted GNU/Linux stuff
# we need this -I so <arch/endianness.h> can be found
ARCH ?= gnu-linux
CFLAGS += -Iarch-$(ARCH)/include
include arch-$(ARCH)/Makefile
# And this is the rule to build our target.o file. The architecture may
# build more stuff. Please note that ./MAKEALL looks for $(TARGET)
# (i.e., the ELF which is either the output or the input to objcopy -O binary)
#
# The object only depends on OBJ-y because each subdirs added needed
# libraries: see proto-standard/Makefile as an example.
$(TARGET).o: $(OBJ-y)
$(LD) -Map $(TARGET).map1 -r -o $@ $(OBJ-y) $(LIBS)
# Finally, "make clean" is expected to work
clean:
rm -f $$(find . -name '*.[oa]') *.bin $(TARGET) *~ $(TARGET).map*
# Alessandro Rubini for CERN, 2011 -- public domain
CFLAGS += -ffreestanding -Os
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-io.o \
$A/syscalls.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 -- public domain
*/
#include <pproto/pproto.h>
#include "bare-linux.h"
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 pp_get_stamp(uint32_t *sptr)
{
*sptr = htonl(sys_time(0));
}
/* 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)
{
/* from u-boot-1.1.2 */
char *xs = (char *) s;
while (count--)
*xs++ = c;
return s;
}
void *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;
}
/*
* 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);
extern int bare_send_packet(struct pp_instance *ppi, void *pkt, int len);
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 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));
OUTPUT_FORMAT("elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_pproto_start)
SECTIONS
{
. = 0x10000000; /* A random address, non-standard by choice*/
_pproto_start = .;
.text : {
*(.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 <pproto/pproto.h>
#include "bare-linux.h"
/* Receive and send is trivial */
int bare_recv_packet(struct pp_instance *ppi, void *pkt, int len)
{
return sys_recv(ppi->ch.fd, pkt, len, 0);
}
int bare_send_packet(struct pp_instance *ppi, void *pkt, int len)
{
return sys_send(ppi->ch.fd, pkt, len, 0);
}
int pp_recv_packet(struct pp_instance *ppi, void *pkt, int len)
__attribute__((alias("bare_recv_packet")));
int pp_send_packet(struct pp_instance *ppi, void *pkt, int len)
__attribute__((alias("bare_send_packet")));
#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_PROTO_NR);
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(ppi->ch.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_PROTO_NR);
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", "");
}
ppi->ch.fd = sock;
return 0;
}
/*
* 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 <pproto/pproto.h>
#include "bare-linux.h"
extern int __bss_start, __bss_end;
void pproto_clear_bss(void)
{
int *ptr;
for (ptr = &__bss_start; ptr < &__bss_end; ptr++)
*ptr = 0;
}
static struct pp_instance ppi_static;
void pproto_main(void)
{
struct pp_instance *ppi = &ppi_static; /* no malloc, one instance */
pp_puts("bare: starting. Compiled on " __DATE__ "\n");
if (bare_open_ch(ppi, "eth0")) {
pp_diag_error(ppi, bare_errno);
pp_diag_fatal(ppi, "open_ch", "");
}
pp_open_instance(ppi,0);
bare_main_loop(ppi);
}
/*
* A stupid crt0.S for "freestanding" stuff on gnu/linux
* Alessandro Rubini for CERN, 2011 -- GNU GPL v2 or later
*/
.section .boot, "ax"
.extern pproto_main
call pproto_clear_bss /* In C, lazy me */
call pproto_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
#endif /* __ARCH_H__ */
/*
* Alessandro Rubini for CERN, 2011 -- GNU LGPL v2.1 or later
*/
/*
* This is the main loop for "freestanding" stuff under Linux.
*/
#include <pproto/pproto.h>
#include "bare-linux.h"
/* Define other hackish stuff */
typedef struct {unsigned long bits[1024/32];} bare_fd_set;
#define FD_ZERO(p) memset(p, 0, sizeof(p))
#define FD_SET(bit, p) ((p)->bits[0] |= (1 << (bit)))
struct bare_timeval {unsigned long tv_sec; unsigned long tv_usec;};
#define NULL 0
void bare_main_loop(struct pp_instance *ppi)
{
int delay_ms;
/*
* 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) {
bare_fd_set set;
int i;
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(ppi->ch.fd, &set);
i = sys_select(ppi->ch.fd + 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
*/
i = bare_recv_packet(ppi, packet, sizeof(packet));
/* FIXME
if (i < sizeof(struct pp_packet))
goto again;
*/
/* Warning: PP_PROTO_NR is endian-agnostic by design */
if ( ((struct bare_ethhdr *)packet)->h_proto
!= htons(PP_PROTO_NR))
goto again;
delay_ms = pp_state_machine(ppi, packet, i);
}
}
/*
* Alessandro Rubini for CERN, 2011 -- public domain
*/
#include <asm/unistd.h>
#include <pproto/pproto.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)
/*
* 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);
}
/* 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);
}
/*
* 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); \
}