diff options
Diffstat (limited to 'clients/net-snk/kernel')
-rw-r--r-- | clients/net-snk/kernel/Makefile | 43 | ||||
-rw-r--r-- | clients/net-snk/kernel/crt0.c | 74 | ||||
-rw-r--r-- | clients/net-snk/kernel/driver/Makefile | 40 | ||||
-rw-r--r-- | clients/net-snk/kernel/driver/net/Makefile | 38 | ||||
-rw-r--r-- | clients/net-snk/kernel/driver/net/netmodule.c | 138 | ||||
-rw-r--r-- | clients/net-snk/kernel/driver/net_support.c | 534 | ||||
-rw-r--r-- | clients/net-snk/kernel/endian.c | 30 | ||||
-rw-r--r-- | clients/net-snk/kernel/entry.S | 167 | ||||
-rw-r--r-- | clients/net-snk/kernel/init.c | 175 | ||||
-rw-r--r-- | clients/net-snk/kernel/lowmem.S | 186 | ||||
-rw-r--r-- | clients/net-snk/kernel/systemcall.c | 171 | ||||
-rw-r--r-- | clients/net-snk/kernel/timer.c | 67 |
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", ®, 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); +} |