aboutsummaryrefslogtreecommitdiff
path: root/slof/ppc64.c
blob: 83a8e82cfb42ba916801ca55f09399ce169404d8 (plain)
1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/******************************************************************************
 * 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;

	/* 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))
		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))
		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;
	int 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;
}