Browse Source

Add riscv support code, both portable and arch-specific

Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Ronald G. Minnich 7 years ago
parent
commit
8113f0690e

+ 6 - 0
sys/include/libc.h

@@ -729,3 +729,9 @@ void psliceappend(PSlice *s, void *p);
 size_t pslicelen(PSlice *slice);
 void **pslicefinalize(PSlice *slice);
 void pslicedestroy(PSlice *slice);
+
+/* configstring functions. These are from riscv but the idea is so good
+ * it might have other uses. */
+void query_mem(const char *config_string, uintptr_t *base, size_t *size);
+void query_rtc(const char *config_string, uintptr_t *mtime);
+int query_uint(const char *configstring, char *name, uintptr_t *m);

+ 1 - 0
sys/src/libc/BUILD

@@ -134,6 +134,7 @@ LIBC_SRCS = [
     "port/cistrstr.c",
     "port/charstod.c",
     "port/cleanname.c",
+    "port/configstring.c",
     "port/ctype.c",
     "port/encodefmt.c",
     "port/execl.c",

+ 1 - 0
sys/src/libc/klibc.json

@@ -103,6 +103,7 @@
 			"port/cistrstr.c",
 			"port/charstod.c",
 			"port/cleanname.c",
+			"port/configstring.c",
 			"port/ctype.c",
 			"port/encodefmt.c",
 			"port/execl.c",

+ 1 - 0
sys/src/libc/libc.json

@@ -151,6 +151,7 @@
 		"port/cistrstr.c",
 		"port/charstod.c",
 		"port/cleanname.c",
+		"port/configstring.c",
 		"port/ctype.c",
 		"port/encodefmt.c",
 		"port/execl.c",

+ 243 - 0
sys/src/libc/port/configstring.c

@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2013-2016, The Regents of the University of California
+ *(Regents).
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Regents nor the
+ *    names of its contributors may be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
+ * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
+ * ARISING
+ * OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
+ * BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
+ * HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
+ * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ */
+
+#include <u.h>
+#include <libc.h>
+
+static const char *skip_whitespace(const char *str)
+{
+	while (*str && *str <= ' ')
+		str++;
+	return str;
+}
+
+static const char *skip_string(const char *str)
+{
+	while (*str && *str++ != '"')
+		;
+	return str;
+}
+
+static int is_hex(char ch)
+{
+	return (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f') ||
+	       (ch >= 'A' && ch <= 'F');
+}
+
+static int parse_hex(char ch)
+{
+	return (ch >= '0' && ch <= '9') ? ch - '0' : (ch >= 'a' && ch <= 'f')
+							 ? ch - 'a' + 10
+							 : ch - 'A' + 10;
+}
+
+static const char *skip_key(const char *str)
+{
+	while (*str >= 35 && *str <= 122 && *str != ';')
+		str++;
+	return str;
+}
+
+typedef struct {
+	const char *start;
+	const char *end;
+} query_result;
+
+static query_result query_config_string(const char *str, const char *k)
+{
+	size_t ksize = 0;
+	while (k[ksize] && k[ksize] != '{')
+		ksize++;
+	int last = !k[ksize];
+
+	query_result res = {0, 0};
+	while (1) {
+		const char *key_start = str = skip_whitespace(str);
+		const char *key_end = str = skip_key(str);
+		int match = (size_t)(key_end - key_start) == ksize;
+		if (match)
+			for (size_t i = 0; i < ksize; i++)
+				if (key_start[i] != k[i])
+					match = 0;
+		const char *value_start = str = skip_whitespace(str);
+		while (*str != ';') {
+			if (!*str) {
+				return res;
+			} else if (*str == '"') {
+				str = skip_string(str + 1);
+			} else if (*str == '{') {
+				const char *search_key =
+				    match && !last ? k + ksize + 1 : "";
+				query_result inner_res =
+				    query_config_string(str + 1, search_key);
+				if (inner_res.start)
+					return inner_res;
+				str = inner_res.end + 1;
+			} else {
+				str = skip_key(str);
+			}
+			str = skip_whitespace(str);
+		}
+		res.end = str;
+		if (match && last) {
+			res.start = value_start;
+			return res;
+		}
+		str = skip_whitespace(str + 1);
+		if (*str == '}') {
+			res.end = str;
+			return res;
+		}
+	}
+}
+
+static void parse_string(query_result r, char *buf)
+{
+	if (r.start < r.end) {
+		if (*r.start == '"') {
+			for (const char *p = r.start + 1;
+			     p < r.end && *p != '"'; p++) {
+				char ch = p[0];
+				if (ch == '\\' && p[1] == 'x' && is_hex(p[2])) {
+					ch = parse_hex(p[2]);
+					if (is_hex(p[3])) {
+						ch =
+						    (ch << 4) + parse_hex(p[3]);
+						p++;
+					}
+					p += 2;
+				}
+				*buf++ = ch;
+			}
+		} else {
+			for (const char *p = r.start; p < r.end && *p > ' ';
+			     p++)
+				*buf++ = *p;
+		}
+	}
+	*buf = 0;
+}
+
+static uint64_t __get_uint_hex(const char *s)
+{
+	uint64_t res = 0;
+	while (*s) {
+		if (is_hex(*s))
+			res = (res << 4) + parse_hex(*s);
+		else if (*s != '_')
+			break;
+		s++;
+	}
+	return res;
+}
+
+static uint64_t __get_uint_dec(const char *s)
+{
+	uint64_t res = 0;
+	while (*s) {
+		if (*s >= '0' && *s <= '9')
+			res = res * 10 + (*s - '0');
+		else
+			break;
+		s++;
+	}
+	return res;
+}
+
+static uint64_t __get_uint(const char *s)
+{
+	if (s[0] == '0' && s[1] == 'x')
+		return __get_uint_hex(s + 2);
+	return __get_uint_dec(s);
+}
+
+static inline uint64_t get_uint(query_result res)
+{
+	uint64_t v;
+	char *name;
+
+	name = malloc(res.end - res.start + 1);
+	parse_string(res, name);
+	v = __get_uint(name);
+	free(name);
+	return v;
+}
+
+/* this will be needed, but just not yet.*/
+#if 0
+static inline int64_t get_sint(query_result res)
+{
+	int64_t v;
+	char *name;
+
+	name = malloc(res.end - res.start + 1);
+	parse_string(res, name);
+	if (name[0] == '-')
+		return -__get_uint(name + 1);
+	v = __get_uint(name);
+	free(name);
+	return v;
+}
+#endif
+
+void query_mem(const char *config_string, uintptr_t *base, size_t *size)
+{
+	*base = 0;
+	*size = 0;
+	query_result res = query_config_string(config_string, "ram{0{addr");
+	if (!res.start)
+		return;
+	*base = get_uint(res);
+	res = query_config_string(config_string, "ram{0{size");
+	if (!res.start)
+		return;
+	*size = get_uint(res);
+}
+
+/* query_rtc returns the physical address of the rtc. */
+void query_rtc(const char *config_string, uintptr_t *mtime)
+{
+	*mtime = 0;
+	query_result res = query_config_string(config_string, "rtc{addr");
+	if (!res.start)
+		return;
+	*mtime = (uintptr_t)get_uint(res);
+}
+
+int query_uint(const char *configstring, char *name, uintptr_t *res)
+{
+	query_result m;
+
+	m = query_config_string(configstring, name);
+	if (m.start) {
+		*res = (uintptr_t)get_uint(m);
+		return 0;
+	}
+	return -1;
+}

+ 27 - 17
sys/src/libc/riscv/atomic.S

@@ -2,13 +2,16 @@
 
 .globl ainc				/* int32_t ainc(int32_t *); */
 ainc:
-	li		a1, 1
-	amoadd.w.aq	a0, a1, 0(a0)
+	li		t0, 1
+	amoadd.w.aq	t1, t0, 0(a0)
+	add		a0, t1, t0
 	ret
+
 .globl adec				/* int32_t adec(int32_t *); */
 adec:
-	li		a1, -1
-	amoadd.w.aq	a0, a1, 0(a0)
+	li		t0, -1
+	amoadd.w.aq	t1, t0, 0(a0)
+	add		a0, t1, t0
 	ret
 
 /* This works fine either way as we are little endian. */
@@ -19,11 +22,14 @@ _tas32:
 tas32:
 .globl _tas				/* int _tas(int *); */
 _tas:
-	mv	a3, a0
-	li           a1, 1
-	ld	     a2, 0(a0)
-	amoswap.w.aq a0, a1, 0(a0)
-	ld		a3, 0(a3)
+	li t0, 1
+	amoswap.w.aq t0, t0, 0(a0)
+	bnez t0, 1f
+	li a0, 0
+	ret
+/* failure. */
+1:
+	li a0, 1
 	ret
 
 .globl aswap				/* int aswap(int *, int); */
@@ -34,15 +40,19 @@ aswap:
 .globl cas32
 // int	cas32(void* %rdi, uint32_t %esi, uint32_t %edx);
 // a0 holds address of memory location
-// a1 holds expected value
-// a2 holds desired value
-// v0 return value, 0 if successful, !0 otherwise
+// a1 holds expected value (old)
+// a2 holds desired value (new)
+// v0 return value, 1 if successful, 0 otherwise
 cas32:
-	lr.w x17, (a0)  // Load original value
-	li x16, 1 # Preset return to fail
-	bne x17, a1, return # Doesn’t match, so fail
-	sc.w x16, a2, (a0) # Try to update
-return: jr ra
+	lr.w t0, (a0)  // Load original value
+	bne t0, a1, 1f # Doesn’t match, so fail
+	sc.w a0, a2, (a0) # Try to update
+	bne zero, a0, 1f
+	li a0, 1
+	jr ra
+1: 
+	li a0, 0 # Preset return to fail
+	jr ra
 
 .globl mfence
 mfence:

+ 0 - 2
sys/src/libc/riscv/build.json

@@ -9,8 +9,6 @@
 	    "$ARCH/gettls.S",
 	    "$ARCH/main9.S",
 	    "$ARCH/setjmp.S",
-	    "$ARCH/_spl.S",
-	    "$ARCH/spl.c",
 	    "$ARCH/sqrt.c"
 	]
     }

+ 9 - 0
sys/src/libc/riscv/main9.S

@@ -1,5 +1,14 @@
 .text
 
+.globl _gp
 .globl	_main
+.globl _tos
 _main:
+	lui     a5,%hi(_tos)
+	sd      a2,%lo(_tos)(a5)
+	ld	a0, 0(sp)
+	addi	a1, sp, 8
+	j main
+////        auipc   gp,0xfffff
+//        addi    gp,gp,_gp
 	ret