aboutsummaryrefslogtreecommitdiff
path: root/clients/net-snk/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'clients/net-snk/kernel')
-rw-r--r--clients/net-snk/kernel/Makefile43
-rw-r--r--clients/net-snk/kernel/crt0.c74
-rw-r--r--clients/net-snk/kernel/driver/Makefile40
-rw-r--r--clients/net-snk/kernel/driver/net/Makefile38
-rw-r--r--clients/net-snk/kernel/driver/net/netmodule.c138
-rw-r--r--clients/net-snk/kernel/driver/net_support.c534
-rw-r--r--clients/net-snk/kernel/endian.c30
-rw-r--r--clients/net-snk/kernel/entry.S167
-rw-r--r--clients/net-snk/kernel/init.c175
-rw-r--r--clients/net-snk/kernel/lowmem.S186
-rw-r--r--clients/net-snk/kernel/systemcall.c171
-rw-r--r--clients/net-snk/kernel/timer.c67
12 files changed, 1663 insertions, 0 deletions
diff --git a/clients/net-snk/kernel/Makefile b/clients/net-snk/kernel/Makefile
new file mode 100644
index 0000000..73e8127
--- /dev/null
+++ b/clients/net-snk/kernel/Makefile
@@ -0,0 +1,43 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+ifndef TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS = entry.o init.o systemcall.o lowmem.o crt0.o endian.o timer.o
+OBJDIRS = driver/net.o
+
+all: kernel.o
+
+driver/net.o:
+ make -C driver
+
+kernel.o: subdirs $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJDIRS) $(OBJS) -o $@ -r
+
+subdirs:
+ for dir in $(dir $(OBJDIRS)); do \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \
+ done
+
+clean:
+ $(RM) -f *.o *.a *.i
+ @for dir in $(dir $(OBJDIRS)); do \
+ $(CLEAN); \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \
+ done
+
+include $(TOP)/make.depend
diff --git a/clients/net-snk/kernel/crt0.c b/clients/net-snk/kernel/crt0.c
new file mode 100644
index 0000000..e3c443b
--- /dev/null
+++ b/clients/net-snk/kernel/crt0.c
@@ -0,0 +1,74 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+extern int main (int, char**);
+extern int callback (int, char **);
+
+#define MAX_ARGV 10
+int
+gen_argv(const char *arg_string, int len, char* argv[])
+{
+ const char *str, *str_end, *arg_string_end = arg_string + len;
+ int i;
+
+ str = arg_string;
+ for (i = 0; i < MAX_ARGV; i++)
+ {
+ str_end = str;
+
+ while((*str_end++ != ' ') && (str_end <= arg_string_end));
+
+ argv[i] = malloc(str_end-str);
+
+ memcpy (argv[i], str, str_end-str-1);
+ argv[i][str_end-str-1] = '\0';
+ str = str_end-1;
+ while(*(++str) == ' ');
+ if (str >= arg_string_end)
+ break;
+ }
+ return i+1;
+}
+
+
+
+int
+_start(char * arg_string, long len)
+{
+ int rc;
+ int argc;
+ char* argv[MAX_ARGV];
+
+ argc = gen_argv(arg_string, len, argv);
+
+ rc = main(argc, argv);
+
+ return rc;
+}
+
+/*
+ * Takes a Forth representation of a string and generates an argument array,
+ * then calls callback().
+ */
+unsigned long
+callback_entry(void *base, unsigned long len) {
+ char *argv[MAX_ARGV];
+ int argc;
+
+ argc = gen_argv(base, len, argv);
+
+ return (callback(argc, argv));
+}
+
diff --git a/clients/net-snk/kernel/driver/Makefile b/clients/net-snk/kernel/driver/Makefile
new file mode 100644
index 0000000..6c2c8d4
--- /dev/null
+++ b/clients/net-snk/kernel/driver/Makefile
@@ -0,0 +1,40 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+ifndef TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS = net_support.o
+OBJDIRS = net/net_driver.o
+
+all: net.o
+
+net.o: subdirs $(OBJS)
+ $(LD) $(LDFLAGS) $(OBJDIRS) $(OBJS) -o $@ -r
+
+subdirs:
+ for dir in $(dir $(OBJDIRS)); do \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir || exit 1; \
+ done
+
+clean:
+ $(RM) -f *.o *.a *.i
+ @for dir in $(dir $(OBJDIRS)); do \
+ $(CLEAN); \
+ $(MAKE) -C $$dir DIRECTORY=$(DIRECTORY)$$dir clean; \
+ done
+
+-include $(TOP)/make.depend
diff --git a/clients/net-snk/kernel/driver/net/Makefile b/clients/net-snk/kernel/driver/net/Makefile
new file mode 100644
index 0000000..95efa2b
--- /dev/null
+++ b/clients/net-snk/kernel/driver/net/Makefile
@@ -0,0 +1,38 @@
+# *****************************************************************************
+# * Copyright (c) 2004, 2007 IBM Corporation
+# * All rights reserved.
+# * This program and the accompanying materials
+# * are made available under the terms of the BSD License
+# * which accompanies this distribution, and is available at
+# * http://www.opensource.org/licenses/bsd-license.php
+# *
+# * Contributors:
+# * IBM Corporation - initial implementation
+# ****************************************************************************/
+
+
+ifndef TOP
+ TOP = $(shell while ! test -e make.rules; do cd .. ; done; pwd)
+ export TOP
+endif
+include $(TOP)/make.rules
+
+OBJS = netmodule.o
+
+all: net_driver.o
+
+net_driver.o: $(OBJS)
+ $(LD) $(LDFLAGS) $^ -o $@ -r
+
+clean:
+ $(RM) -f *.o *.a *.i
+
+include $(TOP)/make.depend
+
+#depend :
+# @echo "create .depend file"
+# @touch .depend ; \
+# makedepend -v -f.depend -- $(CFLAGS) -- $(OBJS:.o=.c) 2> /dev/null
+
+#mrproper : clean
+# rm -rf .depend
diff --git a/clients/net-snk/kernel/driver/net/netmodule.c b/clients/net-snk/kernel/driver/net/netmodule.c
new file mode 100644
index 0000000..e81628e
--- /dev/null
+++ b/clients/net-snk/kernel/driver/net/netmodule.c
@@ -0,0 +1,138 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <netdriver_int.h>
+#include <kernel.h>
+#include <of.h>
+#include <rtas.h>
+#include <cpu.h>
+
+# define MODULE_ADDR 0xF800000
+
+unsigned int read_io(void *, size_t);
+int write_io(void *, unsigned int, size_t);
+void translate_address(unsigned long *);
+
+static snk_kernel_t snk_kernel_interface = {
+ .version = 1,
+ .print = printk,
+ .us_delay = udelay,
+ .ms_delay = mdelay,
+ .pci_config_read = rtas_pci_config_read,
+ .pci_config_write = rtas_pci_config_write,
+ .k_malloc_aligned = malloc_aligned,
+ .k_romfs_lookup = romfs_lookup,
+ .translate_addr = translate_address
+};
+
+static snk_module_t *snk_module_interface;
+
+typedef snk_module_t *(*module_init_t) (snk_kernel_t *, pci_config_t *);
+
+/* Load module and call init code.
+ Init code will check, if module is responsible for device.
+ Returns -1, if not responsible for device, 0 otherwise.
+*/
+
+int
+load_module(const char *name, pci_config_t * pciconf)
+{
+ int len;
+ void *addr;
+ module_init_t module_init;
+
+ /* Read module from FLASH */
+ len = romfs_lookup(name, &addr);
+
+ if (len <= 0) {
+ return -1;
+ }
+ /* Copy image from flash to RAM
+ * FIXME fix address 8MB
+ */
+
+ memcpy((void *) MODULE_ADDR, addr, len);
+
+ flush_cache((void *) MODULE_ADDR, len);
+
+ /* Module starts with opd structure of the module_init
+ * function.
+ */
+ module_init = (module_init_t) MODULE_ADDR;
+ snk_module_interface = module_init(&snk_kernel_interface, pciconf);
+ if (snk_module_interface == 0)
+ return -1;
+ return 0;
+}
+
+int
+net_init(pci_config_t * pciconf, char *mac_addr)
+{
+ snk_kernel_interface.io_read = read_io;
+ snk_kernel_interface.io_write = write_io;
+
+ if (snk_module_interface->net_init){
+ return snk_module_interface->net_init(pciconf, mac_addr);
+ }
+ else {
+ printk("No net_init function available");
+ return -1;
+ }
+}
+
+int
+net_term(pci_config_t * pciconf)
+{
+ if (snk_module_interface->net_term)
+ return snk_module_interface->net_term(pciconf);
+ else {
+ printk("No net_term function available");
+ return -1;
+ }
+}
+
+
+int
+net_xmit(pci_config_t * pciconf, char *buffer, int len)
+{
+ if (snk_module_interface->net_xmit)
+ return snk_module_interface->net_xmit(pciconf, buffer, len);
+ else {
+ printk("No net_xmit function available");
+ return -1;
+ }
+}
+
+int
+net_receive(pci_config_t * pciconf, char *buffer, int len)
+{
+ if (snk_module_interface->net_receive)
+ return snk_module_interface->net_receive(pciconf, buffer, len);
+ else {
+ printk("No net_receive function available");
+ return -1;
+ }
+}
+
+int
+net_ioctl(pci_config_t * pciconf, int request, void* data)
+{
+ snk_kernel_interface.io_read = read_io;
+ snk_kernel_interface.io_write = write_io;
+
+ if (snk_module_interface->net_ioctl)
+ return snk_module_interface->net_ioctl(pciconf, request, data);
+ else {
+ printk("No net_ioctl function available");
+ return -1;
+ }
+}
diff --git a/clients/net-snk/kernel/driver/net_support.c b/clients/net-snk/kernel/driver/net_support.c
new file mode 100644
index 0000000..983374a
--- /dev/null
+++ b/clients/net-snk/kernel/driver/net_support.c
@@ -0,0 +1,534 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <pci.h>
+#include <net.h>
+#include <netdriver_int.h>
+#include <kernel.h>
+#include <rtas.h>
+#include <stdlib.h>
+#include <of.h>
+#include <types.h>
+
+extern int net_init(pci_config_t * pciconf, char *mac_addr);
+extern int net_term(pci_config_t * pciconf);
+extern int net_xmit(pci_config_t * pciconf, char *buffer, int len);
+extern int net_receive(pci_config_t * pciconf, char *buffer, int len);
+extern int net_ioctl(pci_config_t * conf, int request, void *data);
+extern int load_module(const char *, pci_config_t *);
+
+
+static char *mod_names[] = {
+ "net_e1000",
+ "net_bcm",
+ "net_nx203x",
+ "net_mcmal",
+ "net_spider",
+ 0
+};
+
+net_driver_t *
+find_net_driver(pci_config_t pci_conf)
+{
+ int rc;
+ int i = 0;
+ static net_driver_t module_net_driver;
+
+ /* Loop over module name */
+ while (mod_names[i]) {
+ rc = load_module(mod_names[i], &pci_conf);
+ if (rc == 0) {
+ module_net_driver.net_init = net_init;
+ module_net_driver.net_term = net_term;
+ module_net_driver.net_transmit = net_xmit;
+ module_net_driver.net_receive = net_receive;
+ module_net_driver.net_ioctl = net_ioctl;
+ return &module_net_driver;
+ }
+ i++;
+ }
+ return 0;
+}
+
+static phandle_t
+get_boot_device(void)
+{
+ static int nameprinted = 1;
+ char buf[1024];
+ phandle_t dev = of_finddevice("/chosen");
+
+ if (dev == -1) {
+ printk("/chosen not found\n");
+ dev = of_finddevice("/aliases");
+ if (dev == -1)
+ return dev;
+ printk("/aliases found, net=%s\n", buf);
+ of_getprop(dev, "net", buf, 1024);
+ } else
+ of_getprop(dev, "bootpath", buf, 1024);
+
+// FIXME: This printk is nice add to "Reading MAC from device" from netboot
+// However it is too hackish having "kernel" code finish the application
+// output line
+ if (!nameprinted++)
+ printk("%s: ", buf);
+
+ return of_finddevice(buf);
+}
+
+static void
+get_mac(char *mac)
+{
+ phandle_t net = get_boot_device();
+
+ if (net == -1)
+ return;
+
+ of_getprop(net, "local-mac-address", mac, 6);
+}
+
+void translate_address_dev(uint64_t *, phandle_t);
+
+/**
+ * get_puid walks up in the device tree until it finds a parent
+ * node without a reg property. get_puid is assuming that if the
+ * parent node has no reg property it has found the pci host bridge
+ *
+ * this is not the correct way to find PHBs but it seems to work
+ * for all our systems
+ *
+ * @param node the device for which to find the puid
+ *
+ * @return the puid or 0
+ */
+uint64_t
+get_puid(phandle_t node)
+{
+ uint64_t puid = 0;
+ uint64_t tmp = 0;
+ phandle_t curr_node = of_parent(node);
+ if (!curr_node)
+ /* no parent found */
+ return 0;
+ for (;;) {
+ puid = tmp;
+ if (of_getprop(curr_node, "reg", &tmp, 8) < 8) {
+ /* if the found PHB is not directly under
+ * root we need to translate the found address */
+ translate_address_dev(&puid, node);
+ return puid;
+ }
+ curr_node = of_parent(curr_node);
+ if (!curr_node)
+ return 0;
+ }
+ return 0;
+}
+
+/* Fill in the pci config structure from the device tree */
+int
+set_pci_config(pci_config_t * pci_config)
+{
+ unsigned char buf[1024];
+ int len, bar_nr;
+ unsigned int *assigned_ptr;
+ phandle_t net = get_boot_device();
+
+ if (net == -1)
+ return -1;
+ of_getprop(net, "vendor-id", &pci_config->vendor_id, 4);
+ of_getprop(net, "device-id", &pci_config->device_id, 4);
+ of_getprop(net, "revision-id", &pci_config->revision_id, 4);
+ of_getprop(net, "class-code", &pci_config->class_code, 4);
+ of_getprop(net, "interrupts", &pci_config->interrupt_line, 4);
+
+ len = of_getprop(net, "assigned-addresses", buf, 400);
+ if (len <= 0)
+ return -1;
+ assigned_ptr = (unsigned int *) &buf[0];
+ pci_config->bus = (assigned_ptr[0] & 0x00ff0000) >> 16;
+ pci_config->devfn = (assigned_ptr[0] & 0x0000ff00) >> 8;
+
+ while (len > 0) {
+ /* Fixme 64 bit bars */
+ bar_nr = ((assigned_ptr[0] & 0xff) - 0x10) / 4;
+ pci_config->bars[bar_nr].type =
+ (assigned_ptr[0] & 0x0f000000) >> 24;
+ pci_config->bars[bar_nr].addr = assigned_ptr[2];
+ pci_config->bars[bar_nr].size = assigned_ptr[4];
+ assigned_ptr += 5;
+ len -= 5 * sizeof(int);
+ }
+
+ pci_config->puid = get_puid(net);
+
+ return 0;
+}
+
+
+typedef struct {
+ pci_config_t pci_conf;
+ net_driver_t net_driv;
+
+ char mac_addr[6];
+ int running;
+} net_status_t;
+
+static net_status_t net_status;
+
+int
+init_net_driver()
+{
+ int result = 0;
+ net_driver_t *net_driver;
+
+ /* Find net device and initialize pci config */
+ if (set_pci_config(&net_status.pci_conf) == -1) {
+ printk(" No net device found \n");
+ return -1;
+ }
+
+ /* Get mac address from device tree */
+ get_mac(net_status.mac_addr);
+
+ /* Find net device driver */
+
+ net_driver = find_net_driver(net_status.pci_conf);
+ if (net_driver == 0) {
+ printk(" No net device driver found \n");
+ return -1;
+ }
+ net_status.net_driv = *net_driver;
+ /* Init net device driver */
+ result = net_status.net_driv.net_init(&net_status.pci_conf,
+ &net_status.mac_addr[0]);
+ if (result == -1) {
+ net_status.running = 0;
+ return -2;
+ } else {
+ net_status.running = 1;
+ }
+ return 0;
+}
+
+
+void
+term_net_driver()
+{
+ if (net_status.running == 1)
+ net_status.net_driv.net_term(&net_status.pci_conf);
+}
+
+
+int
+_socket(int domain, int type, int proto, char *mac_addr)
+{
+ static int first_time = 1;
+ if (first_time) {
+ switch (init_net_driver()) {
+ case -1:
+ return -1;
+ case -2:
+ return -2;
+ default:
+ break;
+ }
+ first_time = 0;
+ }
+
+ memcpy(mac_addr, &net_status.mac_addr[0], 6);
+ return 0;
+}
+
+
+long
+_recv(int fd, void *packet, int packet_len, int flags)
+{
+ return net_status.net_driv.net_receive(&net_status.pci_conf,
+ packet, packet_len);
+}
+
+
+long
+_sendto(int fd, void *packet, int packet_len, int flags,
+ void *sock_addr, int sock_addr_len)
+{
+ return net_status.net_driv.net_transmit(&net_status.pci_conf,
+ packet, packet_len);
+}
+
+long
+_send(int fd, void *packet, int packet_len, int flags)
+{
+ return net_status.net_driv.net_transmit(&net_status.pci_conf,
+ packet, packet_len);
+}
+
+long
+_ioctl(int fd, int request, void *data)
+{
+ net_driver_t *net_driver;
+
+ /* Find net device and initialize pci config */
+ if (set_pci_config(&net_status.pci_conf) == -1) {
+ printk(" No net device found \n");
+ return -1;
+ }
+
+ /* Find net device driver */
+
+ net_driver = find_net_driver(net_status.pci_conf);
+ if (net_driver == 0) {
+ printk(" No net device driver found \n");
+ return -1;
+ }
+ net_status.net_driv = *net_driver;
+
+ return net_status.net_driv.net_ioctl(&net_status.pci_conf,
+ request, data);
+}
+
+
+void *
+malloc_aligned(size_t size, int align)
+{
+ unsigned long p = (unsigned long) malloc(size + align - 1);
+ p = p + align - 1;
+ p = p & ~(align - 1);
+
+ return (void *) p;
+}
+
+#define CONFIG_SPACE 0
+#define IO_SPACE 1
+#define MEM_SPACE 2
+
+#define ASSIGNED_ADDRESS_PROPERTY 0
+#define REG_PROPERTY 1
+
+#define DEBUG_TRANSLATE_ADDRESS 0
+#if DEBUG_TRANSLATE_ADDRESS != 0
+#define DEBUG_TR(str...) printk(str)
+#else
+#define DEBUG_TR(str...)
+#endif
+
+/**
+ * pci_address_type tries to find the type for which a
+ * mapping should be done. This is PCI specific and is done by
+ * looking at the first 32bit of the phys-addr in
+ * assigned-addresses
+ *
+ * @param node the node of the device which requests
+ * translatation
+ * @param address the address which needs to be translated
+ * @param prop_type the type of the property to search in (either REG_PROPERTY or ASSIGNED_ADDRESS_PROPERTY)
+ * @return the corresponding type (config, i/o, mem)
+ */
+static int
+pci_address_type(phandle_t node, uint64_t address, uint8_t prop_type)
+{
+ char *prop_name = "assigned-addresses";
+ if (prop_type == REG_PROPERTY)
+ prop_name = "reg";
+ /* #address-cells */
+ const unsigned int nac = 3; //PCI
+ /* #size-cells */
+ const unsigned int nsc = 2; //PCI
+ /* up to 11 pairs of (phys-addr(3) size(2)) */
+ unsigned char buf[11 * (nac + nsc) * sizeof(int)];
+ unsigned int *assigned_ptr;
+ int result = -1;
+ int len;
+ len = of_getprop(node, prop_name, buf, 11 * (nac + nsc) * sizeof(int));
+ assigned_ptr = (unsigned int *) &buf[0];
+ while (len > 0) {
+ if ((prop_type == REG_PROPERTY)
+ && ((assigned_ptr[0] & 0xFF) != 0)) {
+ //BARs and Expansion ROM must be in assigned-addresses... so in reg
+ // we only look for those without config space offset set...
+ assigned_ptr += (nac + nsc);
+ len -= (nac + nsc) * sizeof(int);
+ continue;
+ }
+ DEBUG_TR("%s %x size %x\n", prop_name, assigned_ptr[2],
+ assigned_ptr[4]);
+ if (address >= assigned_ptr[2]
+ && address <= assigned_ptr[2] + assigned_ptr[4]) {
+ DEBUG_TR("found a match\n");
+ result = (assigned_ptr[0] & 0x03000000) >> 24;
+ break;
+ }
+ assigned_ptr += (nac + nsc);
+ len -= (nac + nsc) * sizeof(int);
+ }
+ /* this can only handle 32bit memory space and should be
+ * removed as soon as translations for 64bit are available */
+ return (result == 3) ? MEM_SPACE : result;
+}
+
+/**
+ * this is a hack which returns the lower 64 bit of any number of cells
+ * all the higher bits will silently discarded
+ * right now this works pretty good as long 64 bit addresses is all we want
+ *
+ * @param addr a pointer to the first address cell
+ * @param nc number of cells addr points to
+ * @return the lower 64 bit to which addr points
+ */
+static uint64_t
+get_dt_address(uint32_t *addr, uint32_t nc)
+{
+ uint64_t result = 0;
+ while (nc--)
+ result = (result << 32) | *(addr++);
+ return result;
+}
+
+/**
+ * this functions tries to find a mapping for the given address
+ * it assumes that if we have #address-cells == 3 that we are trying
+ * to do a PCI translation
+ *
+ * @param addr a pointer to the address that should be translated
+ * if a translation has been found the address will
+ * be modified
+ * @param type this is required for PCI devices to find the
+ * correct translation
+ * @param ranges this is one "range" containing the translation
+ * information (one range = nac + pnac + nsc)
+ * @param nac the OF property #address-cells
+ * @param nsc the OF property #size-cells
+ * @param pnac the OF property #address-cells from the parent node
+ * @return -1 if no translation was possible; else 0
+ */
+static int
+map_one_range(uint64_t *addr, int type, uint32_t *ranges, uint32_t nac,
+ uint32_t nsc, uint32_t pnac)
+{
+ long offset;
+ /* cm - child mapping */
+ /* pm - parent mapping */
+ uint64_t cm, size, pm;
+ /* only check for the type if nac == 3 (PCI) */
+ DEBUG_TR("type %x, nac %x\n", ranges[0], nac);
+ if (((ranges[0] & 0x03000000) >> 24) != type && nac == 3)
+ return -1;
+ /* okay, it is the same type let's see if we find a mapping */
+ size = get_dt_address(ranges + nac + pnac, nsc);
+ if (nac == 3) /* skip type if PCI */
+ cm = get_dt_address(ranges + 1, nac - 1);
+ else
+ cm = get_dt_address(ranges, nac);
+
+ DEBUG_TR("\t\tchild_mapping %lx\n", cm);
+ DEBUG_TR("\t\tsize %lx\n", size);
+ DEBUG_TR("\t\t*address %lx\n", (uint64_t) * addr);
+ if (cm + size <= (uint64_t) * addr || cm > (uint64_t) * addr)
+ /* it is not inside the mapping range */
+ return -1;
+ /* get the offset */
+ offset = *addr - cm;
+ /* and add the offset on the parent mapping */
+ if (pnac == 3) /* skip type if PCI */
+ pm = get_dt_address(ranges + nac + 1, pnac - 1);
+ else
+ pm = get_dt_address(ranges + nac, pnac);
+ DEBUG_TR("\t\tparent_mapping %lx\n", pm);
+ *addr = pm + offset;
+ DEBUG_TR("\t\t*address %lx\n", *addr);
+ return 0;
+}
+
+/**
+ * translate_address_dev tries to translate the device specific address
+ * to a host specific address by walking up in the device tree
+ *
+ * @param address a pointer to a 64 bit value which will be
+ * translated
+ * @param current_node phandle of the device from which the
+ * translation will be started
+ */
+void
+translate_address_dev(uint64_t *addr, phandle_t current_node)
+{
+ unsigned char buf[1024];
+ phandle_t parent;
+ unsigned int pnac;
+ unsigned int nac;
+ unsigned int nsc;
+ int addr_type;
+ int len;
+ unsigned int *ranges;
+ unsigned int one_range;
+ DEBUG_TR("translate address %lx, node: %lx\n", *addr, current_node);
+ of_getprop(current_node, "name", buf, 400);
+ DEBUG_TR("current node: %s\n", buf);
+ addr_type =
+ pci_address_type(current_node, *addr, ASSIGNED_ADDRESS_PROPERTY);
+ if (addr_type == -1) {
+ // check in "reg" property if not found in "assigned-addresses"
+ addr_type = pci_address_type(current_node, *addr, REG_PROPERTY);
+ }
+ DEBUG_TR("address_type %x\n", addr_type);
+ current_node = of_parent(current_node);
+ while (1) {
+ parent = of_parent(current_node);
+ if (!parent) {
+ DEBUG_TR("reached root node...\n");
+ break;
+ }
+ of_getprop(current_node, "#address-cells", &nac, 4);
+ of_getprop(current_node, "#size-cells", &nsc, 4);
+ of_getprop(parent, "#address-cells", &pnac, 4);
+ one_range = nac + pnac + nsc;
+ len = of_getprop(current_node, "ranges", buf, 400);
+ if (len < 0) {
+ DEBUG_TR("no 'ranges' property; not translatable\n");
+ return;
+ }
+ ranges = (unsigned int *) &buf[0];
+ while (len > 0) {
+ if (!map_one_range
+ ((uint64_t *) addr, addr_type, ranges, nac, nsc,
+ pnac))
+ /* after a successful mapping we stop
+ * going through the ranges */
+ break;
+ ranges += one_range;
+ len -= one_range * sizeof(int);
+ }
+ DEBUG_TR("address %lx\n", *addr);
+ of_getprop(current_node, "name", buf, 400);
+ DEBUG_TR("current node: %s\n", buf);
+ DEBUG_TR("\t#address-cells: %x\n", nac);
+ DEBUG_TR("\t#size-cells: %x\n", nsc);
+ of_getprop(parent, "name", buf, 400);
+ DEBUG_TR("parent node: %s\n", buf);
+ DEBUG_TR("\t#address-cells: %x\n", pnac);
+ current_node = parent;
+ }
+}
+
+/**
+ * translate_address tries to translate the device specific address
+ * of the boot device to a host specific address
+ *
+ * @param address a pointer to a 64 bit value which will be
+ * translated
+ */
+void
+translate_address(uint64_t *addr)
+{
+ translate_address_dev(addr, get_boot_device());
+}
diff --git a/clients/net-snk/kernel/endian.c b/clients/net-snk/kernel/endian.c
new file mode 100644
index 0000000..9748778
--- /dev/null
+++ b/clients/net-snk/kernel/endian.c
@@ -0,0 +1,30 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include "endian.h"
+
+inline uint16_t bswap_16 (uint16_t x)
+{
+ return ((x&0xff00) >> 8) | ((x&0xff) << 8);
+}
+
+inline uint32_t bswap_32 (uint32_t x)
+{
+ return bswap_16((x&0xffff0000) >> 16) | (bswap_16(x&0xffff) << 16);
+}
+
+inline uint64_t bswap_64 (uint64_t x)
+{
+ return (unsigned long long) bswap_32((x&0xffffffff00000000ULL) >> 32) |
+ (unsigned long long) bswap_32(x&0xffffffffULL) << 32;
+}
diff --git a/clients/net-snk/kernel/entry.S b/clients/net-snk/kernel/entry.S
new file mode 100644
index 0000000..8db10af
--- /dev/null
+++ b/clients/net-snk/kernel/entry.S
@@ -0,0 +1,167 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#define STACKSIZE 0x100000
+#include <macros.h>
+
+/*
+Function:
+ Input:
+ r3:
+ r4:
+ r5: prom entry
+ Output:
+
+Decription: Main entry point, called from OF
+
+*/
+ .globl _entry
+ .section ".opd","aw"
+ .align 3
+_entry:
+ .quad ._entry,.TOC.@tocbase,0
+ .previous
+ .size main,24
+ .globl ._entry
+._entry:
+ mr r3, r6 # parm 0 passed in r6
+ mr r4, r7 # parm 1 passed in r7
+ mr r6, r1 # save stack pointer
+ mflr r7 # save link register
+ bcl 20,31,over # branch after pointer table
+base:
+ .align 3
+.LCgot: .quad _got-base+0x8000
+.LCstack: .quad _stack+STACKSIZE-0x80-base
+over:
+ mflr r8 # gpr 8 is the base
+ ld r1,.LCstack-base(r8) # load new stack pointer
+ add r1, r1, r8 # add base
+ std r2, 64(r1) # save got
+ std r7, 56(r1) # save link register
+# ld r2, .LCgot-base(r8) # load got pointer
+# add r2, r2, r8 # add base
+ std r6, 0(r1) # save stack pointer
+
+ ld r6, _prom_entry@got(r2)
+ std r5, 0(r6) # Save prom handle
+
+ ld r10, _exit_sp@got(r2) # save stack pointer for exit call
+ std r1, 0(r10)
+
+ bl ._start_kernel # call kernel init code
+
+the_end:
+ ld r4, 56(r1) # Restore link register
+ mtlr r4
+ ld r2, 64(r1) # restore got
+ ld r1, 0(r1)
+
+ blr
+
+/*
+ * Function: _callback_entry
+ * Input: r6 start address of parameter string
+ * r7 length of parameter string.
+ *
+ * Description: If a client application wants to register a callback function,
+ * this function is registered w/ SLOF, not the application's function. SLOF
+ * passes the parameter string in Forth representation in R6 and R7. This
+ * function moves R6 to R3 and R7 to R4 and then calls callback_entry().
+ *
+ */
+ .globl _callback_entry
+ .section ".opd", "aw"
+ .align 3
+_callback_entry:
+ .quad ._callback_entry,.TOC.@tocbase,0
+ .previous
+ .size callback,24
+ .type ._callback_entry, @function
+ .globl ._callback_entry
+._callback_entry:
+ # Save the LR
+ mflr r0
+ std r0, 16(r1)
+
+ # Reserve stack space
+ stdu r1, -32(r1)
+
+ # SLOF passes the parameters in Registers R6 and R7 but the target
+ # wants them in registers R3 and R4
+ mr r3, r6
+ mr r4, r7
+
+ # Branch to the callback_entry function
+ bl .callback_entry
+
+ # Destroy stack frame
+ ld r1, 0(r1)
+
+ # Restore LR
+ ld r0, 16(r1)
+ mtlr r0
+
+ # Return to caller
+ blr
+
+
+ .globl _exit_sp
+_exit_sp: .quad 0
+ .globl _prom_entry
+_prom_entry: .quad 0
+
+ENTRY(_exit)
+ ld r1, _exit_sp@got(r2)
+ ld r1, 0(r1)
+ b the_end
+
+ .globl .undo_exception
+.undo_exception:
+ .globl undo_exception
+undo_exception:
+
+/*
+ unwind stack
+*/
+ ld r3,exception_stack_frame@got(r2)
+ ld r1,0(r3)
+
+ ld r14,0x130(r1)
+ mtctr r14
+
+// restore regs same as in _exception_handler:
+
+ .irp i, 2,3,4,5,6,7,8,9,10,12,13,14,15,16, \
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+ 27, 28, 29, 30, 31
+ ld r\i, 0x30+\i*8 (r1)
+ .endr
+ addi r1, r1, 0x130
+
+// restore regs as in default handler
+
+ ld r0, 0x48(r1)
+ mtsrr0 r0
+ ld r0, 0x50(r1)
+ mtsrr1 r0
+// 20
+ ld r0, 0x38(r1)
+ mtlr r0
+ ld r0, 0x30(r1)
+ ld r11, 0x40(r1)
+// 30
+ addi r1, r1, 0x58
+
+ rfid
+
+ .lcomm _stack,STACKSIZE,16
diff --git a/clients/net-snk/kernel/init.c b/clients/net-snk/kernel/init.c
new file mode 100644
index 0000000..76b35ed
--- /dev/null
+++ b/clients/net-snk/kernel/init.c
@@ -0,0 +1,175 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+#include <of.h>
+#include <rtas.h>
+#include <pci.h>
+#include <kernel.h>
+#include <types.h>
+#include <string.h>
+#include <cpu.h>
+
+/* Application entry point .*/
+extern int _start(unsigned char *arg_string, long len);
+
+unsigned long exception_stack_frame;
+
+ihandle_t fd_array[32];
+pci_config_t pci_device_array[32];
+
+extern uint64_t tb_freq;
+
+void term_net_driver(void);
+
+static int
+init_io()
+{
+ phandle_t chosen = of_finddevice("/chosen");
+
+ if (chosen == -1)
+ return -1;
+
+ of_getprop(chosen, "stdin", &fd_array[0], sizeof(ihandle_t));
+ of_getprop(chosen, "stdout", &fd_array[1], sizeof(ihandle_t));
+
+ if (of_write(fd_array[1], " ", 1) < 0)
+ return -2;
+
+ return 0;
+}
+
+static char save_vector[0x4000];
+extern char _lowmem_start;
+extern char _lowmem_end;
+extern char __client_start;
+extern char __client_end;
+
+static void
+copy_exception_vectors()
+{
+ char *dest;
+ char *src;
+ int len;
+
+ dest = save_vector;
+ src = (char *) 0x200;
+ len = &_lowmem_end - &_lowmem_start;
+ memcpy(dest, src, len);
+
+ dest = (char *) 0x200;
+ src = &_lowmem_start;
+ memcpy(dest, src, len);
+ flush_cache(dest, len);
+}
+
+static void
+restore_exception_vectors()
+{
+ char *dest;
+ char *src;
+ int len;
+
+ dest = (char *) 0x200;
+ src = save_vector;
+ len = &_lowmem_end - &_lowmem_start;
+ memcpy(dest, src, len);
+ flush_cache(dest, len);
+}
+
+static long memory_size;
+
+static void
+checkmemorysize()
+{
+ char buf[255];
+ phandle_t ph;
+ memory_size = 0;
+
+ struct reg {
+ long adr;
+ long size;
+ } reg;
+
+ ph = of_peer(0); // begin from root-node
+ ph = of_child(ph); // get a child
+
+ while (ph != 0) {
+ if (of_getprop(ph, "device_type", buf, 255) != -1) {
+ /* if device_type == memory */
+ if (strcmp(buf, "memory") == 0)
+ if (of_getprop(ph, "reg", &reg, 16) != -1) {
+ memory_size += reg.size;
+ }
+ }
+ ph = of_peer(ph); // get next siblings
+ }
+}
+
+long
+getmemsize()
+{
+ return memory_size;
+}
+
+static void
+get_timebase()
+{
+ unsigned int timebase;
+ phandle_t cpu;
+ phandle_t cpus = of_finddevice("/cpus");
+
+ if (cpus == -1)
+ return;
+
+ cpu = of_child(cpus);
+
+ if (cpu == -1)
+ return;
+
+ of_getprop(cpu, "timebase-frequency", &timebase, 4);
+ tb_freq = (uint64_t) timebase;
+}
+
+int
+_start_kernel(unsigned long p0, unsigned long p1)
+{
+ int rc,claim_rc;
+ size_t _client_start = (size_t)&__client_start;
+ size_t _client_size = (size_t)&__client_end - (size_t)&__client_start;
+
+ claim_rc=(int)(long)of_claim((void *)(long)_client_start, _client_size, 0);
+
+ if (init_io() <= -1)
+ return -1;
+ copy_exception_vectors();
+
+ checkmemorysize();
+ get_timebase();
+ rtas_init();
+ rc = _start((unsigned char *) p0, p1);
+
+ term_net_driver();
+
+ restore_exception_vectors();
+ if (claim_rc >= 0) {
+ of_release((void *)(long)_client_start, _client_size);
+ }
+ return rc;
+}
+
+
+void
+exception_forward(void)
+{
+ restore_exception_vectors();
+ undo_exception();
+}
diff --git a/clients/net-snk/kernel/lowmem.S b/clients/net-snk/kernel/lowmem.S
new file mode 100644
index 0000000..ad5127f
--- /dev/null
+++ b/clients/net-snk/kernel/lowmem.S
@@ -0,0 +1,186 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <macros.h>
+.section .lowmem,"aw",@progbits
+
+ .irp i, 0x0200,0x0300,0x0380,0x0400,0x0480,0x0500,0x0600,0x0700, \
+ 0x0800,0x0900,0x0a00,0x0b00
+ . = \i - 0x200
+// 0
+ stdu r1, -0x58(r1)
+ std r0, 0x30(r1)
+ mflr r0
+ std r0, 0x38(r1)
+// 10
+ mfsrr0 r0
+ std r0, 0x48(r1)
+ mfsrr1 r0
+ std r0, 0x50(r1)
+// 20
+ std r11, 0x40(r1)
+ li r0, \i
+ ld r11, 0x60 + \i(0)
+ bl _exception_handler
+
+// 30
+ ld r0, 0x48(r1)
+ mtsrr0 r0
+ ld r0, 0x50(r1)
+ mtsrr1 r0
+
+// 40
+ ld r0, 0x38(r1)
+ mtlr r0
+ ld r0, 0x30(r1)
+ ld r11, 0x40(r1)
+// 50
+ addi r1, r1, 0x58
+ rfid
+ nop
+ nop
+// 60
+// .quad \i+0x68
+ .quad .exception_forward
+// 68
+ blr
+ .endr
+
+ # System call entry
+ . = 0xc00 - 0x200
+
+ stdu r1, -0x50(r1)
+ mflr r11
+ std r11, 0x30(r1)
+ mfsrr0 r11
+ std r11, 0x40(r1)
+ mfsrr1 r11
+ std r11, 0x48(r1)
+ ld r11, _system_call@got(r2)
+ ld r11, 0(r11)
+ mtctr r11
+ mr r10, r0
+ bctrl
+ ld r11, 0x30(r1)
+ mtlr r11
+ ld r11, 0x40(r1)
+ mtsrr0 r11
+ ld r11, 0x48(r1)
+ mtsrr1 r11
+ addi r1, r1, 0x50
+ rfid
+
+ .irp i, 0x0d00,0x0e00,0x0f00, \
+ 0x1000,0x1100,0x1200,0x1300,0x1400,0x1500,0x1600,0x1700, \
+ 0x1800,0x1900,0x1a00,0x1b00,0x1c00,0x1d00,0x1e00,0x1f00, \
+ 0x2000,0x2100,0x2200,0x2300,0x2400,0x2500,0x2600,0x2700, \
+ 0x2800,0x2900,0x2a00,0x2b00,0x2c00,0x2d00,0x2e00,0x2f00
+ . = \i - 0x200
+// 0
+ stdu r1, -0x58(r1)
+ std r0, 0x30(r1)
+ mflr r0
+ std r0, 0x38(r1)
+// 10
+ mfsrr0 r0
+ std r0, 0x48(r1)
+ mfsrr1 r0
+ std r0, 0x50(r1)
+// 20
+ std r11, 0x40(r1)
+ li r0, \i
+ ld r11, 0x60 + \i(0)
+ bl _exception_handler
+
+// 30
+ ld r0, 0x48(r1)
+ mtsrr0 r0
+ ld r0, 0x50(r1)
+ mtsrr1 r0
+
+// 40
+ ld r0, 0x38(r1)
+ mtlr r0
+ ld r0, 0x30(r1)
+ ld r11, 0x40(r1)
+// 50
+ addi r1, r1, 0x58
+ rfid
+ nop
+ nop
+// 60
+// .quad \i+0x68
+ .quad .exception_forward
+// 68
+ blr
+ .endr
+
+/* Saves all register potential clobbered in exception handler.
+ In r0 the pointer to the function is passed.
+ */
+
+_exception_handler:
+ stdu r1, -0x130(r1)
+ .irp i, 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, \
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+ 27, 28, 29, 30, 31
+ std r\i, 0x30+\i*8 (r1)
+ .endr
+ mfctr r14
+ std r14,0x130(r1)
+ mtctr r11
+
+ LOAD64(r3,_entry)
+ ld r2,8(r3)
+
+ ld r3,exception_stack_frame@got(r2)
+ std r1,0(r3)
+
+
+ mflr r14
+ bctrl
+ mtlr r14
+
+ ld r14,0x130(r1)
+ mtctr r14
+/*
+ mfsrr0 r2
+ addi r2, r2, 4
+ mtsrr0 r2
+*/
+ .irp i, 2,3,4,5,6,7,8,9,10,12,13,14,15,16, \
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, \
+ 27, 28, 29, 30, 31
+ ld r\i, 0x30+\i*8 (r1)
+ .endr
+ addi r1, r1, 0x130
+ blr
+
+ .text
+
+/* Set exception handler for given exception vector.
+ r3: exception vector offset
+ r4: exception handler
+*/
+ .globl .set_exception
+.set_exception:
+ .globl set_exception
+set_exception:
+ ld r4,0x0(r4)
+ .globl .set_exception_asm
+.set_exception_asm:
+ .globl set_exception_asm
+set_exception_asm:
+ std r4, 0x60(r3) # fixme diff 1f - 0b
+ blr
+
diff --git a/clients/net-snk/kernel/systemcall.c b/clients/net-snk/kernel/systemcall.c
new file mode 100644
index 0000000..f15cae1
--- /dev/null
+++ b/clients/net-snk/kernel/systemcall.c
@@ -0,0 +1,171 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+
+
+#include <of.h>
+#include <systemcall.h>
+#include <stdarg.h>
+
+extern ihandle_t fd_array[32];
+
+int _socket (int, int, int, char*);
+long _recv (int, void*, int, int);
+long _sendto (int, void*, int, int, void*, int);
+long _send (int, void*, int, int);
+long _ioctl (int, int, void*);
+int vsprintf(char *, const char *, va_list);
+
+long
+_syscall_write (int fd, char *buf, long len)
+{
+ char dest_buf[512];
+ char *dest_buf_ptr;
+ int i;
+ if (fd == 1 || fd == 2)
+ {
+ dest_buf_ptr = &dest_buf[0];
+ for (i = 0; i < len && i < 256; i++)
+ {
+ *dest_buf_ptr++ = *buf++;
+ if (buf[-1] == '\n')
+ *dest_buf_ptr++ = '\r';
+ }
+ len = dest_buf_ptr - &dest_buf[0];
+ buf = &dest_buf[0];
+ }
+ return of_write (fd_array[fd], buf, len);
+}
+
+int
+printk(const char* fmt, ...)
+{
+ int count;
+ va_list ap;
+ char buffer[256];
+ va_start (ap, fmt);
+ count=vsprintf(buffer, fmt, ap);
+ _syscall_write (1, buffer, count);
+ va_end (ap);
+ return count;
+}
+
+long
+_syscall_read (int fd, char *buf, long len)
+{
+ return of_read (fd_array[fd], buf, len);
+}
+
+long
+_syscall_lseek (int fd, long offset, int whence)
+{
+ if (whence != 0)
+ return -1;
+
+ of_seek (fd_array[fd], (unsigned int) (offset>>32), (unsigned int) (offset & 0xffffffffULL));
+
+ return offset;
+}
+
+void
+_syscall_close(int fd)
+{
+ of_close(fd_array[fd]);
+}
+
+int
+_syscall_ioctl (int fd, int request, void* data)
+{
+ return _ioctl (fd, request, data);
+}
+
+long
+_syscall_socket (long which, long arg0, long arg1, long arg2,
+ long arg3, long arg4, long arg5)
+{
+ long rc = -1;
+ switch (which)
+ {
+ case _sock_sc_nr:
+ rc = _socket (arg0, arg1, arg2, (char*) arg3);
+ break;
+ case _recv_sc_nr:
+ rc = _recv (arg0, (void *) arg1, arg2, arg3);
+ break;
+ case _send_sc_nr:
+ rc = _send (arg0, (void *) arg1, arg2, arg3);
+ break;
+ case _sendto_sc_nr:
+ rc = _sendto (arg0, (void *) arg1, arg2, arg3, (void *) arg4, arg5);
+ break;
+ }
+ return rc;
+}
+
+int
+_syscall_open(const char* name, int flags)
+{
+ static int fd = 2;
+ ihandle_t ihandle;
+
+ if ((ihandle = of_open (name)) == 0)
+ {
+ printk ("Cannot open %s\n", name);
+ return -1;
+ }
+
+ fd++;
+ fd_array[fd] = ihandle;
+
+ return fd;
+}
+
+long
+_system_call(long arg0, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6, int nr)
+{
+ long rc = -1;
+ switch (nr)
+ {
+
+ case _open_sc_nr:
+ rc = _syscall_open ((void *) arg0, arg1);
+ break;
+ case _read_sc_nr:
+ rc = _syscall_read (arg0, (void *) arg1, arg2);
+ break;
+ case _close_sc_nr:
+ _syscall_close (arg0);
+ break;
+ case _lseek_sc_nr:
+ rc = _syscall_lseek (arg0, arg1, arg2);
+ break;
+ case _write_sc_nr:
+ rc = _syscall_write (arg0, (void *) arg1, arg2);
+ break;
+ case _ioctl_sc_nr:
+ rc = _syscall_ioctl (arg0, arg1, (void *) arg2);
+ break;
+ case _socket_sc_nr:
+ rc = _syscall_socket (arg0, arg1, arg2, arg3,
+ arg4, arg5, arg6);
+ break;
+ }
+ return rc;
+}
+
+void _exit(int status);
+
+void
+exit(int status)
+{
+ _exit(status);
+}
diff --git a/clients/net-snk/kernel/timer.c b/clients/net-snk/kernel/timer.c
new file mode 100644
index 0000000..a57a463
--- /dev/null
+++ b/clients/net-snk/kernel/timer.c
@@ -0,0 +1,67 @@
+/******************************************************************************
+ * Copyright (c) 2004, 2007 IBM Corporation
+ * All rights reserved.
+ * This program and the accompanying materials
+ * are made available under the terms of the BSD License
+ * which accompanies this distribution, and is available at
+ * http://www.opensource.org/licenses/bsd-license.php
+ *
+ * Contributors:
+ * IBM Corporation - initial implementation
+ *****************************************************************************/
+#include <types.h>
+
+//*******************************************************************
+// variable "tb_freq" contains the frequency in Hz
+// and is read from the device tree (setup by LLFW) in "init.c"
+uint64_t tb_freq;
+
+//-------------------------------------------------------------------
+// Read the current timebase
+uint64_t get_time(void)
+{
+ uint64_t act;
+
+ __asm__ __volatile__(
+ "0: mftbu %0 ;\
+ mftbl %%r0 ; \
+ mftbu %%r4 ; \
+ cmpw %0,%%r4 ; \
+ bne 0b; \
+ sldi %0,%0,32; \
+ or %0,%0,%%r0"
+ : "=r"(act)
+ : /* no inputs */
+ : "r0", "r4");
+ return act;
+}
+
+//-------------------------------------------------------------------
+// wait for ticks/scale timebase ticks
+void wait_ticks(uint64_t ticks)
+{
+ uint64_t timeout = get_time() + ticks;
+ while (get_time() < timeout) {
+ unsigned int i;
+ for (i = 1000; i > 0; i--)
+ __asm__ __volatile__ ("" : : : "memory");
+ }
+}
+
+//-------------------------------------------------------------------
+// wait for (at least) usecs microseconds
+void udelay(unsigned int usecs)
+{
+ // first multiply the usec with timebase and then devide
+ // because 1.000.000 is relatively huge compared to usecs
+ wait_ticks((usecs*tb_freq)/1000000);
+}
+
+//-------------------------------------------------------------------
+// wait for (at least) msecs milliseconds
+void mdelay(unsigned int msecs)
+{
+ // first multiply the msec and timebase and then devide
+ // because 1.000 is relatively huge compared to msecs
+ wait_ticks((msecs*tb_freq)/1000);
+}