diff options
author | 2016-06-03 03:33:22 +0000 | |
---|---|---|
committer | 2016-06-03 03:33:23 +0000 | |
commit | da27230f80795d0028333713f036d44c53cb0e68 (patch) | |
tree | b3d379eaf000adf72b36cb01cdf4d79c3e3f064c /qemu/roms/SLOF/lib | |
parent | 0e68cb048bb8aadb14675f5d4286d8ab2fc35449 (diff) | |
parent | 437fd90c0250dee670290f9b714253671a990160 (diff) |
Merge "These changes are the raw update to qemu-2.6."
Diffstat (limited to 'qemu/roms/SLOF/lib')
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) |