diff options
Diffstat (limited to 'roms/SLOF/slof/ppc64.c')
-rw-r--r-- | roms/SLOF/slof/ppc64.c | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/roms/SLOF/slof/ppc64.c b/roms/SLOF/slof/ppc64.c new file mode 100644 index 000000000..ca6cafffc --- /dev/null +++ b/roms/SLOF/slof/ppc64.c @@ -0,0 +1,280 @@ +/****************************************************************************** + * Copyright (c) 2004, 2008 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 <unistd.h> +#include <sys/socket.h> +#include <cpu.h> + +void asm_cout(long Character,long UART,long NVRAM); + +/* the exception frame should be page aligned + * the_exception_frame is used by the handler to store a copy of all + * registers after an exception; this copy can then be used by paflof's + * exception handler to printout a register dump */ +cell the_exception_frame[0x400 / CELLSIZE] __attribute__ ((aligned(PAGE_SIZE)));; + +/* the_client_frame is the register save area when starting a client */ +cell the_client_frame[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100))); +cell the_client_stack[0x8000 / CELLSIZE] __attribute__ ((aligned(0x100))); +/* THE forth stack */ +cell the_data_stack[0x2000 / CELLSIZE] __attribute__ ((aligned(0x100))); +/* the forth return stack */ +cell the_return_stack[0x2000 / CELLSIZE] __attribute__ ((aligned(0x100))); + +/* forth stack and return-stack pointers */ +cell *restrict dp; +cell *restrict rp; + +/* terminal input buffer */ +cell the_tib[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100))); +/* temporary string buffers */ +char the_pockets[NUMPOCKETS * POCKETSIZE] __attribute__ ((aligned(0x100))); + +cell the_comp_buffer[0x1000 / CELLSIZE] __attribute__ ((aligned(0x100))); + +cell the_heap[HEAP_SIZE / CELLSIZE] __attribute__ ((aligned(0x1000))); +cell *the_heap_start = &the_heap[0]; +cell *the_heap_end = &the_heap[HEAP_SIZE / CELLSIZE]; + +extern void io_putchar(unsigned char); +extern unsigned long call_c(cell arg0, cell arg1, cell arg2, cell entry); + + +static long writeLogByte_wrapper(long x, long y) +{ + unsigned long result; + + SET_CI; + result = writeLogByte(x, y); + CLR_CI; + + return result; +} + + +/** + * Standard write function for the libc. + * + * @param fd file descriptor (should always be 1 or 2) + * @param buf pointer to the array with the output characters + * @param count number of bytes to be written + * @return the number of bytes that have been written successfully + */ +ssize_t write(int fd, const void *buf, size_t count) +{ + char *ptr = (char *)buf; + int len; + + if (fd != 1 && fd != 2) + return 0; + + if (!init_engine || fd == 2) { + len = count; + while (len-- > 0) { + if (*ptr == '\n') + io_putchar('\r'); + io_putchar(*ptr++); + } + return count; + } + + while ((ptr = strchr(buf, '\n')) != NULL) { + forth_push((long)buf); + forth_push((long)ptr - (long)buf); + forth_eval("type cr"); + buf = ptr + 1; + } + len = strlen(buf); + if (len) { + forth_push((long)buf); + forth_push(len); + forth_eval("type"); + } + + return count; +} + +/* This should probably be temporary until a better solution is found */ +void +asm_cout(long Character, long UART, long NVRAM __attribute__((unused))) +{ + if (UART) + io_putchar(Character); +} + +static type_u find_method(type_u phandle, const char *name) +{ + forth_push((type_u)name); + forth_push(strlen(name)); + forth_push(phandle); + forth_eval("find-method"); + if (forth_pop()) + return forth_pop(); + + return 0; +} + +#define FILEIO_TYPE_EMPTY 0 +#define FILEIO_TYPE_FILE 1 +#define FILEIO_TYPE_SOCKET 2 + +struct fileio_type { + int type; + type_u read_xt; + type_u write_xt; +}; + +#define FILEIO_MAX 32 +static struct fileio_type fd_array[FILEIO_MAX]; + +int socket(int domain, int type, int proto, char *mac_addr) +{ + const char mac_prop_name[] = "local-mac-address"; + type_u phandle; + uint8_t *prop_addr; + int prop_len; + int fd; + + if (!(domain == AF_INET || domain == AF_INET6)) + return -1; + + if (type != SOCK_DGRAM || proto != 0) + return -1; + + /* search free file descriptor (and skip stdio handlers) */ + for (fd = 3; fd < FILEIO_MAX; ++fd) { + if (fd_array[fd].type == FILEIO_TYPE_EMPTY) { + break; + } + } + if (fd == FILEIO_MAX) { + puts("Can not open socket, file descriptor list is full"); + return -2; + } + + /* Assume that obp-tftp package is the current one, so + * my-parent is the NIC node that we are interested in */ + forth_eval("my-parent ?dup IF ihandle>phandle THEN"); + phandle = forth_pop(); + if (phandle == 0) { + puts("Can not open socket, no parent instance"); + return -1; + } + fd_array[fd].read_xt = find_method(phandle, "read"); + if (!fd_array[fd].read_xt) { + puts("Can not open socket, no 'read' method"); + return -1; + } + fd_array[fd].write_xt = find_method(phandle, "write"); + if (!fd_array[fd].write_xt) { + puts("Can not open socket, no 'write' method"); + return -1; + } + + /* Read MAC address from device */ + forth_push((unsigned long)mac_prop_name); + forth_push(strlen(mac_prop_name)); + forth_push(phandle); + forth_eval("get-property"); + if (forth_pop()) + return -1; + prop_len = forth_pop(); + prop_addr = (uint8_t *)forth_pop(); + memcpy(mac_addr, &prop_addr[prop_len - 6], 6); + + fd_array[fd].type = FILEIO_TYPE_SOCKET; + + return fd; +} + +static inline int is_valid_fd(int fd) +{ + return fd >= 0 && fd < FILEIO_MAX && + fd_array[fd].type != FILEIO_TYPE_EMPTY; +} + +int close(int fd) +{ + if (!is_valid_fd(fd)) + return -1; + + fd_array[fd].type = FILEIO_TYPE_EMPTY; + + return 0; +} + +/** + * Standard recv function for the libc. + * + * @param fd socket file descriptor + * @param buf pointer to the array where the packet should be stored + * @param len maximum length in bytes of the packet + * @param flags currently unused, should be 0 + * @return the number of bytes that have been received successfully + */ +int recv(int fd, void *buf, int len, int flags) +{ + if (!is_valid_fd(fd) || flags) + return -1; + + forth_push((unsigned long)buf); + forth_push(len); + forth_push(fd_array[fd].read_xt); + return forth_eval_pop("EXECUTE"); +} + +/** + * Standard send function for the libc. + * + * @param fd socket file descriptor + * @param buf pointer to the array with the output packet + * @param len length in bytes of the packet + * @param flags currently unused, should be 0 + * @return the number of bytes that have been sent successfully + */ +int send(int fd, const void *buf, int len, int flags) +{ + if (!is_valid_fd(fd) || flags) + return -1; + + forth_push((unsigned long)buf); + forth_push(len); + forth_push(fd_array[fd].write_xt); + return forth_eval_pop("EXECUTE"); + +} + +/** + * Standard read function for the libc. + * + * @param fd file descriptor (should always be 0 or 2) + * @param buf pointer to the array with the output characters + * @param len number of bytes to be read + * @return the number of bytes that have been read successfully + */ +ssize_t read(int fd, void *buf, size_t len) +{ + char *ptr = (char *)buf; + unsigned cnt = 0; + char code; + + if (fd == 0 || fd == 2) { + while (cnt < len) { + code = forth_eval_pop("key? IF key ELSE 0 THEN"); + if (!code) + break; + ptr[cnt++] = code; + } + } + + return cnt; +} |