📄 rtems_glue.c
字号:
/* * $Id: rtems_glue.c,v 1.29.2.2 2003/09/15 14:07:57 jennifer Exp $ */#define RTEMS_FAST_MUTEX#ifdef RTEMS_FAST_MUTEX#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__ 1#endif#include <string.h>#include <stdarg.h>#include <stdio.h>#include <errno.h>#include <rtems.h>#include <rtems/libio.h>#include <rtems/error.h>#include <rtems/rtems_bsdnet.h>#include <sys/types.h>#include <sys/param.h>#include <sys/domain.h>#include <sys/mbuf.h>#include <sys/socketvar.h>#include <sys/socket.h>#include <sys/sockio.h>#include <sys/callout.h>#include <sys/proc.h>#include <sys/ioctl.h>#include <net/if.h>#include <net/route.h>#include <netinet/in.h>#include <vm/vm.h>#include <arpa/inet.h>#include <net/netisr.h>#include <net/route.h>/* * Sysctl init all. */void sysctl_register_all(void *arg);/* * Memory allocation */static int nmbuf = (64 * 1024) / MSIZE; int nmbclusters = (128 * 1024) / MCLBYTES;/* * Socket buffering parameters */unsigned long sb_efficiency = 8;/* * Network task synchronization */static rtems_id networkSemaphore;#ifdef RTEMS_FAST_MUTEXSemaphore_Control *the_networkSemaphore;#endifstatic rtems_id networkDaemonTid;static rtems_unsigned32 networkDaemonPriority;static void networkDaemon (void *task_argument);/* * Network timing */int rtems_bsdnet_ticks_per_second;int rtems_bsdnet_microseconds_per_tick;/* * Callout processing */static rtems_interval ticksWhenCalloutsLastChecked;static struct callout *callfree, calltodo;/* * FreeBSD variables */int nfs_diskless_valid;/* * BOOTP values */struct in_addr rtems_bsdnet_log_host_address = {0};struct in_addr rtems_bsdnet_bootp_server_address = {0};char *rtems_bsdnet_bootp_boot_file_name = 0;char *rtems_bsdnet_bootp_server_name = 0;char *rtems_bsdnet_domain_name = 0;char *rtems_bsdnet_bootp_cmdline = 0;struct in_addr rtems_bsdnet_nameserver[sizeof rtems_bsdnet_config.name_server / sizeof rtems_bsdnet_config.name_server[0]];int rtems_bsdnet_nameserver_count = 0;struct in_addr rtems_bsdnet_ntpserver[sizeof rtems_bsdnet_config.ntp_server / sizeof rtems_bsdnet_config.ntp_server[0]];int rtems_bsdnet_ntpserver_count = 0;long rtems_bsdnet_timeoffset = 0;/* * Perform FreeBSD memory allocation. * FIXME: This should be modified to keep memory allocation statistics. */#undef malloc#undef freeextern void *malloc (size_t);extern void free (void *);void *rtems_bsdnet_malloc (unsigned long size, int type, int flags){ void *p; int try = 0; for (;;) { p = malloc (size); if (p || (flags & M_NOWAIT)) return p; rtems_bsdnet_semaphore_release (); if (++try >= 30) { rtems_bsdnet_malloc_starvation(); try = 0; } rtems_task_wake_after (rtems_bsdnet_ticks_per_second); rtems_bsdnet_semaphore_obtain (); }}/* * Free FreeBSD memory * FIXME: This should be modified to keep memory allocation statistics. */voidrtems_bsdnet_free (void *addr, int type){ free (addr);}/* * Do the initializations required by the BSD code */static intbsd_init (void){ int i; char *p; /* * Set up mbuf cluster data strutures */ p = malloc ((nmbclusters*MCLBYTES)+MCLBYTES-1); if (p == NULL) { printf ("Can't get network cluster memory.\n"); return -1; } p = (char *)(((unsigned long)p + (MCLBYTES-1)) & ~(MCLBYTES-1)); mbutl = (struct mbuf *)p; for (i = 0; i < nmbclusters; i++) { ((union mcluster *)p)->mcl_next = mclfree; mclfree = (union mcluster *)p; p += MCLBYTES; mbstat.m_clfree++; } mbstat.m_clusters = nmbclusters; mclrefcnt = malloc (nmbclusters); if (mclrefcnt == NULL) { printf ("Can't get mbuf cluster reference counts memory.\n"); return -1; } memset (mclrefcnt, '\0', nmbclusters); /* * Set up mbuf data structures */ p = malloc(nmbuf * MSIZE + MSIZE - 1); p = (char *)(((unsigned int)p + MSIZE - 1) & ~(MSIZE - 1)); if (p == NULL) { printf ("Can't get network memory.\n"); return -1; } for (i = 0; i < nmbuf; i++) { ((struct mbuf *)p)->m_next = mmbfree; mmbfree = (struct mbuf *)p; p += MSIZE; } mbstat.m_mbufs = nmbuf; mbstat.m_mtypes[MT_FREE] = nmbuf; /* * Set up domains */ { extern struct domain routedomain; extern struct domain inetdomain; routedomain.dom_next = domains; domains = &routedomain; inetdomain.dom_next = domains; domains = &inetdomain; domaininit (NULL); } /* * Setup the sysctl, normally done by a SYSINIT call. */ sysctl_register_all(0); /* * Set up interfaces */ ifinit (NULL); return 0;}/* * Initialize and start network operations */static intrtems_bsdnet_initialize (void){ rtems_status_code sc; /* * Set the priority of all network tasks */ if (rtems_bsdnet_config.network_task_priority == 0) networkDaemonPriority = 100; else networkDaemonPriority = rtems_bsdnet_config.network_task_priority; /* * Set the memory allocation limits */ if (rtems_bsdnet_config.mbuf_bytecount) nmbuf = rtems_bsdnet_config.mbuf_bytecount / MSIZE; if (rtems_bsdnet_config.mbuf_cluster_bytecount) nmbclusters = rtems_bsdnet_config.mbuf_cluster_bytecount / MCLBYTES; /* * Create the task-synchronization semaphore */ sc = rtems_semaphore_create (rtems_build_name('B', 'S', 'D', 'n'), 0, RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL, 0, &networkSemaphore); if (sc != RTEMS_SUCCESSFUL) { printf ("Can't create network seamphore: `%s'\n", rtems_status_text (sc)); return -1; }#ifdef RTEMS_FAST_MUTEX { Objects_Locations location; the_networkSemaphore = _Semaphore_Get( networkSemaphore, &location ); _Thread_Enable_dispatch(); }#endif /* * Compute clock tick conversion factors */ rtems_clock_get (RTEMS_CLOCK_GET_TICKS_PER_SECOND, &rtems_bsdnet_ticks_per_second); if (rtems_bsdnet_ticks_per_second <= 0) rtems_bsdnet_ticks_per_second = 1; rtems_bsdnet_microseconds_per_tick = 1000000 / rtems_bsdnet_ticks_per_second; /* * Ensure that `seconds' is greater than 0 */ while (rtems_bsdnet_seconds_since_boot() == 0) rtems_task_wake_after(1); /* * Set up BSD-style sockets */ if (bsd_init () < 0) return -1; /* * Start network daemon */ networkDaemonTid = rtems_bsdnet_newproc ("ntwk", 4096, networkDaemon, NULL); /* * Let other network tasks begin */ rtems_bsdnet_semaphore_release (); return 0;}/* * Obtain network mutex */voidrtems_bsdnet_semaphore_obtain (void){#ifdef RTEMS_FAST_MUTEX ISR_Level level; _ISR_Disable (level); _CORE_mutex_Seize ( &the_networkSemaphore->Core_control.mutex, networkSemaphore, 1, /* wait */ 0, /* forever */ level ); if (_Thread_Executing->Wait.return_code) rtems_panic ("Can't obtain network semaphore\n");#else rtems_status_code sc; sc = rtems_semaphore_obtain (networkSemaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT); if (sc != RTEMS_SUCCESSFUL) rtems_panic ("Can't obtain network semaphore: `%s'\n", rtems_status_text (sc));#endif}/* * Release network mutex */voidrtems_bsdnet_semaphore_release (void){#ifdef RTEMS_FAST_MUTEX int i; _Thread_Disable_dispatch(); i = _CORE_mutex_Surrender ( &the_networkSemaphore->Core_control.mutex, networkSemaphore, NULL ); _Thread_Enable_dispatch(); if (i) rtems_panic ("Can't release network semaphore\n");#else rtems_status_code sc; sc = rtems_semaphore_release (networkSemaphore); if (sc != RTEMS_SUCCESSFUL) rtems_panic ("Can't release network semaphore: `%s'\n", rtems_status_text (sc));#endif}/* * Wait for something to happen to a socket buffer */intsbwait(sb) struct sockbuf *sb;{ rtems_event_set events; rtems_id tid; rtems_status_code sc; /* * Soak up any pending events. * The sleep/wakeup synchronization in the FreeBSD * kernel has no memory. */ rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events); /* * Set this task as the target of the wakeup operation. */ rtems_task_ident (RTEMS_SELF, 0, &tid); sb->sb_sel.si_pid = tid; /* * Show that socket is waiting */ sb->sb_flags |= SB_WAIT; /* * Release the network semaphore. */ rtems_bsdnet_semaphore_release (); /* * Wait for the wakeup event. */ sc = rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, sb->sb_timeo, &events); /* * Reobtain the network semaphore. */ rtems_bsdnet_semaphore_obtain (); /* * Return the status of the wait. */ switch (sc) { case RTEMS_SUCCESSFUL: return 0; case RTEMS_TIMEOUT: return EWOULDBLOCK; default: return ENXIO; }}/* * Wake up the task waiting on a socket buffer. */voidsowakeup(so, sb) register struct socket *so; register struct sockbuf *sb;{ if (sb->sb_flags & SB_WAIT) { sb->sb_flags &= ~SB_WAIT; rtems_event_send (sb->sb_sel.si_pid, SBWAIT_EVENT); } if (sb->sb_wakeup) { (*sb->sb_wakeup) (so, sb->sb_wakeuparg); }}/* * For now, a socket can be used by only one task at a time. */intsb_lock(sb) register struct sockbuf *sb;{ rtems_panic ("Socket buffer is already in use."); return 0;}voidwakeup (void *p){ rtems_panic ("Wakeup called");}/* * Wait for a connection/disconnection event. */intsoconnsleep (struct socket *so){ rtems_event_set events; rtems_id tid; rtems_status_code sc; /* * Soak up any pending events. * The sleep/wakeup synchronization in the FreeBSD * kernel has no memory. */ rtems_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events); /* * Set this task as the target of the wakeup operation. */ if (so->so_pgid) rtems_panic ("Another task is already sleeping on that socket"); rtems_task_ident (RTEMS_SELF, 0, &tid); so->so_pgid = tid; /* * Wait for the wakeup event. */ sc = rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, so->so_rcv.sb_timeo, &events); /* * Relinquish ownership of the socket. */ so->so_pgid = 0; switch (sc) { case RTEMS_SUCCESSFUL: return 0; case RTEMS_TIMEOUT: return EWOULDBLOCK; default: return ENXIO; }}/* * Wake up a task waiting for a connection/disconnection to complete. */voidsoconnwakeup (struct socket *so){ if (so->so_pgid) rtems_event_send (so->so_pgid, SOSLEEP_EVENT);}/* * Send an event to the network daemon. * This corresponds to sending a software interrupt in the BSD kernel. */voidrtems_bsdnet_schednetisr (int n){ rtems_event_send (networkDaemonTid, 1 << n);}/* * The network daemon * This provides a context to run BSD software interrupts */static voidnetworkDaemon (void *task_argument){ rtems_status_code sc; rtems_event_set events; rtems_interval now; int ticksPassed; unsigned32 timeout; struct callout *c; for (;;) { c = calltodo.c_next; if (c) timeout = c->c_time; else timeout = RTEMS_NO_TIMEOUT; sc = rtems_bsdnet_event_receive (NETISR_EVENTS, RTEMS_EVENT_ANY | RTEMS_WAIT, timeout, &events); if ( sc == RTEMS_SUCCESSFUL ) { if (events & NETISR_IP_EVENT) ipintr (); if (events & NETISR_ARP_EVENT) arpintr (); } rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now); ticksPassed = now - ticksWhenCalloutsLastChecked; if (ticksPassed != 0) { ticksWhenCalloutsLastChecked = now; c = calltodo.c_next; if (c) { c->c_time -= ticksPassed; while ((c = calltodo.c_next) != NULL && c->c_time <= 0) { void *arg; void (*func) (void *); func = c->c_func; arg = c->c_arg; calltodo.c_next = c->c_next; c->c_next = callfree; callfree = c; (*func)(arg); } } } }}/* * Structure passed to task-start stub */struct newtask { void (*entry)(void *); void *arg;};/* * Task-start stub */static voidtaskEntry (rtems_task_argument arg){ struct newtask t; /* * Pick up task information and free * the memory allocated to pass the * information to this task. */ t = *(struct newtask *)arg; free ((struct newtask *)arg); /* * Enter the competition for the network semaphore */ rtems_bsdnet_semaphore_obtain (); /* * Enter the task */ (*t.entry)(t.arg); rtems_panic ("Network task returned!\n");}/* * Start a network task */rtems_idrtems_bsdnet_newproc (char *name, int stacksize, void(*entry)(void *), void *arg){ struct newtask *t; char nm[4]; rtems_id tid; rtems_status_code sc; strncpy (nm, name, 4); sc = rtems_task_create (rtems_build_name(nm[0], nm[1], nm[2], nm[3]), networkDaemonPriority, stacksize, RTEMS_PREEMPT|RTEMS_NO_TIMESLICE|RTEMS_NO_ASR|RTEMS_INTERRUPT_LEVEL(0), RTEMS_NO_FLOATING_POINT|RTEMS_LOCAL, &tid); if (sc != RTEMS_SUCCESSFUL) rtems_panic ("Can't create network daemon `%s': `%s'\n", name, rtems_status_text (sc)); /* * Set up task arguments */ t = malloc (sizeof *t); t->entry = entry;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -