summaryrefslogtreecommitdiffstats
path: root/qemu/roms/SLOF/lib
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/SLOF/lib')
-rw-r--r--qemu/roms/SLOF/lib/libc/include/stdlib.h1
-rw-r--r--qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c180
-rw-r--r--qemu/roms/SLOF/lib/libc/stdlib/rand.c9
-rw-r--r--qemu/roms/SLOF/lib/libhvcall/Makefile2
-rw-r--r--qemu/roms/SLOF/lib/libhvcall/rfill.c38
-rw-r--r--qemu/roms/SLOF/lib/libnvram/envvar.c40
-rw-r--r--qemu/roms/SLOF/lib/libnvram/libnvram.code75
-rw-r--r--qemu/roms/SLOF/lib/libnvram/nvram.c27
-rw-r--r--qemu/roms/SLOF/lib/libnvram/nvram.h10
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-core.c37
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-core.h7
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-ehci.c4
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-hid.c85
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-hub.c4
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-ohci.c16
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-slof.c34
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-xhci.c236
-rw-r--r--qemu/roms/SLOF/lib/libusb/usb-xhci.h5
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/p9.c2
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/p9.h2
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-9p.c35
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-9p.h2
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-blk.c100
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-blk.h2
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-internal.h48
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-net.c200
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-net.h15
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c174
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio.c457
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio.code23
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio.h58
-rw-r--r--qemu/roms/SLOF/lib/libvirtio/virtio.in2
32 files changed, 1355 insertions, 575 deletions
diff --git a/qemu/roms/SLOF/lib/libc/include/stdlib.h b/qemu/roms/SLOF/lib/libc/include/stdlib.h
index dff57f577..5e0eda9ff 100644
--- a/qemu/roms/SLOF/lib/libc/include/stdlib.h
+++ b/qemu/roms/SLOF/lib/libc/include/stdlib.h
@@ -29,5 +29,6 @@ unsigned long int strtoul(const char *nptr, char **endptr, int base);
long int strtol(const char *nptr, char **endptr, int base);
int rand(void);
+void srand(unsigned int seed);
#endif
diff --git a/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c b/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c
index e78fb3d8e..21dd04dfe 100644
--- a/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c
+++ b/qemu/roms/SLOF/lib/libc/stdio/vsnprintf.c
@@ -10,72 +10,110 @@
* IBM Corporation - initial implementation
*****************************************************************************/
+#include <stdbool.h>
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
+#include "ctype.h"
-const static unsigned long long convert[] = {
+static const unsigned long long convert[] = {
0x0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF,
0xFFFFFFFFFFULL, 0xFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFFULL
};
-
-
static int
-print_itoa(char **buffer,unsigned long value, unsigned short int base)
+print_str_fill(char **buffer, size_t bufsize, char *sizec,
+ const char *str, char c)
{
- const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
- static char sign = 0;
-
- if(base <= 2 || base > 16)
- return 0;
-
- if(value < 0) {
- sign = 1;
- value *= -1;
- }
+ int i, sizei, len;
+ char *bstart = *buffer;
- if(value < base) {
- if(sign) {
- **buffer = '-';
+ sizei = strtoul(sizec, NULL, 10);
+ len = strlen(str);
+ if (sizei > len) {
+ for (i = 0;
+ (i < (sizei - len)) && ((*buffer - bstart) < bufsize);
+ i++) {
+ **buffer = c;
*buffer += 1;
- sign = 0;
}
- **buffer = zeichen[value];
- *buffer += 1;
- } else {
- print_itoa(buffer, value / base, base);
- **buffer = zeichen[(value % base)];
- *buffer += 1;
}
-
return 1;
}
+static int
+print_str(char **buffer, size_t bufsize, const char *str)
+{
+ char *bstart = *buffer;
+ size_t i;
+
+ for (i = 0; (i < strlen(str)) && ((*buffer - bstart) < bufsize); i++) {
+ **buffer = str[i];
+ *buffer += 1;
+ }
+ return 1;
+}
static unsigned int
print_intlen(unsigned long value, unsigned short int base)
{
int i = 0;
- while(value > 0) {
+ while (value > 0) {
value /= base;
i++;
}
- if(i == 0) i = 1;
+ if (i == 0)
+ i = 1;
return i;
}
+static int
+print_itoa(char **buffer, size_t bufsize, unsigned long value,
+ unsigned short base, bool upper)
+{
+ const char zeichen[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+ char c;
+ size_t i, len;
+
+ if(base <= 2 || base > 16)
+ return 0;
+
+ len = i = print_intlen(value, base);
+
+ /* Don't print to buffer if bufsize is not enough. */
+ if (len > bufsize)
+ return 0;
+
+ do {
+ c = zeichen[value % base];
+ if (upper)
+ c = toupper(c);
+
+ (*buffer)[--i] = c;
+ value /= base;
+ } while(value);
+
+ *buffer += len;
+
+ return 1;
+}
+
+
static int
-print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int base, char c, int optlen)
+print_fill(char **buffer, size_t bufsize, char *sizec, unsigned long size,
+ unsigned short int base, char c, int optlen)
{
int i, sizei, len;
+ char *bstart = *buffer;
sizei = strtoul(sizec, NULL, 10);
len = print_intlen(size, base) + optlen;
- if(sizei > len) {
- for(i = 0; i < (sizei - len); i++) {
+ if (sizei > len) {
+ for (i = 0;
+ (i < (sizei - len)) && ((*buffer - bstart) < bufsize);
+ i++) {
**buffer = c;
*buffer += 1;
}
@@ -86,17 +124,18 @@ print_fill(char **buffer, char *sizec, unsigned long size, unsigned short int ba
static int
-print_format(char **buffer, const char *format, void *var)
+print_format(char **buffer, size_t bufsize, const char *format, void *var)
{
- unsigned long start;
- unsigned int i = 0, sizei = 0, len = 0, length_mod = sizeof(int);
+ char *start;
+ unsigned int i = 0, length_mod = sizeof(int);
unsigned long value = 0;
unsigned long signBit;
char *form, sizec[32];
char sign = ' ';
+ bool upper = false;
form = (char *) format;
- start = (unsigned long) *buffer;
+ start = *buffer;
form++;
if(*form == '0' || *form == '.') {
@@ -104,7 +143,7 @@ print_format(char **buffer, const char *format, void *var)
form++;
}
- while(*form != '\0') {
+ while ((*form != '\0') && ((*buffer - start) < bufsize)) {
switch(*form) {
case 'u':
case 'd':
@@ -112,57 +151,59 @@ print_format(char **buffer, const char *format, void *var)
sizec[i] = '\0';
value = (unsigned long) var;
signBit = 0x1ULL << (length_mod * 8 - 1);
- if (signBit & value) {
+ if ((*form != 'u') && (signBit & value)) {
**buffer = '-';
*buffer += 1;
value = (-(unsigned long)value) & convert[length_mod];
}
- print_fill(buffer, sizec, value, 10, sign, 0);
- print_itoa(buffer, value, 10);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, value, 10, sign, 0);
+ print_itoa(buffer, bufsize - (*buffer - start),
+ value, 10, upper);
break;
case 'X':
+ upper = true;
case 'x':
sizec[i] = '\0';
value = (unsigned long) var & convert[length_mod];
- print_fill(buffer, sizec, value, 16, sign, 0);
- print_itoa(buffer, value, 16);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, value, 16, sign, 0);
+ print_itoa(buffer, bufsize - (*buffer - start),
+ value, 16, upper);
break;
case 'O':
case 'o':
sizec[i] = '\0';
value = (long int) var & convert[length_mod];
- print_fill(buffer, sizec, value, 8, sign, 0);
- print_itoa(buffer, value, 8);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, value, 8, sign, 0);
+ print_itoa(buffer, bufsize - (*buffer - start),
+ value, 8, upper);
break;
case 'p':
sizec[i] = '\0';
- print_fill(buffer, sizec, (unsigned long) var, 16, ' ', 2);
- **buffer = '0';
- *buffer += 1;
- **buffer = 'x';
- *buffer += 1;
- print_itoa(buffer,(unsigned long) var, 16);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, (unsigned long) var, 16, ' ', 2);
+ print_str(buffer, bufsize - (*buffer - start),
+ "0x");
+ print_itoa(buffer, bufsize - (*buffer - start),
+ (unsigned long) var, 16, upper);
break;
case 'c':
sizec[i] = '\0';
- print_fill(buffer, sizec, 1, 10, ' ', 0);
+ print_fill(buffer, bufsize - (*buffer - start),
+ sizec, 1, 10, ' ', 0);
**buffer = (unsigned long) var;
*buffer += 1;
break;
case 's':
sizec[i] = '\0';
- sizei = strtoul(sizec, NULL, 10);
- len = strlen((char *) var);
- if(sizei > len) {
- for(i = 0; i < (sizei - len); i++) {
- **buffer = ' ';
- *buffer += 1;
- }
- }
- for(i = 0; i < strlen((char *) var); i++) {
- **buffer = ((char *) var)[i];
- *buffer += 1;
- }
+ print_str_fill(buffer,
+ bufsize - (*buffer - start), sizec,
+ (char *) var, ' ');
+
+ print_str(buffer, bufsize - (*buffer - start),
+ (char *) var);
break;
case 'l':
form++;
@@ -182,6 +223,9 @@ print_format(char **buffer, const char *format, void *var)
length_mod = sizeof(short int);
}
break;
+ case 'z':
+ length_mod = sizeof(size_t);
+ break;
default:
if(*form >= '0' && *form <= '9')
sizec[i++] = *form;
@@ -206,6 +250,16 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
bstart = buffer;
ptr = (char *) format;
+ /*
+ * Return from here if size passed is zero, otherwise we would
+ * overrun buffer while setting NULL character at the end.
+ */
+ if (!buffer || !bufsize)
+ return 0;
+
+ /* Leave one space for NULL character */
+ bufsize--;
+
while(*ptr != '\0' && (buffer - bstart) < bufsize)
{
if(*ptr == '%') {
@@ -224,7 +278,9 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg)
if(*ptr == '%') {
*buffer++ = '%';
} else {
- print_format(&buffer, formstr, va_arg(arg, void *));
+ print_format(&buffer,
+ bufsize - (buffer - bstart),
+ formstr, va_arg(arg, void *));
}
ptr++;
} else {
diff --git a/qemu/roms/SLOF/lib/libc/stdlib/rand.c b/qemu/roms/SLOF/lib/libc/stdlib/rand.c
index 87e3efd29..39f5a9a2c 100644
--- a/qemu/roms/SLOF/lib/libc/stdlib/rand.c
+++ b/qemu/roms/SLOF/lib/libc/stdlib/rand.c
@@ -18,7 +18,12 @@ static unsigned long _rand = 1;
int
rand(void)
{
- _rand = _rand * 25364735 + 34563;
+ _rand = _rand * 1237732973 + 34563;
- return ((unsigned int) (_rand << 16) & RAND_MAX);
+ return ((unsigned int) (_rand >> 16) & RAND_MAX);
+}
+
+void srand(unsigned int seed)
+{
+ _rand = seed;
}
diff --git a/qemu/roms/SLOF/lib/libhvcall/Makefile b/qemu/roms/SLOF/lib/libhvcall/Makefile
index 2a9b2d7d1..def532509 100644
--- a/qemu/roms/SLOF/lib/libhvcall/Makefile
+++ b/qemu/roms/SLOF/lib/libhvcall/Makefile
@@ -24,7 +24,7 @@ TARGET = ../libhvcall.a
all: $(TARGET)
-SRCS = brokensc1.c
+SRCS = brokensc1.c rfill.c
SRCSS = hvcall.S
diff --git a/qemu/roms/SLOF/lib/libhvcall/rfill.c b/qemu/roms/SLOF/lib/libhvcall/rfill.c
new file mode 100644
index 000000000..5407cd2a6
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libhvcall/rfill.c
@@ -0,0 +1,38 @@
+/*****************************************************************************
+ * Fast function for filling cache-inhibited memory regions via h-call.
+ *
+ * Copyright 2015 Red Hat, Inc.
+ *
+ * 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:
+ * Thomas Huth, Red Hat Inc. - initial implementation
+ *****************************************************************************/
+
+#include <cache.h>
+#include <string.h>
+
+typedef unsigned long type_u;
+
+/**
+ * fast_rfill is the implementation of the FAST_RFILL macro with h-calls.
+ * This is defined here instead of cache.h since we need a temporary
+ * local buffer - and that caused stack size problems in engine() when
+ * we used it directly in the FAST_RFILL macro.
+ */
+void fast_rfill(char *dst, long size, char pat)
+{
+ type_u buf[64];
+
+ memset(buf, pat, size < sizeof(buf) ? size : sizeof(buf));
+
+ while (size > sizeof(buf)) {
+ FAST_MRMOVE(buf, dst, sizeof(buf));
+ dst += sizeof(buf);
+ size -= sizeof(buf);
+ }
+ FAST_MRMOVE(buf, dst, size);
+}
diff --git a/qemu/roms/SLOF/lib/libnvram/envvar.c b/qemu/roms/SLOF/lib/libnvram/envvar.c
index 87aaf27a0..ee943fce5 100644
--- a/qemu/roms/SLOF/lib/libnvram/envvar.c
+++ b/qemu/roms/SLOF/lib/libnvram/envvar.c
@@ -17,7 +17,7 @@
#include "nvram.h"
/* returns the offset of the first byte after the searched envvar */
-static int get_past_env_pos(partition_t part, char *envvar)
+static int get_past_env_pos(partition_t part, char *envvar, int evlen)
{
int offset, len;
static char temp[256];
@@ -32,7 +32,7 @@ static int get_past_env_pos(partition_t part, char *envvar)
while((data=nvram_read_byte(offset++)) && len < 256) {
temp[len++]=data;
}
- if (!strncmp(envvar, temp, strlen(envvar))) {
+ if (!strncmp(envvar, temp, evlen)) {
return offset;
}
} while (len);
@@ -43,16 +43,16 @@ static int get_past_env_pos(partition_t part, char *envvar)
/**
* @param partition name of the envvar partition
* @param envvar name of the environment variable
+ * @param evlen string length of the envvar parameter
* @return pointer to temporary string containing the value of envvar
*/
-
-char *get_env(partition_t part, char *envvar)
+char *nvram_get_env(partition_t part, char *envvar, int evlen)
{
static char temp[256+1];
int len, offset;
uint8_t data;
- DEBUG("get_env %s... ", envvar);
+ DEBUG("nvram_get_env %p... ", envvar);
if(!part.addr) {
/* ERROR: No environment variable partition */
DEBUG("invalid partition.\n");
@@ -68,7 +68,7 @@ char *get_env(partition_t part, char *envvar)
}
temp[len]=0;
- if (!strncmp(envvar, temp, strlen(envvar))) {
+ if (!strncmp(envvar, temp, evlen)) {
int pos=0;
while (temp[pos]!='=' && pos < len) pos++;
// DEBUG("value='%s'\n", temp+pos+1);
@@ -100,7 +100,7 @@ static int find_last_envvar(partition_t part)
return -1;
}
-int add_env(partition_t part, char *envvar, char *value)
+int nvram_add_env(partition_t part, char *envvar, int evlen, char *value, int vallen)
{
int freespace, last, len, offset;
unsigned int i;
@@ -112,7 +112,7 @@ int add_env(partition_t part, char *envvar, char *value)
freespace = part.addr+part.len-last;
/* how long is the entry we want to write? */
- len = strlen(envvar) + strlen(value) + 2;
+ len = evlen + vallen + 2;
if(freespace<len) {
// TODO try to increase partition size
@@ -121,18 +121,18 @@ int add_env(partition_t part, char *envvar, char *value)
offset=last;
- for(i=0; i<strlen(envvar); i++)
+ for (i = 0; i < evlen; i++)
nvram_write_byte(offset++, envvar[i]);
nvram_write_byte(offset++, '=');
- for(i=0; i<strlen(value); i++)
+ for (i = 0; i < vallen; i++)
nvram_write_byte(offset++, value[i]);
return 0;
}
-int del_env(partition_t part, char *envvar)
+int nvram_del_env(partition_t part, char *envvar, int evlen)
{
int last, current, pos, i;
char *buffer;
@@ -141,7 +141,7 @@ int del_env(partition_t part, char *envvar)
return -1;
last=find_last_envvar(part);
- current = pos = get_past_env_pos(part, envvar);
+ current = pos = get_past_env_pos(part, envvar, evlen);
// TODO is this really required?
/* go back to non-0 value */
@@ -168,25 +168,25 @@ int del_env(partition_t part, char *envvar)
return 0;
}
-int set_env(partition_t part, char *envvar, char *value)
+int nvram_set_env(partition_t part, char *envvar, int evlen, char *value, int vallen)
{
char *oldvalue, *buffer;
int last, current, buffersize, i;
- DEBUG("set_env %lx[%lx]: %s=%s\n", part.addr, part.len, envvar, value);
+ DEBUG("nvram_set_env %lx[%lx]: %p=>%p\n", part.addr, part.len, envvar, value);
if(!part.addr)
return -1;
/* Check whether the environment variable exists already */
- oldvalue = get_env(part, envvar);
+ oldvalue = nvram_get_env(part, envvar, evlen);
- if(oldvalue==NULL)
- return add_env(part, envvar, value);
+ if (oldvalue == NULL)
+ return nvram_add_env(part, envvar, evlen, value, vallen);
/* The value did not change. So we succeeded! */
- if(!strncmp(oldvalue, value, strlen(value)+1))
+ if (strlen(oldvalue) == vallen && !strncmp(oldvalue, value, vallen))
return 0;
/* we need to overwrite environment variables, back them up first */
@@ -195,7 +195,7 @@ int set_env(partition_t part, char *envvar, char *value)
/* allocate a buffer */
last=find_last_envvar(part);
- current=get_past_env_pos(part, envvar);
+ current = get_past_env_pos(part, envvar, evlen);
buffersize = last - current;
buffer=get_nvram_buffer(buffersize);
if(!buffer)
@@ -214,7 +214,7 @@ int set_env(partition_t part, char *envvar, char *value)
current++;
/* Write the new value */
- for(i=0; i<(int)strlen(value); i++) {
+ for(i = 0; i < vallen; i++) {
nvram_write_byte(current++, value[i]);
}
diff --git a/qemu/roms/SLOF/lib/libnvram/libnvram.code b/qemu/roms/SLOF/lib/libnvram/libnvram.code
index 723941d3e..8481f57f5 100644
--- a/qemu/roms/SLOF/lib/libnvram/libnvram.code
+++ b/qemu/roms/SLOF/lib/libnvram/libnvram.code
@@ -11,17 +11,6 @@
*****************************************************************************/
#include <nvram.h>
-#define STRING_INIT(str) \
- char str[255]; \
- char * str##_address; \
- int str##_length;
-
-#define STRING_FROM_STACK(str) \
- str##_length = TOS.u; POP; \
- str##_address = TOS.a; POP; \
- memcpy(str, str##_address, str##_length); \
- memset(str + str##_length, 0, 255 - str##_length);
-
PRIM(nvram_X2d_c_X40)
unsigned int offset = TOS.u;
TOS.u=nvram_read_byte(offset);
@@ -80,21 +69,18 @@ MIRP
/* get-named-nvram-partition ( name.addr name.len -- addr len FAILED? ) */
PRIM(get_X2d_named_X2d_nvram_X2d_partition)
- STRING_INIT(name)
partition_t partition;
+ int namelen = TOS.n; POP;
- STRING_FROM_STACK(name)
- partition = get_partition(-1, name);
+ partition = get_partition_fs(TOS.a, namelen);
if(partition.len && partition.len != -1) {
- PUSH;
TOS.u = partition.addr;
PUSH;
TOS.u = partition.len;
PUSH;
TOS.u = 0; // FALSE
} else {
- PUSH;
TOS.u = -1; // TRUE
}
MIRP
@@ -103,23 +89,16 @@ MIRP
/* new-nvram-partition ( type name.addr name.len len -- part.offs part.len FALSE | TRUE) */
PRIM(new_X2d_nvram_X2d_partition)
- int type, len, i, slen;
- char name[12], *addr;
+ int type, len, namelen;
partition_t partition;
+ char *name;
len = TOS.u; POP;
- slen = TOS.u; POP;
- addr = (char *)TOS.u; POP;
+ namelen = TOS.u; POP;
+ name = (char *)TOS.u; POP;
type = TOS.u; POP;
- for (i=0; i<12; i++) {
- if(slen>i)
- name[i]=addr[i];
- else
- name[i]=0;
- }
-
- partition=new_nvram_partition(type, name, len);
+ partition = new_nvram_partition_fs(type, name, namelen, len);
if(!partition.len) {
PUSH; TOS.u = -1; // TRUE
@@ -165,15 +144,17 @@ MIRP
// ( part.start part.len name.addr name.len -- var.addr var.len TRUE | false )
PRIM(internal_X2d_get_X2d_env)
- STRING_INIT(name)
+ char *name;
+ int namelen;
partition_t part;
char *val;
- STRING_FROM_STACK(name)
+ namelen = TOS.u; POP;
+ name = TOS.a; POP;
part.len = TOS.u; POP;
part.addr = TOS.u; POP;
- val=get_env(part, name);
+ val = nvram_get_env(part, name, namelen);
if(val) {
PUSH; TOS.a = val;
PUSH; TOS.u = strlen(val);
@@ -185,17 +166,19 @@ MIRP
// ( part.start part.len name.addr name.len val.addr val.len -- FALSE|TRUE)
PRIM(internal_X2d_add_X2d_env)
- STRING_INIT(name)
- STRING_INIT(value)
+ char *name, *val;
+ int namelen, vallen;
partition_t part;
int ret;
- STRING_FROM_STACK(value)
- STRING_FROM_STACK(name)
+ vallen = TOS.u; POP;
+ val = TOS.a; POP;
+ namelen = TOS.u; POP;
+ name = TOS.a; POP;
part.len = TOS.u; POP;
part.addr = TOS.u; POP;
- ret=add_env(part, name, value);
+ ret = nvram_add_env(part, name, namelen, val, vallen);
if(ret) {
PUSH; TOS.u = -1; // TRUE
} else {
@@ -205,15 +188,17 @@ MIRP
// ( part.addr part.len name.addr name.len -- FALSE|TRUE)
PRIM(internal_X2d_del_X2d_env)
- STRING_INIT(name)
+ char *name;
+ int namelen;
partition_t part;
int ret;
- STRING_FROM_STACK(name);
+ namelen = TOS.u; POP;
+ name = TOS.a; POP;
part.len = TOS.u; POP;
part.addr = TOS.u; POP;
- ret=del_env(part, name);
+ ret = nvram_del_env(part, name, namelen);
if(ret) {
PUSH; TOS.u = -1; // TRUE
} else {
@@ -224,17 +209,19 @@ MIRP
// internal-set-env ( part.addr part.len name.addr name.len val.addr val.len -- FALSE|TRUE)
PRIM(internal_X2d_set_X2d_env)
- STRING_INIT(name)
- STRING_INIT(value)
+ char *name, *value;
+ int namelen, valuelen;
partition_t part;
int ret;
- STRING_FROM_STACK(value)
- STRING_FROM_STACK(name)
+ valuelen = TOS.u; POP;
+ value = TOS.a; POP;
+ namelen = TOS.u; POP;
+ name = TOS.a; POP;
part.len = TOS.u; POP;
part.addr = TOS.u; POP;
- ret=set_env(part, name, value);
+ ret = nvram_set_env(part, name, namelen, value, valuelen);
if(ret) {
PUSH; TOS.u = -1; // TRUE
} else {
diff --git a/qemu/roms/SLOF/lib/libnvram/nvram.c b/qemu/roms/SLOF/lib/libnvram/nvram.c
index 5c1137669..473814e5c 100644
--- a/qemu/roms/SLOF/lib/libnvram/nvram.c
+++ b/qemu/roms/SLOF/lib/libnvram/nvram.c
@@ -358,6 +358,17 @@ partition_t get_partition(unsigned int type, char *name)
return ret;
}
+/* Get partition specified by a Forth string */
+partition_t get_partition_fs(char *name, int namelen)
+{
+ char buf[namelen + 1];
+
+ memcpy(buf, name, namelen);
+ buf[namelen] = 0;
+
+ return get_partition(-1, buf);
+}
+
void erase_nvram(int offset, int len)
{
int i;
@@ -466,6 +477,22 @@ partition_t new_nvram_partition(int type, char *name, int len)
return new_part;
}
+partition_t new_nvram_partition_fs(int type, char *name, int namelen, int len)
+{
+ char buf[13];
+ int i;
+
+ for (i = 0; i < 12; i++) {
+ if (i < namelen)
+ buf[i] = name[i];
+ else
+ buf[i] = 0;
+ }
+ buf[12] = 0;
+
+ return new_nvram_partition(type, buf, len);
+}
+
/**
* @param partition partition structure pointing to the partition to wipe.
*/
diff --git a/qemu/roms/SLOF/lib/libnvram/nvram.h b/qemu/roms/SLOF/lib/libnvram/nvram.h
index fa6bdd425..73fe44424 100644
--- a/qemu/roms/SLOF/lib/libnvram/nvram.h
+++ b/qemu/roms/SLOF/lib/libnvram/nvram.h
@@ -51,9 +51,11 @@ char *get_nvram_buffer(int len);
void free_nvram_buffer(char *buffer);
int nvramlog_printf(const char* fmt, ...);
partition_t get_partition(unsigned int type, char *name);
+partition_t get_partition_fs(char *name, int namelen);
void erase_nvram(int offset, int len);
int wipe_partition(partition_t partition, int header_only);
partition_t new_nvram_partition(int type, char *name, int len);
+partition_t new_nvram_partition_fs(int type, char *name, int namelen, int len);
int increase_nvram_partition_size(partition_t partition, int newsize);
int clear_nvram_partition(partition_t part);
int delete_nvram_partition(partition_t part);
@@ -65,9 +67,9 @@ void nvram_init(uint32_t store_token, uint32_t fetch_token,
unsigned int get_nvram_size(void);
/* envvar.c */
-char *get_env(partition_t part, char *envvar);
-int add_env(partition_t part, char *envvar, char *value);
-int del_env(partition_t part, char *envvar);
-int set_env(partition_t part, char *envvar, char *value);
+char *nvram_get_env(partition_t part, char *envvar, int evlen);
+int nvram_add_env(partition_t part, char *envvar, int evlen, char *value, int vallen);
+int nvram_del_env(partition_t part, char *envvar, int evlen);
+int nvram_set_env(partition_t part, char *envvar, int evlen, char *val, int vlen);
#endif
diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.c b/qemu/roms/SLOF/lib/libusb/usb-core.c
index 6719c5726..4c720ce2f 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-core.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-core.c
@@ -383,8 +383,6 @@ int usb_hid_exit(void *vdev)
return true;
}
-#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16)
-
int usb_msc_init(void *vdev)
{
struct usb_dev *dev;
@@ -420,7 +418,7 @@ int usb_msc_exit(void *vdev)
return true;
}
-static int usb_msc_reset(struct usb_dev *dev)
+int usb_msc_reset(struct usb_dev *dev)
{
struct usb_dev_req req;
@@ -477,7 +475,7 @@ static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *c
case DESCR_TYPE_HUB:
break;
default:
- printf("ptr %p desc_type %d\n", ptr, desc_type);
+ dprintf("ptr %p desc_type %d\n", ptr, desc_type);
}
ptr += desc_len;
len -= desc_len;
@@ -485,7 +483,7 @@ static int usb_handle_device(struct usb_dev *dev, struct usb_dev_config_descr *c
return true;
}
-int setup_new_device(struct usb_dev *dev, unsigned int port)
+int usb_setup_new_device(struct usb_dev *dev, unsigned int port)
{
struct usb_dev_descr descr;
struct usb_dev_config_descr cfg;
@@ -552,35 +550,6 @@ int setup_new_device(struct usb_dev *dev, unsigned int port)
if (!usb_handle_device(dev, &cfg, data, len))
goto fail_mem_free;
- switch (usb_get_intf_class(dev->class)) {
- case 3:
- dprintf("HID found %06X\n", dev->class);
- slof_usb_handle(dev);
- break;
- case 8:
- dprintf("MASS STORAGE found %d %06X\n", dev->intf_num,
- dev->class);
- if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */
- printf("Device not supported %06X\n", dev->class);
- goto fail_mem_free;
- }
-
- if (!usb_msc_reset(dev)) {
- printf("%s: bulk reset failed\n", __func__);
- goto fail_mem_free;
- }
- SLOF_msleep(100);
- slof_usb_handle(dev);
- break;
- case 9:
- dprintf("HUB found\n");
- slof_usb_handle(dev);
- break;
- default:
- printf("USB Interface class -%x- Not supported\n", dev->class);
- break;
- }
-
SLOF_dma_free(data, len);
return true;
fail_mem_free:
diff --git a/qemu/roms/SLOF/lib/libusb/usb-core.h b/qemu/roms/SLOF/lib/libusb/usb-core.h
index 7441979e9..a35df3485 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-core.h
+++ b/qemu/roms/SLOF/lib/libusb/usb-core.h
@@ -261,6 +261,8 @@ struct usb_hcd_ops {
unsigned int usb_type;
};
+#define usb_get_intf_class(x) ((x & 0x00FF0000) >> 16)
+
extern void usb_hcd_register(struct usb_hcd_ops *ops);
extern struct usb_pipe *usb_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
char *buf, size_t len);
@@ -269,11 +271,12 @@ extern int usb_poll_intr(struct usb_pipe *pipe, uint8_t *buf);
extern int usb_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *data);
extern struct usb_dev *usb_devpool_get(void);
extern void usb_devpool_put(struct usb_dev *);
-extern int setup_new_device(struct usb_dev *dev, unsigned int port);
-extern int slof_usb_handle(struct usb_dev *dev);
+extern int usb_setup_new_device(struct usb_dev *dev, unsigned int port);
+extern void usb_slof_populate_new_device(struct usb_dev *dev);
extern int usb_dev_populate_pipe(struct usb_dev *dev, struct usb_ep_descr *ep,
void *buf, size_t len);
extern int usb_hid_kbd_init(struct usb_dev *dev);
extern int usb_hid_kbd_exit(struct usb_dev *dev);
+extern int usb_msc_reset(struct usb_dev *dev);
extern void usb_msc_resetrecovery(struct usb_dev *dev);
#endif
diff --git a/qemu/roms/SLOF/lib/libusb/usb-ehci.c b/qemu/roms/SLOF/lib/libusb/usb-ehci.c
index 4cca0da15..60af9e101 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-ehci.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-ehci.c
@@ -79,7 +79,9 @@ static int ehci_hub_check_ports(struct ehci_hcd *ehcd)
dprintf("usb-ehci: allocated device %p\n", dev);
dev->hcidev = ehcd->hcidev;
dev->speed = USB_HIGH_SPEED; /* TODO: Check for Low/Full speed device */
- if (!setup_new_device(dev, i))
+ if (usb_setup_new_device(dev, i))
+ usb_slof_populate_new_device(dev);
+ else
printf("usb-ehci: unable to setup device on port %d\n", i);
}
}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-hid.c b/qemu/roms/SLOF/lib/libusb/usb-hid.c
index f0cab8a69..ac6616aba 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-hid.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-hid.c
@@ -28,6 +28,10 @@
#define HID_REQ_SET_IDLE 0x0A
#define HID_REQ_SET_PROTOCOL 0x0B
+//key position for latin letters
+#define KEYP_LATIN_A 4
+#define KEYP_LATIN_Z 29
+
//#define KEY_DEBUG
/* HID SPEC - 7.2.6 Set_Protocol Request */
@@ -83,6 +87,8 @@ uint8_t set_leds;
const uint8_t *key_std = NULL;
const uint8_t *key_std_shift = NULL;
+uint8_t ctrl; /* modifiers */
+
/**
* read character from Keyboard-Buffer
*
@@ -111,6 +117,16 @@ static void write_key(uint8_t key)
}
/**
+ * Checks if keypos is a latin key
+ * @param keypos
+ * @return -
+ */
+static bool is_latin(uint8_t keypos)
+{
+ return keypos >= KEYP_LATIN_A && keypos <= KEYP_LATIN_Z;
+}
+
+/**
* Convert keyboard usage-ID to ANSI-Code
*
* @param Ctrl=Modifier Byte
@@ -120,22 +136,24 @@ static void write_key(uint8_t key)
static void get_char(uint8_t ctrl, uint8_t keypos)
{
uint8_t ch;
+ bool caps = false;
#ifdef KEY_DEBUG
printf("pos %02X\n", keypos);
#endif
if (set_leds & LED_CAPS_LOCK) /* is CAPS Lock set ? */
- ctrl |= MODIFIER_SHIFT; /* simulate shift */
+ caps = true;
- if (ctrl == 0) {
+ /* caps is a shift only for latin chars */
+ if ((!caps && ctrl == 0) || (caps && !is_latin(keypos))) {
ch = key_std[keypos];
if (ch != 0)
write_key(ch);
return;
}
- if (ctrl & MODIFIER_SHIFT) {
+ if ((ctrl & MODIFIER_SHIFT) || caps) {
ch = key_std_shift[keypos];
if (ch != 0)
write_key(ch);
@@ -187,36 +205,38 @@ static void check_key_code(uint8_t *buf)
set_leds ^= LED_CAPS_LOCK;
break;
+ case 0x36: /*Shift pressed*/
+ ctrl |= MODIFIER_SHIFT;
+ break;
+ case 0xb6: /*Shift unpressed*/
+ ctrl &= ~MODIFIER_SHIFT;
+ break;
case 0x3a: /* F1 */
write_key(0x1b);
write_key(0x5b);
- write_key(0x31);
- write_key(0x31);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x50);
break;
case 0x3b: /* F2 */
write_key(0x1b);
write_key(0x5b);
- write_key(0x31);
- write_key(0x32);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x51);
break;
case 0x3c:
write_key(0x1b); /* F3 */
write_key(0x5b);
- write_key(0x31);
- write_key(0x33);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x52);
break;
case 0x3d:
write_key(0x1b); /* F4 */
write_key(0x5b);
- write_key(0x31);
- write_key(0x34);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x53);
break;
case 0x3e:
@@ -254,7 +274,7 @@ static void check_key_code(uint8_t *buf)
case 0x42:
write_key(0x1b); /* F9 */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x30);
write_key(0x7e);
break;
@@ -262,7 +282,7 @@ static void check_key_code(uint8_t *buf)
case 0x43:
write_key(0x1b); /* F10 */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x31);
write_key(0x7e);
break;
@@ -270,7 +290,7 @@ static void check_key_code(uint8_t *buf)
case 0x44:
write_key(0x1b); /* F11 */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x33);
write_key(0x7e);
break;
@@ -278,7 +298,7 @@ static void check_key_code(uint8_t *buf)
case 0x45:
write_key(0x1b); /* F12 */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x34);
write_key(0x7e);
break;
@@ -290,36 +310,34 @@ static void check_key_code(uint8_t *buf)
case 0x49:
write_key(0x1b); /* INS */
write_key(0x5b);
- write_key(0x31);
+ write_key(0x32);
write_key(0x7e);
break;
case 0x4a:
write_key(0x1b); /* HOME */
- write_key(0x5b);
- write_key(0x32);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x48);
break;
case 0x4b:
write_key(0x1b); /* PgUp */
write_key(0x5b);
- write_key(0x33);
+ write_key(0x35);
write_key(0x7e);
break;
case 0x4c:
write_key(0x1b); /* DEL */
write_key(0x5b);
- write_key(0x34);
+ write_key(0x33);
write_key(0x7e);
break;
case 0x4d:
write_key(0x1b); /* END */
- write_key(0x5b);
- write_key(0x35);
- write_key(0x7e);
+ write_key(0x4f);
+ write_key(0x46);
break;
case 0x4e:
@@ -443,11 +461,8 @@ unsigned char usb_key_available(void *dev)
unsigned char usb_read_keyb(void *vdev)
{
- if (!vdev)
- return false;
-
- while (usb_poll_key(vdev)) {
- /* loop for all pending keys */
- }
- return read_key();
+ if (usb_key_available(vdev))
+ return read_key();
+ else
+ return 0;
}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-hub.c b/qemu/roms/SLOF/lib/libusb/usb-hub.c
index 7059cd019..bb8a30915 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-hub.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-hub.c
@@ -175,7 +175,9 @@ unsigned int usb_hub_init(void *hubdev)
newdev = usb_devpool_get();
dprintf("usb-hub: allocated device %p\n", newdev);
newdev->hcidev = dev->hcidev;
- if (!setup_new_device(newdev, i))
+ if (usb_setup_new_device(newdev, i))
+ usb_slof_populate_new_device(newdev);
+ else
printf("usb-hub: unable to setup device on port %d\n", i);
}
}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-ohci.c b/qemu/roms/SLOF/lib/libusb/usb-ohci.c
index 0e8400481..d06c754d1 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-ohci.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-ohci.c
@@ -192,7 +192,9 @@ static void ohci_hub_check_ports(struct ohci_hcd *ohcd)
dev = usb_devpool_get();
dprintf("usb-ohci: Device reset, setting up %p\n", dev);
dev->hcidev = ohcd->hcidev;
- if (!setup_new_device(dev, i))
+ if (usb_setup_new_device(dev, i))
+ usb_slof_populate_new_device(dev);
+ else
printf("usb-ohci: unable to setup device on port %d\n", i);
}
if (port_status & RH_PS_PESC) {
@@ -252,7 +254,7 @@ static int ohci_alloc_pipe_pool(struct ohci_hcd *ohcd)
return false;
ohcd->pool_phys = opipe_phys = SLOF_dma_map_in(opipe, OHCI_PIPE_POOL_SIZE, true);
- dprintf("usb-ohci: %s opipe %x, opipe_phys %x size %d count %d\n",
+ dprintf("usb-ohci: %s opipe %p, opipe_phys %lx size %ld count %d\n",
__func__, opipe, opipe_phys, sizeof(*opipe), count);
/* Although an array, link them*/
for (i = 0, curr = opipe, prev = NULL; i < count; i++, curr++) {
@@ -446,7 +448,7 @@ again:
/* Interrupt is there, read from done_head pointer */
td_phys = (struct ohci_td *)(uint64_t) le32_to_cpu(hcca->done_head);
if (!td_phys) {
- dprintf("Again td_phys null %ld\n");
+ dprintf("Again td_phys null\n");
goto again;
}
hcca->done_head = 0;
@@ -553,7 +555,7 @@ static int ohci_send_ctrl(struct usb_pipe *pipe, struct usb_dev_req *req, void *
attr = EDA_FADDR(pipe->dev->addr) | EDA_MPS(pipe->mps) | EDA_SKIP;
ohci_fill_ed(ed, PTR_U32(td_phys), td_next, attr, 0);
ed->tailp = 0; /* HACK */
- dprintf("usb-ohci: %s - td_start %x td_end %x req %x\n", __func__,
+ dprintf("usb-ohci: %s - td_start %p td_end %lx req %lx\n", __func__,
td_phys, td_next, req_phys);
mb();
ed->attr &= cpu_to_le32(~EDA_SKIP);
@@ -642,7 +644,7 @@ static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr,
td = tds = (struct ohci_td *) td_ptr;
td_phys = (long)td_phys_ptr;
- dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %p\n",
+ dprintf("usb-ohci: %s pipe %p data_phys %p len %d DIR_IN %d td %p td_phys %lx\n",
__func__, pipe, data_phys, datalen, dir, td, td_phys);
if (!tds) {
@@ -672,7 +674,7 @@ static int ohci_transfer_bulk(struct usb_pipe *pipe, void *td_ptr,
| EDA_SKIP | pipe->dev->speed | EDA_EP(pipe->epno);
td_next = ohci_get_td_phys(td, tds, td_phys);
ohci_fill_ed(ed, td_phys, td_next, attr, 0);
- dprintf("usb-ohci: %s - tds %p td %p\n", __func__, td_phys, td_next);
+ dprintf("usb-ohci: %s - tds %lx td %lx\n", __func__, td_phys, td_next);
mb();
ed->attr &= cpu_to_le32(~EDA_SKIP);
@@ -778,7 +780,7 @@ static int ohci_get_pipe_intr(struct usb_pipe *pipe, struct ohci_hcd *ohcd,
td->attr = cpu_to_le32(TDA_DP_IN | TDA_ROUNDING | TDA_CC);
td->next_td = cpu_to_le32(td_next);
td->be = cpu_to_le32(PTR_U32(ptr) + mps - 1);
- dprintf("td %x td++ %x ptr %x be %x\n",
+ dprintf("td %p td++ %x ptr %p be %x\n",
td, le32_to_cpu(td->next_td),
ptr, (PTR_U32(ptr) + mps - 1));
}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-slof.c b/qemu/roms/SLOF/lib/libusb/usb-slof.c
index de841f0fb..ff070559a 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-slof.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-slof.c
@@ -26,7 +26,7 @@
#define dprintf(_x ...)
#endif
-int slof_usb_handle(struct usb_dev *dev)
+static int slof_usb_handle(struct usb_dev *dev)
{
struct slof_usb_dev sdev;
sdev.port = dev->port;
@@ -59,3 +59,35 @@ int slof_usb_handle(struct usb_dev *dev)
}
return true;
}
+
+void usb_slof_populate_new_device(struct usb_dev *dev)
+{
+ switch (usb_get_intf_class(dev->class)) {
+ case 3:
+ dprintf("HID found %06X\n", dev->class);
+ slof_usb_handle(dev);
+ break;
+ case 8:
+ dprintf("MASS STORAGE found %d %06X\n", dev->intf_num,
+ dev->class);
+ if ((dev->class & 0x50) != 0x50) { /* Bulk-only supported */
+ printf("Device not supported %06X\n", dev->class);
+ break;
+ }
+
+ if (!usb_msc_reset(dev)) {
+ printf("%s: bulk reset failed\n", __func__);
+ break;
+ }
+ SLOF_msleep(100);
+ slof_usb_handle(dev);
+ break;
+ case 9:
+ dprintf("HUB found\n");
+ slof_usb_handle(dev);
+ break;
+ default:
+ printf("USB Interface class -%x- Not supported\n", dev->class);
+ break;
+ }
+}
diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.c b/qemu/roms/SLOF/lib/libusb/usb-xhci.c
index 0c3d6e47f..858cd12f9 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-xhci.c
+++ b/qemu/roms/SLOF/lib/libusb/usb-xhci.c
@@ -225,11 +225,11 @@ static void xhci_handle_cmd_completion(struct xhci_hcd *xhcd,
xhcd->slot_id = 0;
}
-static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
- uint32_t event_type)
+static uint64_t xhci_poll_event(struct xhci_hcd *xhcd,
+ uint32_t event_type)
{
struct xhci_event_trb *event;
- uint64_t val;
+ uint64_t val, retval = 0;
uint32_t flags, time;
int index;
@@ -244,7 +244,7 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
mb();
flags = le32_to_cpu(event->flags);
if (time < SLOF_GetTimer())
- return NULL;
+ return 0;
}
mb();
@@ -273,6 +273,7 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
break;
}
xhcd->ering.deq = (uint64_t) (event + 1);
+ retval = le64_to_cpu(event->addr);
event->addr = 0;
event->status = 0;
@@ -289,7 +290,11 @@ static struct xhci_event_trb *xhci_poll_event(struct xhci_hcd *xhcd,
dprintf("Update start %x deq %x index %d\n",
xhcd->ering.trbs_dma, val, index/sizeof(*event));
write_reg64(&xhcd->run_regs->irs[0].erdp, val);
- return event;
+
+ if (retval == 0)
+ return (uint64_t)event;
+ else
+ return retval;
}
static void xhci_send_cmd(struct xhci_hcd *xhcd, uint32_t field1,
@@ -388,10 +393,12 @@ static void xhci_init_seg(struct xhci_seg *seg, uint32_t size, uint32_t type)
seg->deq = (uint64_t)seg->trbs;
memset((void *)seg->trbs, 0, size);
- link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1);
- link->addr = cpu_to_le64(seg->trbs_dma);
- link->field2 = 0;
- link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK));
+ if (type != TYPE_EVENT) {
+ link =(struct xhci_link_trb *) (seg->trbs + seg->size - 1);
+ link->addr = cpu_to_le64(seg->trbs_dma);
+ link->field2 = 0;
+ link->field3 = cpu_to_le32(0x1 | TRB_CMD_TYPE(TRB_LINK));
+ }
return;
}
@@ -601,8 +608,10 @@ static bool xhci_alloc_dev(struct xhci_hcd *xhcd, uint32_t slot_id, uint32_t por
dev->port = newport;
dev->priv = xdev;
xdev->dev = dev;
- if (setup_new_device(dev, newport))
+ if (usb_setup_new_device(dev, newport)) {
+ usb_slof_populate_new_device(dev);
return true;
+ }
xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE);
fail_control_seg:
@@ -616,6 +625,7 @@ static void xhci_free_dev(struct xhci_dev *xdev)
{
xhci_free_seg(&xdev->bulk_in, XHCI_DATA_TRBS_SIZE);
xhci_free_seg(&xdev->bulk_out, XHCI_DATA_TRBS_SIZE);
+ xhci_free_seg(&xdev->intr, XHCI_INTR_TRBS_SIZE);
xhci_free_seg(&xdev->control, XHCI_CONTROL_TRBS_SIZE);
xhci_free_ctx(&xdev->in_ctx, XHCI_CTX_BUF_SIZE);
xhci_free_ctx(&xdev->out_ctx, XHCI_CTX_BUF_SIZE);
@@ -637,7 +647,25 @@ static bool usb3_dev_init(struct xhci_hcd *xhcd, uint32_t port)
return true;
}
-static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
+static int xhci_device_present(uint32_t portsc, uint32_t usb_ver)
+{
+ if (usb_ver == USB_XHCI) {
+ /* Device present and enabled state */
+ if ((portsc & PORTSC_CCS) &&
+ (portsc & PORTSC_PP) &&
+ (portsc & PORTSC_PED)) {
+ return true;
+ }
+ } else if (usb_ver == USB_EHCI) {
+ /* Device present and in disabled state */
+ if ((portsc & PORTSC_CCS) && (portsc & PORTSC_CSC))
+ return true;
+ }
+ return false;
+}
+
+static int xhci_port_scan(struct xhci_hcd *xhcd,
+ uint32_t usb_ver)
{
uint32_t num_ports, portsc, i;
struct xhci_op_regs *op;
@@ -645,7 +673,7 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
struct xhci_cap_regs *cap;
uint32_t xecp_off;
uint32_t *xecp_addr, *base;
- uint32_t port_off = 1, port_cnt;
+ uint32_t port_off = 0, port_cnt;
dprintf("enter\n");
@@ -658,14 +686,14 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
base = (uint32_t *)cap;
while (xecp_off > 0) {
xecp_addr = base + xecp_off;
- dprintf(stderr, "xecp_off %d %p %p \n", xecp_off, base, xecp_addr);
+ dprintf("xecp_off %d %p %p \n", xecp_off, base, xecp_addr);
if (XHCI_XECP_CAP_ID(read_reg32(xecp_addr)) == XHCI_XECP_CAP_SP &&
- XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == 3 &&
+ XHCI_XECP_CAP_SP_MJ(read_reg32(xecp_addr)) == usb_ver &&
XHCI_XECP_CAP_SP_MN(read_reg32(xecp_addr)) == 0) {
port_cnt = XHCI_XECP_CAP_SP_PC(read_reg32(xecp_addr + 2));
port_off = XHCI_XECP_CAP_SP_PO(read_reg32(xecp_addr + 2));
- dprintf(stderr, "PortCount %d Portoffset %d\n", port_cnt, port_off);
+ dprintf("PortCount %d Portoffset %d\n", port_cnt, port_off);
}
base = xecp_addr;
xecp_off = XHCI_XECP_NEXT_PTR(read_reg32(xecp_addr));
@@ -675,10 +703,8 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
for (i = (port_off - 1); i < (port_off + port_cnt - 1); i++) {
prs = &op->prs[i];
portsc = read_reg32(&prs->portsc);
- if ((portsc & PORTSC_CCS) &&
- (portsc & PORTSC_PP) &&
- (portsc & PORTSC_PED)) {
- /* Device present and enabled */
+ if (xhci_device_present(portsc, usb_ver)) {
+ /* Device present */
dprintf("Device present on port %d\n", i);
/* Reset the port */
portsc = read_reg32(&prs->portsc);
@@ -701,6 +727,11 @@ static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
return true;
}
+static int xhci_hub_check_ports(struct xhci_hcd *xhcd)
+{
+ return xhci_port_scan(xhcd, USB_XHCI) | xhci_port_scan(xhcd, USB_EHCI);
+}
+
static bool xhci_hcd_init(struct xhci_hcd *xhcd)
{
struct xhci_op_regs *op;
@@ -868,6 +899,18 @@ static bool xhci_hcd_exit(struct xhci_hcd *xhcd)
SLOF_dma_map_out(xhcd->dcbaap_dma, (void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
SLOF_dma_free((void *)xhcd->dcbaap, XHCI_DCBAAP_MAX_SIZE);
}
+
+ /*
+ * QEMU implementation of XHCI doesn't implement halt
+ * properly. It basically says that it's halted immediately
+ * but doesn't actually terminate ongoing activities and
+ * DMAs. This needs to be fixed in QEMU.
+ *
+ * For now, wait for 50ms grace time till qemu stops using
+ * this device.
+ */
+ SLOF_msleep(50);
+
return true;
}
@@ -1079,18 +1122,17 @@ static inline struct xhci_seg *xhci_pipe_get_seg(struct usb_pipe *pipe)
static inline void *xhci_get_trb(struct xhci_seg *seg)
{
uint64_t val, enq;
- uint32_t size;
+ int index;
struct xhci_link_trb *link;
enq = val = seg->enq;
val = val + XHCI_TRB_SIZE;
- size = seg->size * XHCI_TRB_SIZE;
- /* TRBs being a cyclic buffer, here we cycle back to beginning. */
- if ((val % size) == 0) {
+ index = (enq - (uint64_t)seg->trbs) / XHCI_TRB_SIZE + 1;
+ dprintf("%s: enq %llx, val %llx %x\n", __func__, enq, val, index);
+ /* TRBs being a cyclic buffer, here we cycle back to beginning. */
+ if (index == (seg->size - 1)) {
+ dprintf("%s: rounding \n", __func__);
seg->enq = (uint64_t)seg->trbs;
- enq = seg->enq;
- seg->enq = seg->enq + XHCI_TRB_SIZE;
- val = 0;
seg->cycle_state ^= seg->cycle_state;
link = (struct xhci_link_trb *) (seg->trbs + seg->size - 1);
link->addr = cpu_to_le64(seg->trbs_dma);
@@ -1105,6 +1147,12 @@ static inline void *xhci_get_trb(struct xhci_seg *seg)
return (void *)enq;
}
+static uint64_t xhci_get_trb_phys(struct xhci_seg *seg, uint64_t trb)
+{
+ return seg->trbs_dma + (trb - (uint64_t)seg->trbs);
+}
+
+static int usb_kb = false;
static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
void *data, int datalen)
{
@@ -1114,7 +1162,8 @@ static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
struct xhci_transfer_trb *trb;
struct xhci_db_regs *dbr;
int ret = true;
- uint32_t slot_id, epno;
+ uint32_t slot_id, epno, time;
+ uint64_t trb_phys, event_phys;
if (!pipe->dev || !pipe->dev->hcidev) {
dprintf(" NULL pointer\n");
@@ -1139,13 +1188,26 @@ static int xhci_transfer_bulk(struct usb_pipe *pipe, void *td, void *td_phys,
}
trb = xhci_get_trb(seg);
+ trb_phys = xhci_get_trb_phys(seg, (uint64_t)trb);
fill_normal_trb(trb, (void *)data, datalen);
epno = xhci_get_epno(pipe);
write_reg32(&dbr->db[slot_id], epno);
- if (!xhci_poll_event(xhcd, 0)) {
- dprintf("Bulk failed\n");
- ret = false;
+
+ time = SLOF_GetTimer() + USB_TIMEOUT;
+ while (1) {
+ event_phys = xhci_poll_event(xhcd, 0);
+ if (event_phys == trb_phys) {
+ break;
+ } else if (event_phys == 0) { /* polling timed out */
+ ret = false;
+ break;
+ } else
+ usb_kb = true;
+
+ /* transfer timed out */
+ if (time < SLOF_GetTimer())
+ return false;
}
trb->addr = 0;
trb->len = 0;
@@ -1214,7 +1276,8 @@ static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe)
if (!seg->trbs) {
if (!xhci_alloc_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK)) {
- dprintf("Failed allocating seg\n");
+ printf("usb-xhci: allocation failed for bulk endpoint\n");
+ return;
}
} else {
xhci_init_seg(seg, XHCI_DATA_TRBS_SIZE, TYPE_BULK);
@@ -1235,6 +1298,61 @@ static void xhci_init_bulk_ep(struct usb_dev *dev, struct usb_pipe *pipe)
xpipe->seg = seg;
}
+static int xhci_get_pipe_intr(struct usb_pipe *pipe,
+ struct xhci_hcd *xhcd,
+ char *buf, size_t len)
+{
+ struct xhci_dev *xdev;
+ struct xhci_seg *seg;
+ struct xhci_pipe *xpipe;
+ struct xhci_control_ctx *ctrl;
+ struct xhci_ep_ctx *ep;
+ uint32_t x_epno, val, type;
+ struct usb_dev *dev;
+ struct xhci_transfer_trb *trb;
+
+ dev = pipe->dev;
+ if (dev->class != DEV_HID_KEYB)
+ return false;
+
+ xdev = dev->priv;
+ pipe->mps = 8;
+ seg = xhci_pipe_get_seg(pipe);
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ type = EP_INT_IN;
+ seg = &xdev->intr;
+
+ if (!seg->trbs) {
+ if (!xhci_alloc_seg(seg, XHCI_INTR_TRBS_SIZE, TYPE_BULK)) {
+ printf("usb-xhci: allocation failed for interrupt endpoint\n");
+ return false;
+ }
+ } else {
+ xhci_init_seg(seg, XHCI_EVENT_TRBS_SIZE, TYPE_BULK);
+ }
+
+ xpipe->buf = buf;
+ xpipe->buf_phys = SLOF_dma_map_in(buf, len, false);
+ xpipe->buflen = len;
+
+ ctrl = xhci_get_control_ctx(&xdev->in_ctx);
+ x_epno = xhci_get_epno(pipe);
+ ep = xhci_get_ep_ctx(&xdev->in_ctx, xdev->ctx_size, x_epno);
+ val = EP_TYPE(type) | MAX_BURST(0) | ERROR_COUNT(3) |
+ MAX_PACKET_SIZE(pipe->mps);
+ ep->field2 = cpu_to_le32(val);
+ ep->deq_addr = cpu_to_le64(seg->trbs_dma | seg->cycle_state);
+ ep->field4 = cpu_to_le32(8);
+ ctrl->a_flags = cpu_to_le32(BIT(x_epno) | 0x1);
+ ctrl->d_flags = 0;
+ xhci_configure_ep(xhcd, xdev->slot_id, xdev->in_ctx.dma_addr);
+ xpipe->seg = seg;
+
+ trb = xhci_get_trb(seg);
+ fill_normal_trb(trb, (void *)xpipe->buf_phys, pipe->mps);
+ return true;
+}
+
static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *ep, char *buf, size_t len)
{
struct xhci_hcd *xhcd;
@@ -1264,6 +1382,12 @@ static struct usb_pipe* xhci_get_pipe(struct usb_dev *dev, struct usb_ep_descr *
new->dir = (ep->bEndpointAddress & 0x80) >> 7;
new->epno = ep->bEndpointAddress & 0x0f;
+ if (new->type == USB_EP_TYPE_INTR) {
+ if (!xhci_get_pipe_intr(new, xhcd, buf, len)) {
+ printf("usb-xhci: %s alloc_intr failed %p\n",
+ __func__, new);
+ }
+ }
if (new->type == USB_EP_TYPE_BULK)
xhci_init_bulk_ep(dev, new);
@@ -1284,6 +1408,10 @@ static void xhci_put_pipe(struct usb_pipe *pipe)
if (pipe->type == USB_EP_TYPE_BULK) {
xpipe = xhci_pipe_get_xpipe(pipe);
xpipe->seg = NULL;
+ } else if (pipe->type == USB_EP_TYPE_INTR) {
+ xpipe = xhci_pipe_get_xpipe(pipe);
+ SLOF_dma_map_out(xpipe->buf_phys, xpipe->buf, xpipe->buflen);
+ xpipe->seg = NULL;
}
if (xhcd->end)
xhcd->end->next = pipe;
@@ -1298,6 +1426,51 @@ static void xhci_put_pipe(struct usb_pipe *pipe)
dprintf("usb-xhci: %s exit\n", __func__);
}
+static int xhci_poll_intr(struct usb_pipe *pipe, uint8_t *data)
+{
+ struct xhci_transfer_trb *trb;
+ struct xhci_seg *seg;
+ struct xhci_pipe *xpipe;
+ struct xhci_dev *xdev;
+ struct xhci_hcd *xhcd;
+ struct xhci_db_regs *dbr;
+ uint32_t x_epno;
+ uint8_t *buf, ret = 1;
+
+ if (!pipe || !pipe->dev || !pipe->dev->hcidev)
+ return 0;
+ xdev = pipe->dev->priv;
+ xhcd = (struct xhci_hcd *)pipe->dev->hcidev->priv;
+ x_epno = xhci_get_epno(pipe);
+ seg = xhci_pipe_get_seg(pipe);
+ xpipe = xhci_pipe_get_xpipe(pipe);
+
+ if (usb_kb == true) {
+ /* This event was consumed by bulk transfer */
+ usb_kb = false;
+ goto skip_poll;
+ }
+ buf = xpipe->buf;
+ memset(buf, 0, 8);
+
+ mb();
+ /* Ring the doorbell - x_epno */
+ dbr = xhcd->db_regs;
+ write_reg32(&dbr->db[xdev->slot_id], x_epno);
+ if (!xhci_poll_event(xhcd, 0)) {
+ printf("poll intr failed\n");
+ return 0;
+ }
+ mb();
+ memcpy(data, buf, 8);
+
+skip_poll:
+ trb = xhci_get_trb(seg);
+ fill_normal_trb(trb, (void *)xpipe->buf_phys, pipe->mps);
+ mb();
+ return ret;
+}
+
struct usb_hcd_ops xhci_ops = {
.name = "xhci-hcd",
.init = xhci_init,
@@ -1305,6 +1478,7 @@ struct usb_hcd_ops xhci_ops = {
.usb_type = USB_XHCI,
.get_pipe = xhci_get_pipe,
.put_pipe = xhci_put_pipe,
+ .poll_intr = xhci_poll_intr,
.send_ctrl = xhci_send_ctrl,
.transfer_bulk = xhci_transfer_bulk,
.next = NULL,
diff --git a/qemu/roms/SLOF/lib/libusb/usb-xhci.h b/qemu/roms/SLOF/lib/libusb/usb-xhci.h
index faeb07ead..3fc7e7889 100644
--- a/qemu/roms/SLOF/lib/libusb/usb-xhci.h
+++ b/qemu/roms/SLOF/lib/libusb/usb-xhci.h
@@ -266,6 +266,7 @@ struct xhci_seg {
#define XHCI_EVENT_TRBS_SIZE 4096
#define XHCI_CONTROL_TRBS_SIZE 4096
#define XHCI_DATA_TRBS_SIZE 4096
+#define XHCI_INTR_TRBS_SIZE 4096
#define XHCI_ERST_NUM_SEGS 1
#define XHCI_MAX_BULK_SIZE 0xF000
@@ -349,6 +350,7 @@ struct xhci_dev {
struct xhci_ctx in_ctx;
struct xhci_ctx out_ctx;
struct xhci_seg control;
+ struct xhci_seg intr;
struct xhci_seg bulk_in;
struct xhci_seg bulk_out;
uint32_t ctx_size;
@@ -381,6 +383,9 @@ struct xhci_hcd {
struct xhci_pipe {
struct usb_pipe pipe;
struct xhci_seg *seg;
+ void *buf;
+ long buf_phys;
+ uint32_t buflen;
};
#endif /* USB_XHCI_H */
diff --git a/qemu/roms/SLOF/lib/libvirtio/p9.c b/qemu/roms/SLOF/lib/libvirtio/p9.c
index a55662994..0e5953031 100644
--- a/qemu/roms/SLOF/lib/libvirtio/p9.c
+++ b/qemu/roms/SLOF/lib/libvirtio/p9.c
@@ -143,7 +143,7 @@ int p9_transaction(p9_connection_t *connection)
{
int rc;
int tx_size = GET_SIZE;
- int rx_size = connection->message_size;
+ uint32_t rx_size = connection->message_size;
if (transact == NULL) {
return P9_NO_TRANSPORT;
diff --git a/qemu/roms/SLOF/lib/libvirtio/p9.h b/qemu/roms/SLOF/lib/libvirtio/p9.h
index 7df9ef441..3a35e80ed 100644
--- a/qemu/roms/SLOF/lib/libvirtio/p9.h
+++ b/qemu/roms/SLOF/lib/libvirtio/p9.h
@@ -33,7 +33,7 @@
#define P9_PARTIAL_WALK 1
typedef int (*p9_transact_t)(void *opaque, uint8_t *tx, int tx_size,
- uint8_t *rx, int *rx_size);
+ uint8_t *rx, uint32_t *rx_size);
typedef struct {
uint32_t message_size;
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c
index 5a5fd01da..fc5db9154 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.c
@@ -19,6 +19,7 @@
#include "virtio-9p.h"
#include "p9.h"
+static struct vqs vq;
/**
* Notes for 9P Server config:
@@ -86,7 +87,7 @@ static void dprint_buffer(const char *name, uint8_t *buffer, int length)
* @return 0 = success, -ve = error.
*/
static int virtio_9p_transact(void *opaque, uint8_t *tx, int tx_size, uint8_t *rx,
- int *rx_size)
+ uint32_t *rx_size)
{
struct virtio_device *dev = opaque;
struct vring_desc *desc;
@@ -165,6 +166,7 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
int buf_size)
{
struct vring_avail *vq_avail;
+ int status = VIRTIO_STAT_ACKNOWLEDGE;
/* Check for double open */
if (__buf_size)
@@ -174,28 +176,31 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
dprintf("%s : device at %p\n", __func__, dev->base);
dprintf("%s : type is %04x\n", __func__, dev->type);
- /* Reset device */
- // XXX That will clear the virtq base. We need to move
- // initializing it to here anyway
- //
- // virtio_reset_device(dev);
+ /* Keep it disabled until the driver is 1.0 capable */
+ dev->is_modern = false;
+
+ virtio_reset_device(dev);
/* Acknowledge device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+ virtio_set_status(dev, status);
/* Tell HV that we know how to drive the device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER);
+ status |= VIRTIO_STAT_DRIVER;
+ virtio_set_status(dev, status);
/* Device specific setup - we do not support special features */
virtio_set_guest_features(dev, 0);
+ if (virtio_queue_init_vq(dev, &vq, 0))
+ goto dev_error;
+
vq_avail = virtio_get_vring_avail(dev, 0);
vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
vq_avail->idx = 0;
/* Tell HV that setup succeeded */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER
- |VIRTIO_STAT_DRIVER_OK);
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(dev, status);
/* Setup 9P library. */
p9_reg_transport(virtio_9p_transact, dev,(uint8_t *)tx_buf,
@@ -203,6 +208,12 @@ int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
dprintf("%s : complete\n", __func__);
return 0;
+
+dev_error:
+ printf("%s: failed\n", __func__);
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(dev, status);
+ return -1;
}
/**
@@ -228,7 +239,7 @@ void virtio_9p_shutdown(struct virtio_device *dev)
* @param buffer[out] Where to read the file to.
* @return +ve = amount of data read, -ve = error.
*/
-int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer)
+long virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer)
{
int rc;
uint16_t tag_len;
@@ -332,5 +343,5 @@ cleanup_connection:
dprintf("%s : complete, read %llu bytes\n", __func__, offset);
- return rc == 0 ? offset : rc;
+ return rc == 0 ? (long)offset : rc;
}
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h
index 4bf47d078..db2cf6f11 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-9p.h
@@ -26,7 +26,7 @@ typedef struct {
int virtio_9p_init(struct virtio_device *dev, void *tx_buf, void *rx_buf,
int buf_size);
void virtio_9p_shutdown(struct virtio_device *dev);
-int virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer);
+long virtio_9p_load(struct virtio_device *dev, const char *file_name, uint8_t *buffer);
#endif /* VIRTIO_9P_H_ */
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c
index 826f2ea0e..07ec1048f 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.c
@@ -13,10 +13,15 @@
#include <stdio.h>
#include <cpu.h>
#include <helpers.h>
+#include <byteorder.h>
#include "virtio.h"
#include "virtio-blk.h"
+#include "virtio-internal.h"
#define DEFAULT_SECTOR_SIZE 512
+#define DRIVER_FEATURE_SUPPORT (VIRTIO_BLK_F_BLK_SIZE | VIRTIO_F_VERSION_1)
+
+static struct vqs vq;
/**
* Initialize virtio-block device.
@@ -27,39 +32,54 @@ virtioblk_init(struct virtio_device *dev)
{
struct vring_avail *vq_avail;
int blk_size = DEFAULT_SECTOR_SIZE;
- int features;
+ uint64_t features;
+ int status = VIRTIO_STAT_ACKNOWLEDGE;
/* Reset device */
- // XXX That will clear the virtq base. We need to move
- // initializing it to here anyway
- //
- // virtio_reset_device(dev);
+ virtio_reset_device(dev);
/* Acknowledge device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+ virtio_set_status(dev, status);
/* Tell HV that we know how to drive the device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
+ status |= VIRTIO_STAT_DRIVER;
+ virtio_set_status(dev, status);
+
+ if (dev->is_modern) {
+ /* Negotiate features and sets FEATURES_OK if successful */
+ if (virtio_negotiate_guest_features(dev, DRIVER_FEATURE_SUPPORT))
+ goto dev_error;
+
+ virtio_get_status(dev, &status);
+ } else {
+ /* Device specific setup - we support F_BLK_SIZE */
+ virtio_set_guest_features(dev, VIRTIO_BLK_F_BLK_SIZE);
+ }
- /* Device specific setup - we support F_BLK_SIZE */
- virtio_set_guest_features(dev, VIRTIO_BLK_F_BLK_SIZE);
+ if (virtio_queue_init_vq(dev, &vq, 0))
+ goto dev_error;
vq_avail = virtio_get_vring_avail(dev, 0);
- vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
+ vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
vq_avail->idx = 0;
/* Tell HV that setup succeeded */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
- |VIRTIO_STAT_DRIVER_OK);
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(dev, status);
- virtio_get_host_features(dev, &features);
+ features = virtio_get_host_features(dev);
if (features & VIRTIO_BLK_F_BLK_SIZE) {
blk_size = virtio_get_config(dev,
- offset_of(struct virtio_blk_cfg, blk_size),
- sizeof(blk_size));
+ offset_of(struct virtio_blk_cfg, blk_size),
+ sizeof(blk_size));
}
return blk_size;
+dev_error:
+ printf("%s: failed\n", __func__);
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(dev, status);
+ return 0;
}
@@ -77,6 +97,19 @@ virtioblk_shutdown(struct virtio_device *dev)
virtio_reset_device(dev);
}
+static void fill_blk_hdr(struct virtio_blk_req *blkhdr, bool is_modern,
+ uint32_t type, uint32_t ioprio, uint32_t sector)
+{
+ if (is_modern) {
+ blkhdr->type = cpu_to_le32(type);
+ blkhdr->ioprio = cpu_to_le32(ioprio);
+ blkhdr->sector = cpu_to_le64(sector);
+ } else {
+ blkhdr->type = type;
+ blkhdr->ioprio = ioprio;
+ blkhdr->sector = sector;
+ }
+}
/**
* Read blocks
@@ -87,7 +120,7 @@ virtioblk_shutdown(struct virtio_device *dev)
* @return number of blocks that have been read successfully
*/
int
-virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
+virtioblk_read(struct virtio_device *dev, char *buf, uint64_t blocknum, long cnt)
{
struct vring_desc *desc;
int id;
@@ -100,7 +133,7 @@ virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
struct vring_used *vq_used; /* "Used" vring */
volatile uint8_t status = -1;
volatile uint16_t *current_used_idx;
- uint16_t last_used_idx;
+ uint16_t last_used_idx, avail_idx;
int blk_size = DEFAULT_SECTOR_SIZE;
//printf("virtioblk_read: dev=%p buf=%p blocknum=%li count=%li\n",
@@ -128,41 +161,38 @@ virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt)
vq_avail = virtio_get_vring_avail(dev, 0);
vq_used = virtio_get_vring_used(dev, 0);
+ avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx);
+
last_used_idx = vq_used->idx;
current_used_idx = &vq_used->idx;
/* Set up header */
- blkhdr.type = VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER;
- blkhdr.ioprio = 1;
- blkhdr.sector = blocknum * blk_size / DEFAULT_SECTOR_SIZE;
+ fill_blk_hdr(&blkhdr, dev->is_modern, VIRTIO_BLK_T_IN | VIRTIO_BLK_T_BARRIER,
+ 1, blocknum * blk_size / DEFAULT_SECTOR_SIZE);
/* Determine descriptor index */
- id = (vq_avail->idx * 3) % vq_size;
+ id = (avail_idx * 3) % vq_size;
/* Set up virtqueue descriptor for header */
desc = &vq_desc[id];
- desc->addr = (uint64_t)&blkhdr;
- desc->len = sizeof(struct virtio_blk_req);
- desc->flags = VRING_DESC_F_NEXT;
- desc->next = (id + 1) % vq_size;
+ virtio_fill_desc(desc, dev->is_modern, (uint64_t)&blkhdr,
+ sizeof(struct virtio_blk_req),
+ VRING_DESC_F_NEXT, (id + 1) % vq_size);
/* Set up virtqueue descriptor for data */
desc = &vq_desc[(id + 1) % vq_size];
- desc->addr = (uint64_t)buf;
- desc->len = cnt * blk_size;
- desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
- desc->next = (id + 2) % vq_size;
+ virtio_fill_desc(desc, dev->is_modern, (uint64_t)buf, cnt * blk_size,
+ VRING_DESC_F_NEXT | VRING_DESC_F_WRITE,
+ (id + 2) % vq_size);
/* Set up virtqueue descriptor for status */
desc = &vq_desc[(id + 2) % vq_size];
- desc->addr = (uint64_t)&status;
- desc->len = 1;
- desc->flags = VRING_DESC_F_WRITE;
- desc->next = 0;
+ virtio_fill_desc(desc, dev->is_modern, (uint64_t)&status, 1,
+ VRING_DESC_F_WRITE, 0);
- vq_avail->ring[vq_avail->idx % vq_size] = id;
+ vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16 (dev, id);
mb();
- vq_avail->idx += 1;
+ vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
/* Tell HV that the queue is ready */
virtio_queue_notify(dev, 0);
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h
index ac8bf2896..2e7b5926b 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-blk.h
@@ -55,6 +55,6 @@ struct virtio_blk_req {
extern int virtioblk_init(struct virtio_device *dev);
extern void virtioblk_shutdown(struct virtio_device *dev);
-extern int virtioblk_read(struct virtio_device *dev, char *buf, long blocknum, long cnt);
+extern int virtioblk_read(struct virtio_device *dev, char *buf, uint64_t blocknum, long cnt);
#endif /* _VIRTIO_BLK_H */
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-internal.h b/qemu/roms/SLOF/lib/libvirtio/virtio-internal.h
new file mode 100644
index 000000000..08662eab7
--- /dev/null
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-internal.h
@@ -0,0 +1,48 @@
+/******************************************************************************
+ * Copyright (c) 2016 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 _LIBVIRTIO_INTERNAL_H
+#define _LIBVIRTIO_INTERNAL_H
+
+#include <byteorder.h>
+
+static inline uint16_t virtio_cpu_to_modern16(struct virtio_device *dev, uint16_t val)
+{
+ return dev->is_modern ? cpu_to_le16(val) : val;
+}
+
+static inline uint32_t virtio_cpu_to_modern32(struct virtio_device *dev, uint32_t val)
+{
+ return dev->is_modern ? cpu_to_le32(val) : val;
+}
+
+static inline uint64_t virtio_cpu_to_modern64(struct virtio_device *dev, uint64_t val)
+{
+ return dev->is_modern ? cpu_to_le64(val) : val;
+}
+
+static inline uint16_t virtio_modern16_to_cpu(struct virtio_device *dev, uint16_t val)
+{
+ return dev->is_modern ? le16_to_cpu(val) : val;
+}
+
+static inline uint32_t virtio_modern32_to_cpu(struct virtio_device *dev, uint32_t val)
+{
+ return dev->is_modern ? le32_to_cpu(val) : val;
+}
+
+static inline uint64_t virtio_modern64_to_cpu(struct virtio_device *dev, uint64_t val)
+{
+ return dev->is_modern ? le64_to_cpu(val) : val;
+}
+
+#endif /* _LIBVIRTIO_INTERNAL_H */
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-net.c b/qemu/roms/SLOF/lib/libvirtio/virtio-net.c
index 99c19d952..fc620a201 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-net.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-net.c
@@ -26,6 +26,7 @@
#include <byteorder.h>
#include "virtio.h"
#include "virtio-net.h"
+#include "virtio-internal.h"
#undef DEBUG
//#define DEBUG
@@ -37,22 +38,13 @@
#define sync() asm volatile (" sync \n" ::: "memory")
-/* PCI virtio header offsets */
-#define VIRTIOHDR_DEVICE_FEATURES 0
-#define VIRTIOHDR_GUEST_FEATURES 4
-#define VIRTIOHDR_QUEUE_ADDRESS 8
-#define VIRTIOHDR_QUEUE_SIZE 12
-#define VIRTIOHDR_QUEUE_SELECT 14
-#define VIRTIOHDR_QUEUE_NOTIFY 16
-#define VIRTIOHDR_DEVICE_STATUS 18
-#define VIRTIOHDR_ISR_STATUS 19
-#define VIRTIOHDR_DEVICE_CONFIG 20
-#define VIRTIOHDR_MAC_ADDRESS 20
+#define DRIVER_FEATURE_SUPPORT (VIRTIO_NET_F_MAC | VIRTIO_F_VERSION_1)
struct virtio_device virtiodev;
-struct vqs vq[2]; /* Information about virtqueues */
+static struct vqs vq_rx; /* Information about receive virtqueues */
+static struct vqs vq_tx; /* Information about transmit virtqueues */
-/* See Virtio Spec, appendix C, "Device Operation" */
+/* See Virtio Spec, appendix C, "Device Operation" */
struct virtio_net_hdr {
uint8_t flags;
uint8_t gso_type;
@@ -63,6 +55,18 @@ struct virtio_net_hdr {
// uint16_t num_buffers; /* Only if VIRTIO_NET_F_MRG_RXBUF */
};
+static unsigned int net_hdr_size;
+
+struct virtio_net_hdr_v1 {
+ uint8_t flags;
+ uint8_t gso_type;
+ le16 hdr_len;
+ le16 gso_size;
+ le16 csum_start;
+ le16 csum_offset;
+ le16 num_buffers;
+};
+
static uint16_t last_rx_idx; /* Last index in RX "used" ring */
/**
@@ -72,15 +76,13 @@ static uint16_t last_rx_idx; /* Last index in RX "used" ring */
*/
static int virtionet_init_pci(struct virtio_device *dev)
{
- int i;
-
dprintf("virtionet: doing virtionet_init_pci!\n");
if (!dev)
return -1;
- virtiodev.base = dev->base;
- virtiodev.type = dev->type;
+ /* make a copy of the device structure */
+ memcpy(&virtiodev, dev, sizeof(struct virtio_device));
/* Reset device */
virtio_reset_device(&virtiodev);
@@ -90,29 +92,11 @@ static int virtionet_init_pci(struct virtio_device *dev)
* second the transmit queue, and the forth is the control queue for
* networking options.
* We are only interested in the receive and transmit queue here. */
-
- for (i=VQ_RX; i<=VQ_TX; i++) {
- /* Select ring (0=RX, 1=TX): */
- vq[i].id = i-VQ_RX;
- ci_write_16(virtiodev.base+VIRTIOHDR_QUEUE_SELECT,
- cpu_to_le16(vq[i].id));
-
- vq[i].size = le16_to_cpu(ci_read_16(virtiodev.base+VIRTIOHDR_QUEUE_SIZE));
- vq[i].desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq[i].size), 4096);
- if (!vq[i].desc) {
- printf("memory allocation failed!\n");
- return -1;
- }
- memset(vq[i].desc, 0, virtio_vring_size(vq[i].size));
- ci_write_32(virtiodev.base+VIRTIOHDR_QUEUE_ADDRESS,
- cpu_to_le32((long)vq[i].desc / 4096));
- vq[i].avail = (void*)vq[i].desc
- + vq[i].size * sizeof(struct vring_desc);
- vq[i].used = (void*)VQ_ALIGN((long)vq[i].avail
- + vq[i].size * sizeof(struct vring_avail));
-
- dprintf("%i: vq.id = %llx\nvq.size =%x\n vq.avail =%p\nvq.used=%p\n",
- i, vq[i].id, vq[i].size, vq[i].avail, vq[i].used);
+ if (virtio_queue_init_vq(dev, &vq_rx, VQ_RX) ||
+ virtio_queue_init_vq(dev, &vq_tx, VQ_TX)) {
+ virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
+ |VIRTIO_STAT_FAILED);
+ return -1;
}
/* Acknowledge device. */
@@ -129,6 +113,7 @@ static int virtionet_init_pci(struct virtio_device *dev)
static int virtionet_init(net_driver_t *driver)
{
int i;
+ int status = VIRTIO_STAT_ACKNOWLEDGE | VIRTIO_STAT_DRIVER;
dprintf("virtionet_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
driver->mac_addr[0], driver->mac_addr[1],
@@ -139,60 +124,69 @@ static int virtionet_init(net_driver_t *driver)
return 0;
/* Tell HV that we know how to drive the device. */
- virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
-
- /* Device specific setup - we do not support special features right now */
- virtio_set_guest_features(&virtiodev, 0);
+ virtio_set_status(&virtiodev, status);
+
+ /* Device specific setup */
+ if (virtiodev.is_modern) {
+ if (virtio_negotiate_guest_features(&virtiodev, DRIVER_FEATURE_SUPPORT))
+ goto dev_error;
+ net_hdr_size = sizeof(struct virtio_net_hdr_v1);
+ virtio_get_status(&virtiodev, &status);
+ } else {
+ net_hdr_size = sizeof(struct virtio_net_hdr);
+ virtio_set_guest_features(&virtiodev, 0);
+ }
/* Allocate memory for one transmit an multiple receive buffers */
- vq[VQ_RX].buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr))
+ vq_rx.buf_mem = SLOF_alloc_mem((BUFFER_ENTRY_SIZE+net_hdr_size)
* RX_QUEUE_SIZE);
- if (!vq[VQ_RX].buf_mem) {
+ if (!vq_rx.buf_mem) {
printf("virtionet: Failed to allocate buffers!\n");
- virtio_set_status(&virtiodev, VIRTIO_STAT_FAILED);
- return -1;
+ goto dev_error;
}
/* Prepare receive buffer queue */
for (i = 0; i < RX_QUEUE_SIZE; i++) {
- struct vring_desc *desc;
+ uint64_t addr = (uint64_t)vq_rx.buf_mem
+ + i * (BUFFER_ENTRY_SIZE+net_hdr_size);
+ uint32_t id = i*2;
/* Descriptor for net_hdr: */
- desc = &vq[VQ_RX].desc[i*2];
- desc->addr = (uint64_t)vq[VQ_RX].buf_mem
- + i * (BUFFER_ENTRY_SIZE+sizeof(struct virtio_net_hdr));
- desc->len = sizeof(struct virtio_net_hdr);
- desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
- desc->next = i*2+1;
+ virtio_fill_desc(&vq_rx.desc[id], virtiodev.is_modern, addr, net_hdr_size,
+ VRING_DESC_F_NEXT | VRING_DESC_F_WRITE, id + 1);
/* Descriptor for data: */
- desc = &vq[VQ_RX].desc[i*2+1];
- desc->addr = vq[VQ_RX].desc[i*2].addr + sizeof(struct virtio_net_hdr);
- desc->len = BUFFER_ENTRY_SIZE;
- desc->flags = VRING_DESC_F_WRITE;
- desc->next = 0;
+ virtio_fill_desc(&vq_rx.desc[id+1], virtiodev.is_modern, addr + net_hdr_size,
+ BUFFER_ENTRY_SIZE, VRING_DESC_F_WRITE, 0);
- vq[VQ_RX].avail->ring[i] = i*2;
+ vq_rx.avail->ring[i] = virtio_cpu_to_modern16(&virtiodev, id);
}
sync();
- vq[VQ_RX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
- vq[VQ_RX].avail->idx = RX_QUEUE_SIZE;
- last_rx_idx = vq[VQ_RX].used->idx;
+ vq_rx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, RX_QUEUE_SIZE);
+
+ last_rx_idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx);
- vq[VQ_TX].avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
- vq[VQ_TX].avail->idx = 0;
+ vq_tx.avail->flags = virtio_cpu_to_modern16(&virtiodev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_tx.avail->idx = 0;
/* Tell HV that setup succeeded */
- virtio_set_status(&virtiodev, VIRTIO_STAT_ACKNOWLEDGE
- |VIRTIO_STAT_DRIVER
- |VIRTIO_STAT_DRIVER_OK);
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(&virtiodev, status);
/* Tell HV that RX queues are ready */
virtio_queue_notify(&virtiodev, VQ_RX);
driver->running = 1;
-
+ for(i = 0; i < (int)sizeof(driver->mac_addr); i++) {
+ driver->mac_addr[i] = virtio_get_config(&virtiodev, i, 1);
+ }
return 0;
+
+dev_error:
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(&virtiodev, status);
+ return -1;
}
@@ -225,9 +219,10 @@ static int virtionet_term(net_driver_t *driver)
*/
static int virtionet_xmit(char *buf, int len)
{
- struct vring_desc *desc;
- int id;
- static struct virtio_net_hdr nethdr;
+ int id, idx;
+ static struct virtio_net_hdr_v1 nethdr_v1;
+ static struct virtio_net_hdr nethdr_legacy;
+ void *nethdr = &nethdr_legacy;
if (len > BUFFER_ENTRY_SIZE) {
printf("virtionet: Packet too big!\n");
@@ -236,28 +231,25 @@ static int virtionet_xmit(char *buf, int len)
dprintf("\nvirtionet_xmit(packet at %p, %d bytes)\n", buf, len);
- memset(&nethdr, 0, sizeof(nethdr));
+ if (virtiodev.is_modern)
+ nethdr = &nethdr_v1;
+
+ memset(nethdr, 0, net_hdr_size);
/* Determine descriptor index */
- id = (vq[VQ_TX].avail->idx * 2) % vq[VQ_TX].size;
+ idx = virtio_modern16_to_cpu(&virtiodev, vq_tx.avail->idx);
+ id = (idx * 2) % vq_tx.size;
/* Set up virtqueue descriptor for header */
- desc = &vq[VQ_TX].desc[id];
- desc->addr = (uint64_t)&nethdr;
- desc->len = sizeof(struct virtio_net_hdr);
- desc->flags = VRING_DESC_F_NEXT;
- desc->next = id + 1;
+ virtio_fill_desc(&vq_tx.desc[id], virtiodev.is_modern, (uint64_t)nethdr,
+ net_hdr_size, VRING_DESC_F_NEXT, id + 1);
/* Set up virtqueue descriptor for data */
- desc = &vq[VQ_TX].desc[id+1];
- desc->addr = (uint64_t)buf;
- desc->len = len;
- desc->flags = 0;
- desc->next = 0;
+ virtio_fill_desc(&vq_tx.desc[id+1], virtiodev.is_modern, (uint64_t)buf, len, 0, 0);
- vq[VQ_TX].avail->ring[vq[VQ_TX].avail->idx % vq[VQ_TX].size] = id;
+ vq_tx.avail->ring[idx % vq_tx.size] = virtio_cpu_to_modern16(&virtiodev, id);
sync();
- vq[VQ_TX].avail->idx += 1;
+ vq_tx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1);
sync();
/* Tell HV that TX queue is ready */
@@ -272,23 +264,24 @@ static int virtionet_xmit(char *buf, int len)
*/
static int virtionet_receive(char *buf, int maxlen)
{
- int len = 0;
- int id;
+ uint32_t len = 0;
+ uint32_t id, idx;
- if (last_rx_idx == vq[VQ_RX].used->idx) {
+ idx = virtio_modern16_to_cpu(&virtiodev, vq_rx.used->idx);
+
+ if (last_rx_idx == idx) {
/* Nothing received yet */
return 0;
}
- id = (vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].id + 1)
- % vq[VQ_RX].size;
- len = vq[VQ_RX].used->ring[last_rx_idx % vq[VQ_RX].size].len
- - sizeof(struct virtio_net_hdr);
-
- dprintf("virtionet_receive() last_rx_idx=%i, vq[VQ_RX].used->idx=%i,"
- " id=%i len=%i\n", last_rx_idx, vq[VQ_RX].used->idx, id, len);
+ id = (virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].id) + 1)
+ % vq_rx.size;
+ len = virtio_modern32_to_cpu(&virtiodev, vq_rx.used->ring[last_rx_idx % vq_rx.size].len)
+ - net_hdr_size;
+ dprintf("virtionet_receive() last_rx_idx=%i, vq_rx.used->idx=%i,"
+ " id=%i len=%i\n", last_rx_idx, vq_rx.used->idx, id, len);
- if (len > maxlen) {
+ if (len > (uint32_t)maxlen) {
printf("virtio-net: Receive buffer not big enough!\n");
len = maxlen;
}
@@ -298,7 +291,7 @@ static int virtionet_receive(char *buf, int maxlen)
printf("\n");
int i;
for (i=0; i<64; i++) {
- printf(" %02x", *(uint8_t*)(vq[VQ_RX].desc[id].addr+i));
+ printf(" %02x", *(uint8_t*)(vq_rx.desc[id].addr+i));
if ((i%16)==15)
printf("\n");
}
@@ -306,14 +299,14 @@ static int virtionet_receive(char *buf, int maxlen)
#endif
/* Copy data to destination buffer */
- memcpy(buf, (void*)vq[VQ_RX].desc[id].addr, len);
+ memcpy(buf, (void *)virtio_modern64_to_cpu(&virtiodev, vq_rx.desc[id].addr), len);
/* Move indices to next entries */
last_rx_idx = last_rx_idx + 1;
- vq[VQ_RX].avail->ring[vq[VQ_RX].avail->idx % vq[VQ_RX].size] = id - 1;
+ vq_rx.avail->ring[idx % vq_rx.size] = virtio_cpu_to_modern16(&virtiodev, id - 1);
sync();
- vq[VQ_RX].avail->idx += 1;
+ vq_rx.avail->idx = virtio_cpu_to_modern16(&virtiodev, idx + 1);
/* Tell HV that RX queue entry is ready */
virtio_queue_notify(&virtiodev, VQ_RX);
@@ -321,7 +314,7 @@ static int virtionet_receive(char *buf, int maxlen)
return len;
}
-net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev)
+net_driver_t *virtionet_open(struct virtio_device *dev)
{
net_driver_t *driver;
@@ -331,7 +324,6 @@ net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev)
return NULL;
}
- memcpy(driver->mac_addr, mac_addr, 6);
driver->running = 0;
if (virtionet_init_pci(dev))
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-net.h b/qemu/roms/SLOF/lib/libvirtio/virtio-net.h
index bc7a189f7..c2d8ee336 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-net.h
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-net.h
@@ -23,19 +23,10 @@ enum {
VQ_TX = 1, /* Transmit Queue */
};
-struct vqs {
- uint64_t id; /* Queue ID */
- uint32_t size;
- void *buf_mem;
- struct vring_desc *desc;
- struct vring_avail *avail;
- struct vring_used *used;
-};
-
-/* Device is identified by RX queue ID: */
-#define DEVICE_ID vq[0].id
+/* VIRTIO_NET Feature bits */
+#define VIRTIO_NET_F_MAC (1 << 5)
-extern net_driver_t *virtionet_open(char *mac_addr, int len, struct virtio_device *dev);
+extern net_driver_t *virtionet_open(struct virtio_device *dev);
extern void virtionet_close(net_driver_t *driver);
extern int virtionet_read(char *buf, int len);
extern int virtionet_write(char *buf, int len);
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c b/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c
index 48289289a..04181b06c 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio-scsi.c
@@ -15,6 +15,7 @@
#include <cpu.h>
#include <helpers.h>
#include "virtio.h"
+#include "virtio-internal.h"
#include "virtio-scsi.h"
int virtioscsi_send(struct virtio_device *dev,
@@ -22,58 +23,54 @@ int virtioscsi_send(struct virtio_device *dev,
struct virtio_scsi_resp_cmd *resp,
int is_read, void *buf, uint64_t buf_len)
{
- struct vring_desc *desc;
- struct vring_desc *vq_desc; /* Descriptor vring */
- struct vring_avail *vq_avail; /* "Available" vring */
- struct vring_used *vq_used; /* "Used" vring */
-
- volatile uint16_t *current_used_idx;
- uint16_t last_used_idx;
- int id;
- uint32_t vq_size, time;
-
- int vq = VIRTIO_SCSI_REQUEST_VQ;
-
- vq_size = virtio_get_qsize(dev, vq);
- vq_desc = virtio_get_vring_desc(dev, vq);
- vq_avail = virtio_get_vring_avail(dev, vq);
- vq_used = virtio_get_vring_used(dev, vq);
-
- last_used_idx = vq_used->idx;
- current_used_idx = &vq_used->idx;
-
- /* Determine descriptor index */
- id = (vq_avail->idx * 3) % vq_size;
-
- desc = &vq_desc[id];
- desc->addr = (uint64_t)req;
- desc->len = sizeof(*req);
- desc->flags = VRING_DESC_F_NEXT;
- desc->next = (id + 1) % vq_size;
-
- /* Set up virtqueue descriptor for data */
- desc = &vq_desc[(id + 1) % vq_size];
- desc->addr = (uint64_t)resp;
- desc->len = sizeof(*resp);
- desc->flags = VRING_DESC_F_NEXT | VRING_DESC_F_WRITE;
- desc->next = (id + 2) % vq_size;
-
- if (buf && buf_len) {
- /* Set up virtqueue descriptor for status */
- desc = &vq_desc[(id + 2) % vq_size];
- desc->addr = (uint64_t)buf;
- desc->len = buf_len;
- desc->flags = is_read ? VRING_DESC_F_WRITE : 0;
- desc->next = 0;
- } else
- desc->flags &= ~VRING_DESC_F_NEXT;
-
- vq_avail->ring[vq_avail->idx % vq_size] = id;
- mb();
- vq_avail->idx += 1;
-
- /* Tell HV that the vq is ready */
- virtio_queue_notify(dev, vq);
+ struct vring_desc *vq_desc; /* Descriptor vring */
+ struct vring_avail *vq_avail; /* "Available" vring */
+ struct vring_used *vq_used; /* "Used" vring */
+
+ volatile uint16_t *current_used_idx;
+ uint16_t last_used_idx, avail_idx;
+ int id;
+ uint32_t vq_size, time;
+
+ int vq = VIRTIO_SCSI_REQUEST_VQ;
+
+ vq_size = virtio_get_qsize(dev, vq);
+ vq_desc = virtio_get_vring_desc(dev, vq);
+ vq_avail = virtio_get_vring_avail(dev, vq);
+ vq_used = virtio_get_vring_used(dev, vq);
+
+ avail_idx = virtio_modern16_to_cpu(dev, vq_avail->idx);
+
+ last_used_idx = vq_used->idx;
+ current_used_idx = &vq_used->idx;
+
+ /* Determine descriptor index */
+ id = (avail_idx * 3) % vq_size;
+ virtio_fill_desc(&vq_desc[id], dev->is_modern, (uint64_t)req, sizeof(*req), VRING_DESC_F_NEXT,
+ (id + 1) % vq_size);
+
+ /* Set up virtqueue descriptor for data */
+ if (buf && buf_len) {
+ virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern,
+ (uint64_t)resp, sizeof(*resp),
+ VRING_DESC_F_NEXT | VRING_DESC_F_WRITE,
+ (id + 2) % vq_size);
+ /* Set up virtqueue descriptor for status */
+ virtio_fill_desc(&vq_desc[(id + 2) % vq_size], dev->is_modern,
+ (uint64_t)buf, buf_len,
+ (is_read ? VRING_DESC_F_WRITE : 0), 0);
+ } else {
+ virtio_fill_desc(&vq_desc[(id + 1) % vq_size], dev->is_modern,
+ (uint64_t)resp, sizeof(*resp),
+ VRING_DESC_F_WRITE, 0);
+ }
+
+ vq_avail->ring[avail_idx % vq_size] = virtio_cpu_to_modern16(dev, id);
+ mb();
+ vq_avail->idx = virtio_cpu_to_modern16(dev, avail_idx + 1);
+
+ /* Tell HV that the vq is ready */
+ virtio_queue_notify(dev, vq);
/* Wait for host to consume the descriptor */
time = SLOF_GetTimer() + VIRTIO_TIMEOUT;
@@ -84,7 +81,7 @@ int virtioscsi_send(struct virtio_device *dev,
break;
}
- return 0;
+ return 0;
}
/**
@@ -93,42 +90,55 @@ int virtioscsi_send(struct virtio_device *dev,
*/
int virtioscsi_init(struct virtio_device *dev)
{
- struct vring_avail *vq_avail;
- unsigned int idx = 0;
- int qsize = 0;
-
- /* Reset device */
- // XXX That will clear the virtq base. We need to move
- // initializing it to here anyway
- //
- // virtio_reset_device(dev);
-
- /* Acknowledge device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE);
+ struct vring_avail *vq_avail;
+ unsigned int idx = 0;
+ int qsize = 0;
+ int status = VIRTIO_STAT_ACKNOWLEDGE;
- /* Tell HV that we know how to drive the device. */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER);
-
- /* Device specific setup - we do not support special features right now */
- virtio_set_guest_features(dev, 0);
+ /* Reset device */
+ // XXX That will clear the virtq base. We need to move
+ // initializing it to here anyway
+ //
+ // virtio_reset_device(dev);
+
+ /* Acknowledge device. */
+ virtio_set_status(dev, status);
+
+ /* Tell HV that we know how to drive the device. */
+ status |= VIRTIO_STAT_DRIVER;
+ virtio_set_status(dev, status);
+
+ /* Device specific setup - we do not support special features right now */
+ if (dev->is_modern) {
+ if (virtio_negotiate_guest_features(dev, VIRTIO_F_VERSION_1))
+ goto dev_error;
+ virtio_get_status(dev, &status);
+ } else {
+ virtio_set_guest_features(dev, 0);
+ }
- while(1) {
- qsize = virtio_get_qsize(dev, idx);
- if (!qsize)
- break;
- virtio_vring_size(qsize);
+ while(1) {
+ qsize = virtio_get_qsize(dev, idx);
+ if (!qsize)
+ break;
+ virtio_vring_size(qsize);
- vq_avail = virtio_get_vring_avail(dev, 0);
- vq_avail->flags = VRING_AVAIL_F_NO_INTERRUPT;
- vq_avail->idx = 0;
- idx++;
- }
+ vq_avail = virtio_get_vring_avail(dev, idx);
+ vq_avail->flags = virtio_cpu_to_modern16(dev, VRING_AVAIL_F_NO_INTERRUPT);
+ vq_avail->idx = 0;
+ idx++;
+ }
/* Tell HV that setup succeeded */
- virtio_set_status(dev, VIRTIO_STAT_ACKNOWLEDGE|VIRTIO_STAT_DRIVER
- |VIRTIO_STAT_DRIVER_OK);
+ status |= VIRTIO_STAT_DRIVER_OK;
+ virtio_set_status(dev, status);
return 0;
+dev_error:
+ printf("%s: failed\n", __func__);
+ status |= VIRTIO_STAT_FAILED;
+ virtio_set_status(dev, status);
+ return -1;
}
/**
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.c b/qemu/roms/SLOF/lib/libvirtio/virtio.c
index f9c00a67a..f189941c7 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio.c
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio.c
@@ -10,10 +10,16 @@
* IBM Corporation - initial implementation
*****************************************************************************/
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
#include <cpu.h>
#include <cache.h>
#include <byteorder.h>
#include "virtio.h"
+#include "helpers.h"
/* PCI virtio header offsets */
#define VIRTIOHDR_DEVICE_FEATURES 0
@@ -26,6 +32,166 @@
#define VIRTIOHDR_ISR_STATUS 19
#define VIRTIOHDR_DEVICE_CONFIG 20
+/* PCI defines */
+#define PCI_BASE_ADDR_SPACE_IO 0x01
+#define PCI_BASE_ADDR_SPACE_64BIT 0x04
+#define PCI_BASE_ADDR_MEM_MASK (~0x0fUL)
+#define PCI_BASE_ADDR_IO_MASK (~0x03UL)
+
+#define PCI_BASE_ADDR_REG_0 0x10
+#define PCI_CONFIG_CAP_REG 0x34
+
+#define PCI_CAP_ID_VNDR 0x9
+
+/* Common configuration */
+#define VIRTIO_PCI_CAP_COMMON_CFG 1
+/* Notifications */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG 2
+/* ISR access */
+#define VIRTIO_PCI_CAP_ISR_CFG 3
+/* Device specific configuration */
+#define VIRTIO_PCI_CAP_DEVICE_CFG 4
+/* PCI configuration access */
+#define VIRTIO_PCI_CAP_PCI_CFG 5
+
+#define VIRTIO_PCI_CAP_VNDR 0 /* Generic PCI field: PCI_CAP_ID_VNDR */
+#define VIRTIO_PCI_CAP_NEXT 1 /* Generic PCI field: next ptr. */
+#define VIRTIO_PCI_CAP_LEN 2 /* Generic PCI field: capability length */
+#define VIRTIO_PCI_CAP_CFG_TYPE 3 /* Identifies the structure. */
+#define VIRTIO_PCI_CAP_BAR 4 /* Where to find it. */
+#define VIRTIO_PCI_CAP_OFFSET 8 /* Offset within bar. */
+#define VIRTIO_PCI_CAP_LENGTH 12 /* Length of the structure, in bytes. */
+
+struct virtio_dev_common {
+ le32 dev_features_sel;
+ le32 dev_features;
+ le32 drv_features_sel;
+ le32 drv_features;
+ le16 msix_config;
+ le16 num_queues;
+ uint8_t dev_status;
+ uint8_t cfg_generation;
+
+ le16 q_select;
+ le16 q_size;
+ le16 q_msix_vec;
+ le16 q_enable;
+ le16 q_notify_off;
+ le64 q_desc;
+ le64 q_avail;
+ le64 q_used;
+} __attribute__ ((packed));
+
+/* virtio 1.0 Spec: 4.1.3 PCI Device Layout
+ *
+ * Fields of different sizes are present in the device configuration regions.
+ * All 64-bit, 32-bit and 16-bit fields are little-endian. 64-bit fields are to
+ * be treated as two 32-bit fields, with low 32 bit part followed by the high 32
+ * bit part.
+ */
+static void virtio_pci_write64(void *addr, uint64_t val)
+{
+ uint32_t hi = (val >> 32) & 0xFFFFFFFF;
+ uint32_t lo = val & 0xFFFFFFFF;
+
+ ci_write_32(addr, cpu_to_le32(lo));
+ ci_write_32(addr + 4, cpu_to_le32(hi));
+}
+
+static uint64_t virtio_pci_read64(void *addr)
+{
+ uint64_t hi, lo;
+
+ lo = le32_to_cpu(ci_read_32(addr));
+ hi = le32_to_cpu(ci_read_32(addr + 4));
+ return (hi << 32) | lo;
+}
+
+static void virtio_cap_set_base_addr(struct virtio_cap *cap, uint32_t offset)
+{
+ uint64_t addr;
+
+ addr = SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * cap->bar);
+ if (addr & PCI_BASE_ADDR_SPACE_IO) {
+ addr = addr & PCI_BASE_ADDR_IO_MASK;
+ cap->is_io = 1;
+ } else {
+ if (addr & PCI_BASE_ADDR_SPACE_64BIT)
+ addr |= SLOF_pci_config_read32(PCI_BASE_ADDR_REG_0 + 4 * (cap->bar + 1)) << 32;
+ addr = addr & PCI_BASE_ADDR_MEM_MASK;
+ cap->is_io = 0;
+ }
+ addr = (uint64_t)SLOF_translate_my_address((void *)addr);
+ cap->addr = (void *)addr + offset;
+}
+
+static void virtio_process_cap(struct virtio_device *dev, uint8_t cap_ptr)
+{
+ struct virtio_cap *cap;
+ uint8_t cfg_type, bar;
+ uint32_t offset;
+
+ cfg_type = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_CFG_TYPE);
+ bar = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_BAR);
+ offset = SLOF_pci_config_read32(cap_ptr + VIRTIO_PCI_CAP_OFFSET);
+
+ switch(cfg_type) {
+ case VIRTIO_PCI_CAP_COMMON_CFG:
+ cap = &dev->common;
+ break;
+ case VIRTIO_PCI_CAP_NOTIFY_CFG:
+ cap = &dev->notify;
+ dev->notify_off_mul = SLOF_pci_config_read32(cap_ptr + sizeof(struct virtio_cap));
+ break;
+ case VIRTIO_PCI_CAP_ISR_CFG:
+ cap = &dev->isr;
+ break;
+ case VIRTIO_PCI_CAP_DEVICE_CFG:
+ cap = &dev->device;
+ break;
+ default:
+ return;
+ }
+
+ cap->bar = bar;
+ virtio_cap_set_base_addr(cap, offset);
+ cap->cap_id = cfg_type;
+}
+
+/**
+ * Reads the virtio device capabilities, gets called from SLOF routines The
+ * function determines legacy or modern device and sets up driver registers
+ */
+struct virtio_device *virtio_setup_vd(void)
+{
+ uint8_t cap_ptr, cap_vndr;
+ struct virtio_device *dev;
+
+ dev = SLOF_alloc_mem(sizeof(struct virtio_device));
+ if (!dev) {
+ printf("Failed to allocate memory");
+ return NULL;
+ }
+
+ cap_ptr = SLOF_pci_config_read8(PCI_CONFIG_CAP_REG);
+ while (cap_ptr != 0) {
+ cap_vndr = SLOF_pci_config_read8(cap_ptr + VIRTIO_PCI_CAP_VNDR);
+ if (cap_vndr == PCI_CAP_ID_VNDR)
+ virtio_process_cap(dev, cap_ptr);
+ cap_ptr = SLOF_pci_config_read8(cap_ptr+VIRTIO_PCI_CAP_NEXT);
+ }
+
+ if (dev->common.cap_id && dev->notify.cap_id &&
+ dev->isr.cap_id && dev->device.cap_id) {
+ dev->is_modern = 1;
+ } else {
+ dev->is_modern = 0;
+ dev->legacy.cap_id = 0;
+ dev->legacy.bar = 0;
+ virtio_cap_set_base_addr(&dev->legacy, 0);
+ }
+ return dev;
+}
/**
* Calculate ring size according to queue size number
@@ -33,9 +199,9 @@
unsigned long virtio_vring_size(unsigned int qsize)
{
return VQ_ALIGN(sizeof(struct vring_desc) * qsize +
- sizeof(struct vring_avail) + sizeof(uint16_t) * qsize) +
- VQ_ALIGN(sizeof(struct vring_used) +
- sizeof(struct vring_used_elem) * qsize);
+ sizeof(struct vring_avail) + sizeof(uint16_t) * qsize) +
+ VQ_ALIGN(sizeof(struct vring_used) +
+ sizeof(struct vring_used_elem) * qsize);
}
@@ -45,15 +211,22 @@ unsigned long virtio_vring_size(unsigned int qsize)
* @param queue virtio queue number
* @return number of elements
*/
-int virtio_get_qsize(struct virtio_device *dev, int queue)
+unsigned int virtio_get_qsize(struct virtio_device *dev, int queue)
{
- int size = 0;
+ unsigned int size = 0;
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ if (dev->is_modern) {
+ void *addr = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ ci_write_16(addr, cpu_to_le16(queue));
+ eieio();
+ addr = dev->common.addr + offset_of(struct virtio_dev_common, q_size);
+ size = le16_to_cpu(ci_read_16(addr));
+ }
+ else {
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
cpu_to_le16(queue));
eieio();
- size = le16_to_cpu(ci_read_16(dev->base+VIRTIOHDR_QUEUE_SIZE));
+ size = le16_to_cpu(ci_read_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SIZE));
}
return size;
@@ -70,12 +243,19 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
{
struct vring_desc *desc = 0;
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
+ if (dev->is_modern) {
+ void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ void *q_desc = dev->common.addr + offset_of(struct virtio_dev_common, q_desc);
+
+ ci_write_16(q_sel, cpu_to_le16(queue));
+ eieio();
+ desc = (void *)(virtio_pci_read64(q_desc));
+ } else {
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
cpu_to_le16(queue));
eieio();
desc = (void*)(4096L *
- le32_to_cpu(ci_read_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS)));
+ le32_to_cpu(ci_read_32(dev->legacy.addr+VIRTIOHDR_QUEUE_ADDRESS)));
}
return desc;
@@ -90,8 +270,18 @@ struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue)
*/
struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue)
{
- return (void*)((uint64_t)virtio_get_vring_desc(dev, queue)
- + virtio_get_qsize(dev, queue) * sizeof(struct vring_desc));
+ if (dev->is_modern) {
+ void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ void *q_avail = dev->common.addr + offset_of(struct virtio_dev_common, q_avail);
+
+ ci_write_16(q_sel, cpu_to_le16(queue));
+ eieio();
+ return (void *)(virtio_pci_read64(q_avail));
+ }
+ else {
+ return (void*)((uint64_t)virtio_get_vring_desc(dev, queue) +
+ virtio_get_qsize(dev, queue) * sizeof(struct vring_desc));
+ }
}
@@ -103,20 +293,46 @@ struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue)
*/
struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue)
{
- return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue)
- + virtio_get_qsize(dev, queue)
- * sizeof(struct vring_avail));
+ if (dev->is_modern) {
+ void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ void *q_used = dev->common.addr + offset_of(struct virtio_dev_common, q_used);
+
+ ci_write_16(q_sel, cpu_to_le16(queue));
+ eieio();
+ return (void *)(virtio_pci_read64(q_used));
+ } else {
+ return (void*)VQ_ALIGN((uint64_t)virtio_get_vring_avail(dev, queue)
+ + virtio_get_qsize(dev, queue)
+ * sizeof(struct vring_avail));
+ }
}
+/**
+ * Fill the virtio ring descriptor depending on the legacy mode or virtio 1.0
+ */
+void virtio_fill_desc(struct vring_desc *desc, bool is_modern,
+ uint64_t addr, uint32_t len,
+ uint16_t flags, uint16_t next)
+{
+ if (is_modern) {
+ desc->addr = cpu_to_le64(addr);
+ desc->len = cpu_to_le32(len);
+ desc->flags = cpu_to_le16(flags);
+ desc->next = cpu_to_le16(next);
+ } else {
+ desc->addr = addr;
+ desc->len = len;
+ desc->flags = flags;
+ desc->next = next;
+ }
+}
/**
* Reset virtio device
*/
void virtio_reset_device(struct virtio_device *dev)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, 0);
- }
+ virtio_set_status(dev, 0);
}
@@ -125,25 +341,64 @@ void virtio_reset_device(struct virtio_device *dev)
*/
void virtio_queue_notify(struct virtio_device *dev, int queue)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
+ if (dev->is_modern) {
+ void *q_sel = dev->common.addr + offset_of(struct virtio_dev_common, q_select);
+ void *q_ntfy = dev->common.addr + offset_of(struct virtio_dev_common, q_notify_off);
+ void *addr;
+ uint16_t q_notify_off;
+
+ ci_write_16(q_sel, cpu_to_le16(queue));
+ eieio();
+ q_notify_off = le16_to_cpu(ci_read_16(q_ntfy));
+ addr = dev->notify.addr + q_notify_off * dev->notify_off_mul;
+ ci_write_16(addr, cpu_to_le16(queue));
+ } else {
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_NOTIFY, cpu_to_le16(queue));
}
}
/**
* Set queue address
*/
-void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr)
+void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned long qaddr)
+{
+ if (dev->is_modern) {
+ uint64_t q_desc = qaddr;
+ uint64_t q_avail;
+ uint64_t q_used;
+ uint32_t q_size = virtio_get_qsize(dev, queue);
+
+ virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_desc), q_desc);
+ q_avail = q_desc + q_size * sizeof(struct vring_desc);
+ virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_avail), q_avail);
+ q_used = VQ_ALIGN(q_avail + sizeof(struct vring_avail) + sizeof(uint16_t) * q_size);
+ virtio_pci_write64(dev->common.addr + offset_of(struct virtio_dev_common, q_used), q_used);
+ ci_write_16(dev->common.addr + offset_of(struct virtio_dev_common, q_enable), cpu_to_le16(1));
+ } else {
+ uint32_t val = qaddr;
+ val = val >> 12;
+ ci_write_16(dev->legacy.addr+VIRTIOHDR_QUEUE_SELECT,
+ cpu_to_le16(queue));
+ eieio();
+ ci_write_32(dev->legacy.addr+VIRTIOHDR_QUEUE_ADDRESS,
+ cpu_to_le32(val));
+ }
+}
+
+int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int id)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- uint32_t val = qaddr;
- val = val >> 12;
- ci_write_16(dev->base+VIRTIOHDR_QUEUE_SELECT,
- cpu_to_le16(queue));
- eieio();
- ci_write_32(dev->base+VIRTIOHDR_QUEUE_ADDRESS,
- cpu_to_le32(val));
- }
+ vq->size = virtio_get_qsize(dev, id);
+ vq->desc = SLOF_alloc_mem_aligned(virtio_vring_size(vq->size), 4096);
+ if (!vq->desc) {
+ printf("memory allocation failed!\n");
+ return -1;
+ }
+ memset(vq->desc, 0, virtio_vring_size(vq->size));
+ virtio_set_qaddr(dev, id, (unsigned long)vq->desc);
+ vq->avail = virtio_get_vring_avail(dev, id);
+ vq->used = virtio_get_vring_used(dev, id);
+ vq->id = id;
+ return 0;
}
/**
@@ -151,34 +406,109 @@ void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr)
*/
void virtio_set_status(struct virtio_device *dev, int status)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_8(dev->base+VIRTIOHDR_DEVICE_STATUS, status);
+ if (dev->is_modern) {
+ ci_write_8(dev->common.addr +
+ offset_of(struct virtio_dev_common, dev_status), status);
+ } else {
+ ci_write_8(dev->legacy.addr+VIRTIOHDR_DEVICE_STATUS, status);
}
}
+/**
+ * Get device status bits
+ */
+void virtio_get_status(struct virtio_device *dev, int *status)
+{
+ if (dev->is_modern) {
+ *status = ci_read_8(dev->common.addr +
+ offset_of(struct virtio_dev_common, dev_status));
+ } else {
+ *status = ci_read_8(dev->legacy.addr+VIRTIOHDR_DEVICE_STATUS);
+ }
+}
/**
* Set guest feature bits
*/
-void virtio_set_guest_features(struct virtio_device *dev, int features)
+void virtio_set_guest_features(struct virtio_device *dev, uint64_t features)
{
- if (dev->type == VIRTIO_TYPE_PCI) {
- ci_write_32(dev->base+VIRTIOHDR_GUEST_FEATURES, bswap_32(features));
+ if (dev->is_modern) {
+ uint32_t f1 = (features >> 32) & 0xFFFFFFFF;
+ uint32_t f0 = features & 0xFFFFFFFF;
+ void *addr = dev->common.addr;
+
+ ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features_sel),
+ cpu_to_le32(1));
+ ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features),
+ cpu_to_le32(f1));
+
+ ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features_sel),
+ cpu_to_le32(0));
+ ci_write_32(addr + offset_of(struct virtio_dev_common, drv_features),
+ cpu_to_le32(f0));
+ } else {
+ ci_write_32(dev->legacy.addr+VIRTIOHDR_GUEST_FEATURES, cpu_to_le32(features));
}
}
/**
* Get host feature bits
*/
-void virtio_get_host_features(struct virtio_device *dev, int *features)
+uint64_t virtio_get_host_features(struct virtio_device *dev)
{
- if (dev->type == VIRTIO_TYPE_PCI && features) {
- *features = bswap_32(ci_read_32(dev->base+VIRTIOHDR_DEVICE_FEATURES));
+ uint64_t features = 0;
+ if (dev->is_modern) {
+ uint32_t f0 = 0, f1 = 0;
+ void *addr = dev->common.addr;
+
+ ci_write_32(addr + offset_of(struct virtio_dev_common, dev_features_sel),
+ cpu_to_le32(1));
+ f1 = ci_read_32(addr +
+ offset_of(struct virtio_dev_common, dev_features));
+ ci_write_32(addr + offset_of(struct virtio_dev_common, dev_features_sel),
+ cpu_to_le32(0));
+ f0 = ci_read_32(addr +
+ offset_of(struct virtio_dev_common, dev_features));
+
+ features = ((uint64_t)le32_to_cpu(f1) << 32) | le32_to_cpu(f0);
+ } else {
+ features = le32_to_cpu(ci_read_32(dev->legacy.addr+VIRTIOHDR_DEVICE_FEATURES));
}
+ return features;
}
+int virtio_negotiate_guest_features(struct virtio_device *dev, uint64_t features)
+{
+ uint64_t host_features = 0;
+ int status;
+
+ /* Negotiate features */
+ host_features = virtio_get_host_features(dev);
+ if (!(host_features & VIRTIO_F_VERSION_1)) {
+ fprintf(stderr, "Device does not support virtio 1.0 %llx\n", host_features);
+ return -1;
+ }
+
+ virtio_set_guest_features(dev, features);
+ host_features = virtio_get_host_features(dev);
+ if ((host_features & features) != features) {
+ fprintf(stderr, "Features error %llx\n", features);
+ return -1;
+ }
+
+ virtio_get_status(dev, &status);
+ status |= VIRTIO_STAT_FEATURES_OK;
+ virtio_set_status(dev, status);
+
+ /* Read back to verify the FEATURES_OK bit */
+ virtio_get_status(dev, &status);
+ if ((status & VIRTIO_STAT_FEATURES_OK) != VIRTIO_STAT_FEATURES_OK)
+ return -1;
+
+ return 0;
+}
/**
* Get additional config values
@@ -186,32 +516,38 @@ void virtio_get_host_features(struct virtio_device *dev, int *features)
uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
{
uint64_t val = ~0ULL;
+ uint32_t hi, lo;
void *confbase;
- switch (dev->type) {
- case VIRTIO_TYPE_PCI:
- confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
- break;
- default:
- return ~0ULL;
- }
+ if (dev->is_modern)
+ confbase = dev->device.addr;
+ else
+ confbase = dev->legacy.addr+VIRTIOHDR_DEVICE_CONFIG;
+
switch (size) {
- case 1:
+ case 1:
val = ci_read_8(confbase+offset);
break;
- case 2:
+ case 2:
val = ci_read_16(confbase+offset);
+ if (dev->is_modern)
+ val = le16_to_cpu(val);
break;
- case 4:
+ case 4:
val = ci_read_32(confbase+offset);
+ if (dev->is_modern)
+ val = le32_to_cpu(val);
break;
- case 8:
+ case 8:
/* We don't support 8 bytes PIO accesses
* in qemu and this is all PIO
*/
- val = ci_read_32(confbase+offset);
- val <<= 32;
- val |= ci_read_32(confbase+offset+4);
+ lo = ci_read_32(confbase+offset);
+ hi = ci_read_32(confbase+offset+4);
+ if (dev->is_modern)
+ val = (uint64_t)le32_to_cpu(hi) << 32 | le32_to_cpu(lo);
+ else
+ val = (uint64_t)hi << 32 | lo;
break;
}
@@ -222,20 +558,19 @@ uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size)
* Get config blob
*/
int __virtio_read_config(struct virtio_device *dev, void *dst,
- int offset, int len)
+ int offset, int len)
{
void *confbase;
unsigned char *buf = dst;
int i;
- switch (dev->type) {
- case VIRTIO_TYPE_PCI:
- confbase = dev->base+VIRTIOHDR_DEVICE_CONFIG;
- break;
- default:
- return 0;
- }
+ if (dev->is_modern)
+ confbase = dev->device.addr;
+ else
+ confbase = dev->legacy.addr+VIRTIOHDR_DEVICE_CONFIG;
+
for (i = 0; i < len; i++)
buf[i] = ci_read_8(confbase + offset + i);
+
return len;
}
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.code b/qemu/roms/SLOF/lib/libvirtio/virtio.code
index 258b9bbda..8eec8f055 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio.code
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio.code
@@ -18,6 +18,11 @@
/******** core virtio ********/
+// : virtio-setup-vd ( -- dev )
+PRIM(virtio_X2d_setup_X2d_vd)
+ PUSH; TOS.a = virtio_setup_vd();
+MIRP
+
// : virtio-vring-size ( queuesize -- ringsize )
PRIM(virtio_X2d_vring_X2d_size)
TOS.u = virtio_vring_size(TOS.u);
@@ -122,20 +127,18 @@ MIRP
/******** virtio-net ********/
-// : virtio-net-open ( mac-addr-str len dev -- false | [ driver true ] )
+// : virtio-net-open ( dev -- false | [ driver true ] )
PRIM(virtio_X2d_net_X2d_open)
{
- void *dev = TOS.a; POP;
- int len = TOS.u; POP;
- char *mac_addr = TOS.a;
+ void *dev = TOS.a;
- net_driver_t *net_driver = virtionet_open(mac_addr, len, dev);
+ net_driver_t *net_driver = virtionet_open(dev);
- if (net_driver) {
- TOS.u = (unsigned long)net_driver; PUSH;
- TOS.n = -1;
- } else
- TOS.n = 0;
+ if (net_driver) {
+ TOS.u = (unsigned long)net_driver; PUSH;
+ TOS.n = -1;
+ } else
+ TOS.n = 0;
}
MIRP
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.h b/qemu/roms/SLOF/lib/libvirtio/virtio.h
index d5759b45a..0fee4baec 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio.h
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio.h
@@ -14,13 +14,23 @@
#define _LIBVIRTIO_H
#include <stdint.h>
+#include <stdbool.h>
/* Device status bits */
#define VIRTIO_STAT_ACKNOWLEDGE 1
#define VIRTIO_STAT_DRIVER 2
#define VIRTIO_STAT_DRIVER_OK 4
+#define VIRTIO_STAT_FEATURES_OK 8
+#define VIRTIO_STAT_NEEDS_RESET 64
#define VIRTIO_STAT_FAILED 128
+#define BIT(x) (1UL << (x))
+
+/* VIRTIO 1.0 Device independent feature bits */
+#define VIRTIO_F_RING_INDIRECT_DESC BIT(28)
+#define VIRTIO_F_RING_EVENT_IDX BIT(29)
+#define VIRTIO_F_VERSION_1 BIT(32)
+
#define VIRTIO_TIMEOUT 5000 /* 5 sec timeout */
/* Definitions for vring_desc.flags */
@@ -34,7 +44,7 @@ struct vring_desc {
uint32_t len; /* Length */
uint16_t flags; /* The flags as indicated above */
uint16_t next; /* Next field if flags & NEXT */
-};
+};
/* Definitions for vring_avail.flags */
#define VRING_AVAIL_F_NO_INTERRUPT 1
@@ -44,8 +54,7 @@ struct vring_avail {
uint16_t flags;
uint16_t idx;
uint16_t ring[];
-};
-
+};
/* Definitions for vring_used.flags */
#define VRING_USED_F_NO_NOTIFY 1
@@ -61,27 +70,56 @@ struct vring_used {
struct vring_used_elem ring[];
};
-#define VIRTIO_TYPE_PCI 0 /* For virtio-pci interface */
+/* Structure shared with SLOF and is 16bytes */
+struct virtio_cap {
+ void *addr;
+ uint8_t bar;
+ uint8_t is_io;
+ uint8_t cap_id;
+};
+
struct virtio_device {
- void *base; /* base address */
- int type; /* VIRTIO_TYPE_PCI or VIRTIO_TYPE_VIO */
+ uint32_t is_modern; /* Indicates whether to use virtio 1.0 */
+ struct virtio_cap legacy;
+ struct virtio_cap common;
+ struct virtio_cap notify;
+ struct virtio_cap isr;
+ struct virtio_cap device;
+ struct virtio_cap pci;
+ uint32_t notify_off_mul;
+};
+
+struct vqs {
+ uint64_t id; /* Queue ID */
+ uint32_t size;
+ void *buf_mem;
+ struct vring_desc *desc;
+ struct vring_avail *avail;
+ struct vring_used *used;
};
/* Parts of the virtqueue are aligned on a 4096 byte page boundary */
#define VQ_ALIGN(addr) (((addr) + 0xfff) & ~0xfff)
extern unsigned long virtio_vring_size(unsigned int qsize);
-extern int virtio_get_qsize(struct virtio_device *dev, int queue);
+extern unsigned int virtio_get_qsize(struct virtio_device *dev, int queue);
extern struct vring_desc *virtio_get_vring_desc(struct virtio_device *dev, int queue);
extern struct vring_avail *virtio_get_vring_avail(struct virtio_device *dev, int queue);
extern struct vring_used *virtio_get_vring_used(struct virtio_device *dev, int queue);
+extern void virtio_fill_desc(struct vring_desc *desc, bool is_modern,
+ uint64_t addr, uint32_t len,
+ uint16_t flags, uint16_t next);
+extern int virtio_queue_init_vq(struct virtio_device *dev, struct vqs *vq, unsigned int id);
+extern struct virtio_device *virtio_setup_vd(void);
extern void virtio_reset_device(struct virtio_device *dev);
extern void virtio_queue_notify(struct virtio_device *dev, int queue);
extern void virtio_set_status(struct virtio_device *dev, int status);
-extern void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned int qaddr);
-extern void virtio_set_guest_features(struct virtio_device *dev, int features);
-extern void virtio_get_host_features(struct virtio_device *dev, int *features);
+extern void virtio_get_status(struct virtio_device *dev, int *status);
+extern void virtio_set_qaddr(struct virtio_device *dev, int queue, unsigned long qaddr);
+extern void virtio_set_guest_features(struct virtio_device *dev, uint64_t features);
+extern uint64_t virtio_get_host_features(struct virtio_device *dev);
+extern int virtio_negotiate_guest_features(struct virtio_device *dev, uint64_t features);
extern uint64_t virtio_get_config(struct virtio_device *dev, int offset, int size);
extern int __virtio_read_config(struct virtio_device *dev, void *dst,
int offset, int len);
diff --git a/qemu/roms/SLOF/lib/libvirtio/virtio.in b/qemu/roms/SLOF/lib/libvirtio/virtio.in
index c36d127c7..195840e0f 100644
--- a/qemu/roms/SLOF/lib/libvirtio/virtio.in
+++ b/qemu/roms/SLOF/lib/libvirtio/virtio.in
@@ -10,6 +10,8 @@
* IBM Corporation - initial implementation
*****************************************************************************/
+cod(virtio-setup-vd)
+
cod(virtio-vring-size)
cod(virtio-get-qsize)
cod(virtio-get-config)