diff --git a/.gitmodules b/.gitmodules index 63add75bd46ec1eb95d0ef9293369e8e118bf75d..4d2493514c11c925f52d4d59a2579cfa03a6da61 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "external/glibc.bin"] path = external/glibc.bin url = ../glibc.bin +[submodule "external/glibc-testsuite"] + path = external/glibc-testsuite + url = ../glibc-testsuite diff --git a/README b/README index a47a698e98e6ed603a8d28f94a54229e11c8a60b..19282f268428f3a22cabd1d7daa1247a7d4c43ef 100644 --- a/README +++ b/README @@ -5,9 +5,7 @@ To build OSv 2) make sure all git submodules are uptodate ----------------------------------------- - git submodule init external/openjdk.bin/ - git submodule init external/libunwind - git submodule update + git submodule update --init 1) build the specially patched libunwind ------------------------------------- @@ -19,8 +17,13 @@ To build OSv cp ./src/.libs/libunwind.a ../.. cd ../.. +3) build the glibc test suite -2) build osv + cd external/glibc-testsuite + make + cd ../.. + +3) build osv --------- make diff --git a/bootfs.manifest b/bootfs.manifest index 6bcf0ad4524ff4b6f6a8cc18f167df6e9a134ccf..9e42d5591997df0b79428dd6a65f72855dde4d8b 100644 --- a/bootfs.manifest +++ b/bootfs.manifest @@ -11,7 +11,9 @@ /usr/lib/jvm/jre/lib/rhino.jar: %(jdkbase)s/jre/lib/rhino.jar /usr/lib/jvm/jre/lib/meta-index: %(jdkbase)s/jre/lib/meta-index /usr/lib/libstdc++.so.6: %(gccbase)s/usr/lib64/libstdc++.so.6 -/usr/lib/libm.so.6: /usr/lib64/libm.so.6 +/usr/lib/libm.so.6: %(glibcbase)s/lib64/libm.so.6 /usr/lib/libgcc_s.so.1: %(gccbase)s/lib64/libgcc_s.so.1 -/usr/lib/tst-dir.so: ./tests/tst-dir.so /usr/lib/tst-pthread.so: ./tests/tst-pthread.so +/tests/tst-malloc.so: ../../external/glibc-testsuite/build/debug/malloc/tst-malloc.so +/tests/tst-getcwd.so: ../../external/glibc-testsuite/build/debug/io/tst-getcwd.so + diff --git a/build.mak b/build.mak index f0c288e608e8770da2402d711e2239dbc5aee22a..b5d4af969b84bf55275b75ddf1c39c7411fd0839 100644 --- a/build.mak +++ b/build.mak @@ -51,12 +51,11 @@ autodepend = -MD -MT $@ -MP do-sys-includes = $(foreach inc, $(sys-includes), -isystem $(inc)) -tests := tests/tst-dir.so tests/tst-pthread.so +tests := tests/tst-pthread.so -tests/tst-dir.so: tests/tst-dir.o tests/tst-pthread.so: tests/tst-pthread.o -all: loader.img loader.bin $(tests) +all: loader.img loader.bin boot.bin: arch/x64/boot16.ld arch/x64/boot16.o $(call quiet, $(LD) -o $@ -T $^, LD $@) @@ -117,6 +116,7 @@ objects += linux.o objects += sched.o include $(src)/libc/build.mak + objects += $(addprefix libc/, $(libc)) libstdc++.a = $(shell find $(gccbase) -name libstdc++.a) @@ -143,7 +143,8 @@ gccbase = $(src)/external/gcc.bin bootfs.bin: scripts/mkbootfs.py bootfs.manifest $(tests) $(call quiet, $(src)/scripts/mkbootfs.py -o $@ -d $@.d -m $(src)/bootfs.manifest \ - -D jdkbase=$(jdkbase) -D gccbase=$(gccbase), MKBOOTFS $@) + -D jdkbase=$(jdkbase) -D gccbase=$(gccbase) -D \ + glibcbase=$(glibcbase), MKBOOTFS $@) bootfs.o: bootfs.bin diff --git a/drivers/driver.cc b/drivers/driver.cc index 87543331fc88d9dbb94f5a05482c8e7e436eda3f..abbf22450ca617a8fdd486d7489539bc2f5ac976 100644 --- a/drivers/driver.cc +++ b/drivers/driver.cc @@ -85,6 +85,12 @@ bool Driver::Init(Device* dev) { if (!dev) return false; + if (!earlyInitChecks()) { + return false; + } + + parse_pci_config(); + debug(fmt("Driver:Init %x:%x") % _vid % _id); setBusMaster(true); @@ -116,6 +122,74 @@ Driver::getFunc() { return _func; } +bool Driver::parse_pci_config(void) +{ + // Parse capabilities + bool parse_ok = parse_pci_capabilities(); + + return parse_ok; +} + +bool Driver::parse_pci_capabilities(void) +{ + // FIXME: check pci device type (act differently if bridge) + u8 capabilities_base = pci_readb(PCI_CAPABILITIES_PTR); + u8 off = capabilities_base; + + while (off != 0) { + if (off > 255) { + return (false); + } + + u8 capability = pci_readb(off + PCI_CAP_OFF_ID); + switch (capability) { + case PCI_CAP_MSIX: + _have_msix = true; + debug(fmt("Have MSI-X!")); + break; + } + + off = pci_readb(off + PCI_CAP_OFF_NEXT); + } + + return true; +} + +bool Driver::parse_pci_msix(void) +{ + return true; +} + +u8 Driver::pci_readb(u8 offset) +{ + return read_pci_config_byte(_bus, _slot, _func, offset); +} + +u16 Driver::pci_readw(u8 offset) +{ + return read_pci_config_word(_bus, _slot, _func, offset); +} + +u32 Driver::pci_readl(u8 offset) +{ + return read_pci_config(_bus, _slot, _func, offset); +} + +void Driver::pci_writeb(u8 offset, u8 val) +{ + write_pci_config_byte(_bus, _slot, _func, offset, val); +} + +void Driver::pci_writew(u8 offset, u16 val) +{ + write_pci_config_word(_bus, _slot, _func, offset, val); +} + +void Driver::pci_writel(u8 offset, u32 val) +{ + write_pci_config(_bus, _slot, _func, offset, val); +} + void Driver::dumpConfig() const { debug(fmt("Driver vid:id= %x:%x") % _vid % _id); } diff --git a/drivers/driver.hh b/drivers/driver.hh index 777999a4f59798d7bf5e1153ea0a41141fe2d47a..69dd006cad74b1f76f4c462c596c12badd45c7f2 100644 --- a/drivers/driver.hh +++ b/drivers/driver.hh @@ -29,6 +29,8 @@ public: virtual void dumpConfig() const; virtual bool Init(Device *d); + bool parse_pci_config(void); + friend std::ostream& operator <<(std::ostream& out, const Driver &d); struct equal { bool operator()(const Driver* d1, const Driver* d2) const @@ -60,11 +62,27 @@ protected: bool allocateBARs(); virtual bool earlyInitChecks(); + // Parsing of extra capabilities + virtual bool parse_pci_capabilities(void); + virtual bool parse_pci_msix(void); + + // Access to PCI address space + virtual u8 pci_readb(u8 offset); + virtual u16 pci_readw(u8 offset); + virtual u32 pci_readl(u8 offset); + virtual void pci_writeb(u8 offset, u8 val); + virtual void pci_writew(u8 offset, u16 val); + virtual void pci_writel(u8 offset, u32 val); + u16 _id; u16 _vid; bool _present; u8 _bus, _slot, _func; Bar* _bars[6]; + + // MSI-X + bool _have_msix; + }; #endif diff --git a/drivers/pci.hh b/drivers/pci.hh index e35c289044a2cf4713ffe068eda66f02caa1ce74..9d4ad96acacac728b02addbed6e4cfcebcf54367 100644 --- a/drivers/pci.hh +++ b/drivers/pci.hh @@ -37,6 +37,35 @@ using processor::outl; PCI_CAPABILITIES_PTR = 0x34, }; + /* Capability Register Offsets */ + enum pci_capabilities_offsets { + PCI_CAP_OFF_ID = 0x0, + PCI_CAP_OFF_NEXT = 0x1 + }; + + enum pci_capabilities { + PCI_CAP_PM = 0x01, // PCI Power Management + PCI_CAP_AGP = 0x02, // AGP + PCI_CAP_VPD = 0x03, // Vital Product Data + PCI_CAP_SLOTID = 0x04, // Slot Identification + PCI_CAP_MSI = 0x05, // Message Signaled Interrupts + PCI_CAP_CHSWP = 0x06, // CompactPCI Hot Swap + PCI_CAP_PCIX = 0x07, // PCI-X + PCI_CAP_HT = 0x08, // HyperTransport + PCI_CAP_VENDOR = 0x09, // Vendor Unique + PCI_CAP_DEBUG = 0x0a, // Debug port + PCI_CAP_CRES = 0x0b, // CompactPCI central resource control + PCI_CAP_HOTPLUG = 0x0c, // PCI Hot-Plug + PCI_CAP_SUBVENDOR = 0x0d, // PCI-PCI bridge subvendor ID + PCI_CAP_AGP8X = 0x0e, // AGP 8x + PCI_CAP_SECDEV = 0x0f, // Secure Device + PCI_CAP_EXPRESS = 0x10, // PCI Express + PCI_CAP_MSIX = 0x11, // MSI-X + PCI_CAP_SATA = 0x12, // SATA + PCI_CAP_PCIAF = 0x13 // PCI Advanced Features + }; + + u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset); u16 read_pci_config_word(u8 bus, u8 slot, u8 func, u8 offset); u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset); diff --git a/drivers/virtio.cc b/drivers/virtio.cc index d05f92c009328a670dbb4a63cda29391acb2952d..38e4ab660e83af240542327429fe7ed8264325a5 100644 --- a/drivers/virtio.cc +++ b/drivers/virtio.cc @@ -52,10 +52,6 @@ namespace virtio { bool virtio_driver::Init(Device* dev) { - if (!earlyInitChecks()) { - return false; - } - if (!Driver::Init(dev)) { return (false); } diff --git a/elf.cc b/elf.cc index 454175fa0bc24aeedfaadc5dcf360035adb07e56..c998b74013cc4ea9b98c3edd8215f87ffc9122d3 100644 --- a/elf.cc +++ b/elf.cc @@ -482,7 +482,7 @@ namespace elf { { auto needed = dynamic_str_array(DT_NEEDED); for (auto lib : needed) { - _prog.add(std::string("/usr/lib") + lib); + _prog.add_object(std::string("/usr/lib") + lib); } } @@ -528,10 +528,10 @@ namespace elf { _core->load_segments(); assert(!s_program); s_program = this; - add("libc.so.6", _core.get()); - add("ld-linux-x86-64.so.2", _core.get()); - add("libpthread.so.0", _core.get()); - add("libdl.so.2", _core.get()); + set_object("libc.so.6", _core.get()); + set_object("ld-linux-x86-64.so.2", _core.get()); + set_object("libpthread.so.0", _core.get()); + set_object("libdl.so.2", _core.get()); } tls_data program::tls() @@ -539,12 +539,12 @@ namespace elf { return _core->tls(); } - void program::add(std::string name, elf_object* obj) + void program::set_object(std::string name, elf_object* obj) { _files[name] = obj; } - elf_object* program::add(std::string name) + elf_object* program::add_object(std::string name) { if (!_files.count(name)) { auto f(_fs.open(name)); diff --git a/elf.hh b/elf.hh index 4f56e7a663b7fe72bb28176ab1148e4486f3d08f..ae6e66535f2878b5e5b51fc2da03e7a41bdd85ba 100644 --- a/elf.hh +++ b/elf.hh @@ -321,8 +321,7 @@ namespace elf { public: explicit program(::filesystem& fs, void* base = reinterpret_cast<void*>(0x100000000000UL)); - elf_object* add(std::string lib); - void add(std::string lib, elf_object* obj); + elf_object* add_object(std::string lib); symbol_module lookup(const char* symbol); template <typename T> T* lookup_function(const char* symbol); @@ -332,6 +331,7 @@ namespace elf { private: void add_debugger_obj(elf_object* obj); void* do_lookup_function(const char* symbol); + void set_object(std::string lib, elf_object* obj); private: ::filesystem& _fs; void* _next_alloc; diff --git a/external/glibc-testsuite b/external/glibc-testsuite new file mode 160000 index 0000000000000000000000000000000000000000..1aa7453760873926164d197f4909c2513edac0cf --- /dev/null +++ b/external/glibc-testsuite @@ -0,0 +1 @@ +Subproject commit 1aa7453760873926164d197f4909c2513edac0cf diff --git a/external/glibc.bin b/external/glibc.bin index 55853b12d5077dac5f76e164ee29e173770d255d..ef094e3a925c6097f122399d40914d6b9bcff09f 160000 --- a/external/glibc.bin +++ b/external/glibc.bin @@ -1 +1 @@ -Subproject commit 55853b12d5077dac5f76e164ee29e173770d255d +Subproject commit ef094e3a925c6097f122399d40914d6b9bcff09f diff --git a/fs/vfs/main.c b/fs/vfs/main.c index ea0d8b13efa5951dfd56f1f8d220f408abe893bb..c6d104dc0612c1b202bd0239355791dc67017d0a 100755 --- a/fs/vfs/main.c +++ b/fs/vfs/main.c @@ -564,9 +564,35 @@ int __xstat64(int ver, const char *pathname, struct stat64 *st) char *getcwd(char *path, size_t size) { struct task *t = main_task; + int len = strlen(t->t_cwd) + 1; + int error; - strlcpy(path, t->t_cwd, size); - return 0; + if (!path) { + if (!size) + size = len; + path = malloc(size); + if (!path) { + error = ENOMEM; + goto out_errno; + } + } else { + if (!size) { + error = EINVAL; + goto out_errno; + } + } + + if (size < len) { + error = ERANGE; + goto out_errno; + } + + memcpy(path, t->t_cwd, len); + return path; + +out_errno: + errno = error; + return NULL; } /* @@ -850,6 +876,7 @@ void unpack_bootfs(void) "/usr/lib/jvm/jre/lib", "/usr/lib/jvm/jre/lib/amd64", "/usr/lib/jvm/jre/lib/amd64/server", + "/tests", NULL, }; diff --git a/libc/build.mak b/libc/build.mak index faaf8d38ed80a86add70cdd7f6b676b879c5df07..bbc918196bdcc294112e4291930ba8a829250028 100644 --- a/libc/build.mak +++ b/libc/build.mak @@ -1,4 +1,7 @@ -libc = string/strcmp.o +libc := + +libc += getopt.o +libc += string/strcmp.o libc += string/strcpy.o libc += string/strlcpy.o libc += string/strlcat.o diff --git a/libc/dlfcn.cc b/libc/dlfcn.cc index 980128bde498eeac77cab2216b85ddc0ddbaa4fd..e04e720d189ea7e46aa48a420e5b14aaa17a9f39 100644 --- a/libc/dlfcn.cc +++ b/libc/dlfcn.cc @@ -5,7 +5,7 @@ void* dlopen(const char* filename, int flags) { auto prog = elf::get_program(); - elf::elf_object* obj = prog->add(filename); + elf::elf_object* obj = prog->add_object(filename); // FIXME: handle flags etc. return obj; } diff --git a/libc/getopt.c b/libc/getopt.c new file mode 100644 index 0000000000000000000000000000000000000000..b2f5778cbfc2a8a97afcad03bc422daed437505b --- /dev/null +++ b/libc/getopt.c @@ -0,0 +1,516 @@ +/**************************************************************************** + +getopt.c - Read command line options + +AUTHOR: Gregory Pietsch +CREATED Fri Jan 10 21:13:05 1997 + +DESCRIPTION: + +The getopt() function parses the command line arguments. Its arguments argc +and argv are the argument count and array as passed to the main() function +on program invocation. The argument optstring is a list of available option +characters. If such a character is followed by a colon (`:'), the option +takes an argument, which is placed in optarg. If such a character is +followed by two colons, the option takes an optional argument, which is +placed in optarg. If the option does not take an argument, optarg is NULL. + +The external variable optind is the index of the next array element of argv +to be processed; it communicates from one call to the next which element to +process. + +The getopt_long() function works like getopt() except that it also accepts +long options started by two dashes `--'. If these take values, it is either +in the form + +--arg=value + + or + +--arg value + +It takes the additional arguments longopts which is a pointer to the first +element of an array of type struct option. The last element of the array +has to be filled with NULL for the name field. + +The longind pointer points to the index of the current long option relative +to longopts if it is non-NULL. + +The getopt() function returns the option character if the option was found +successfully, `:' if there was a missing parameter for one of the options, +`?' for an unknown option character, and EOF for the end of the option list. + +The getopt_long() function's return value is described in the header file. + +The function getopt_long_only() is identical to getopt_long(), except that a +plus sign `+' can introduce long options as well as `--'. + +The following describes how to deal with options that follow non-option +argv-elements. + +If the caller did not specify anything, the default is REQUIRE_ORDER if the +environment variable POSIXLY_CORRECT is defined, PERMUTE otherwise. + +REQUIRE_ORDER means don't recognize them as options; stop option processing +when the first non-option is seen. This is what Unix does. This mode of +operation is selected by either setting the environment variable +POSIXLY_CORRECT, or using `+' as the first character of the optstring +parameter. + +PERMUTE is the default. We permute the contents of ARGV as we scan, so that +eventually all the non-options are at the end. This allows options to be +given in any order, even with programs that were not written to expect this. + +RETURN_IN_ORDER is an option available to programs that were written to +expect options and other argv-elements in any order and that care about the +ordering of the two. We describe each non-option argv-element as if it were +the argument of an option with character code 1. Using `-' as the first +character of the optstring parameter selects this mode of operation. + +The special argument `--' forces an end of option-scanning regardless of the +value of ordering. In the case of RETURN_IN_ORDER, only `--' can cause +getopt() and friends to return EOF with optind != argc. + +2012-08-26: Tried to make the error handling more sus4-like. The functions +return a colon if getopt() and friends detect a missing argument and the +first character of shortopts/optstring starts with a colon (`:'). If getopt() +and friends detect a missing argument and shortopts/optstring does not start +with a colon, the function returns a question mark (`?'). If it was a missing +argument to a short option, optopt is set to the character in question. The +colon goes after the ordering character (`+' or `-'). + +COPYRIGHT NOTICE AND DISCLAIMER: + +Copyright (C) 1997 Gregory Pietsch + +This file and the accompanying getopt.h header file are hereby placed in the +public domain without restrictions. Just give the author credit, don't +claim you wrote it or prevent anyone else from using it. + +Gregory Pietsch's current e-mail address: +gpietsch@comcast.net +****************************************************************************/ + +#ifndef HAVE_GETOPT + +/* include files */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define __need_getopt_newlib +#include <getopt.h> + +typedef struct getopt_data +{ + char *optarg; + int optind, opterr, optopt, optwhere; +} getopt_data; + +/* macros */ + +/* macros defined by this include file */ +#define NO_ARG no_argument +#define REQUIRED_ARG required_argument +#define OPTIONAL_ARG optional_argument + +/* The GETOPT_DATA_INITIALIZER macro is used to initialize a statically- + allocated variable of type struct getopt_data. */ +#define GETOPT_DATA_INITIALIZER {0,0,0,0,0} + +/* types */ +typedef enum GETOPT_ORDERING_T +{ + PERMUTE, + RETURN_IN_ORDER, + REQUIRE_ORDER +} GETOPT_ORDERING_T; + +/* globally-defined variables */ +char *optarg = 0; +int optind = 0; +int opterr = 1; +int optopt = '?'; + +/* static variables */ +static int optwhere = 0; + +/* functions */ + +/* reverse_argv_elements: reverses num elements starting at argv */ +static void +reverse_argv_elements (char **argv, int num) +{ + int i; + char *tmp; + + for (i = 0; i < (num >> 1); i++) + { + tmp = argv[i]; + argv[i] = argv[num - i - 1]; + argv[num - i - 1] = tmp; + } +} + +/* permute: swap two blocks of argv-elements given their lengths */ +static void +permute (char *const argv[], int len1, int len2) +{ + reverse_argv_elements ((char **) argv, len1); + reverse_argv_elements ((char **) argv, len1 + len2); + reverse_argv_elements ((char **) argv, len2); +} + +/* is_option: is this argv-element an option or the end of the option list? */ +static int +is_option (char *argv_element, int only) +{ + return ((argv_element == 0) + || (argv_element[0] == '-') || (only && argv_element[0] == '+')); +} + +/* read_globals: read the values from the globals into a getopt_data + structure */ +static void +read_globals (struct getopt_data *data) +{ + data->optarg = optarg; + data->optind = optind; + data->opterr = opterr; + data->optopt = optopt; + data->optwhere = optwhere; +} + +/* write_globals: write the values into the globals from a getopt_data + structure */ +static void +write_globals (struct getopt_data *data) +{ + optarg = data->optarg; + optind = data->optind; + opterr = data->opterr; + optopt = data->optopt; + optwhere = data->optwhere; +} + +/* getopt_internal: the function that does all the dirty work */ +static int +getopt_internal (int argc, char *const argv[], const char *shortopts, + const struct option *longopts, int *longind, int only, + struct getopt_data *data) +{ + GETOPT_ORDERING_T ordering = PERMUTE; + size_t permute_from = 0; + int num_nonopts = 0; + int optindex = 0; + size_t match_chars = 0; + char *possible_arg = 0; + int longopt_match = -1; + int has_arg = -1; + char *cp = 0; + int arg_next = 0; + int initial_colon = 0; + + /* first, deal with silly parameters and easy stuff */ + if (argc == 0 || argv == 0 || (shortopts == 0 && longopts == 0) + || data->optind >= argc || argv[data->optind] == 0) + return EOF; + if (strcmp (argv[data->optind], "--") == 0) + { + data->optind++; + return EOF; + } + + /* if this is our first time through */ + if (data->optind == 0) + data->optind = data->optwhere = 1; + + /* define ordering */ + if (shortopts != 0 && (*shortopts == '-' || *shortopts == '+')) + { + ordering = (*shortopts == '-') ? RETURN_IN_ORDER : REQUIRE_ORDER; + shortopts++; + } + else + ordering = (getenv ("POSIXLY_CORRECT") != 0) ? REQUIRE_ORDER : PERMUTE; + + /* check for initial colon in shortopts */ + if (shortopts != 0 && *shortopts == ':') + { + ++shortopts; + initial_colon = 1; + } + + /* + * based on ordering, find our next option, if we're at the beginning of + * one + */ + if (data->optwhere == 1) + { + switch (ordering) + { + default: /* shouldn't happen */ + case PERMUTE: + permute_from = data->optind; + num_nonopts = 0; + while (!is_option (argv[data->optind], only)) + { + data->optind++; + num_nonopts++; + } + if (argv[data->optind] == 0) + { + /* no more options */ + data->optind = permute_from; + return EOF; + } + else if (strcmp (argv[data->optind], "--") == 0) + { + /* no more options, but have to get `--' out of the way */ + permute (argv + permute_from, num_nonopts, 1); + data->optind = permute_from + 1; + return EOF; + } + break; + case RETURN_IN_ORDER: + if (!is_option (argv[data->optind], only)) + { + data->optarg = argv[data->optind++]; + return (data->optopt = 1); + } + break; + case REQUIRE_ORDER: + if (!is_option (argv[data->optind], only)) + return EOF; + break; + } + } + /* we've got an option, so parse it */ + + /* first, is it a long option? */ + if (longopts != 0 + && (memcmp (argv[data->optind], "--", 2) == 0 + || (only && argv[data->optind][0] == '+')) && data->optwhere == 1) + { + /* handle long options */ + if (memcmp (argv[data->optind], "--", 2) == 0) + data->optwhere = 2; + longopt_match = -1; + possible_arg = strchr (argv[data->optind] + data->optwhere, '='); + if (possible_arg == 0) + { + /* no =, so next argv might be arg */ + match_chars = strlen (argv[data->optind]); + possible_arg = argv[data->optind] + match_chars; + match_chars = match_chars - data->optwhere; + } + else + match_chars = (possible_arg - argv[data->optind]) - data->optwhere; + for (optindex = 0; longopts[optindex].name != 0; ++optindex) + { + if (memcmp + (argv[data->optind] + data->optwhere, longopts[optindex].name, + match_chars) == 0) + { + /* do we have an exact match? */ + if (match_chars == (int) (strlen (longopts[optindex].name))) + { + longopt_match = optindex; + break; + } + /* do any characters match? */ + else + { + if (longopt_match < 0) + longopt_match = optindex; + else + { + /* we have ambiguous options */ + if (data->opterr) + printf ("%s: option `%s' is ambiguous " + "(could be `--%s' or `--%s')\n", + argv[0], + argv[data->optind], + longopts[longopt_match].name, + longopts[optindex].name); + return (data->optopt = '?'); + } + } + } + } + if (longopt_match >= 0) + has_arg = longopts[longopt_match].has_arg; + } + + /* if we didn't find a long option, is it a short option? */ + if (longopt_match < 0 && shortopts != 0) + { + cp = strchr (shortopts, argv[data->optind][data->optwhere]); + if (cp == 0) + { + /* couldn't find option in shortopts */ + if (data->opterr) + printf ( + "%s: invalid option -- `-%c'\n", + argv[0], argv[data->optind][data->optwhere]); + data->optwhere++; + if (argv[data->optind][data->optwhere] == '\0') + { + data->optind++; + data->optwhere = 1; + } + return (data->optopt = '?'); + } + has_arg = ((cp[1] == ':') + ? ((cp[2] == ':') ? OPTIONAL_ARG : REQUIRED_ARG) : NO_ARG); + possible_arg = argv[data->optind] + data->optwhere + 1; + data->optopt = *cp; + } + + /* get argument and reset data->optwhere */ + arg_next = 0; + switch (has_arg) + { + case OPTIONAL_ARG: + if (*possible_arg == '=') + possible_arg++; + data->optarg = (*possible_arg != '\0') ? possible_arg : 0; + data->optwhere = 1; + break; + case REQUIRED_ARG: + if (*possible_arg == '=') + possible_arg++; + if (*possible_arg != '\0') + { + data->optarg = possible_arg; + data->optwhere = 1; + } + else if (data->optind + 1 >= argc) + { + if (data->opterr) + { + printf ("%s: argument required for option `", argv[0]); + if (longopt_match >= 0) + { + printf ("--%s'\n", longopts[longopt_match].name); + data->optopt = initial_colon ? ':' : '\?'; + } + else + { + printf ("-%c'\n", *cp); + data->optopt = *cp; + } + } + data->optind++; + return initial_colon ? ':' : '\?'; + } + else + { + data->optarg = argv[data->optind + 1]; + arg_next = 1; + data->optwhere = 1; + } + break; + default: /* shouldn't happen */ + case NO_ARG: + if (longopt_match < 0) + { + data->optwhere++; + if (argv[data->optind][data->optwhere] == '\0') + data->optwhere = 1; + } + else + data->optwhere = 1; + data->optarg = 0; + break; + } + + /* do we have to permute or otherwise modify data->optind? */ + if (ordering == PERMUTE && data->optwhere == 1 && num_nonopts != 0) + { + permute (argv + permute_from, num_nonopts, 1 + arg_next); + data->optind = permute_from + 1 + arg_next; + } + else if (data->optwhere == 1) + data->optind = data->optind + 1 + arg_next; + + /* finally return */ + if (longopt_match >= 0) + { + if (longind != 0) + *longind = longopt_match; + if (longopts[longopt_match].flag != 0) + { + *(longopts[longopt_match].flag) = longopts[longopt_match].val; + return 0; + } + else + return longopts[longopt_match].val; + } + else + return data->optopt; +} + +int +getopt (int argc, char *const argv[], const char *optstring) +{ + struct getopt_data data; + int r; + + read_globals (&data); + r = getopt_internal (argc, argv, optstring, 0, 0, 0, &data); + write_globals (&data); + return r; +} + +int +getopt_long (int argc, char *const argv[], const char *shortopts, + const struct option *longopts, int *longind) +{ + struct getopt_data data; + int r; + + read_globals (&data); + r = getopt_internal (argc, argv, shortopts, longopts, longind, 0, &data); + write_globals (&data); + return r; +} + +int +getopt_long_only (int argc, char *const argv[], const char *shortopts, + const struct option *longopts, int *longind) +{ + struct getopt_data data; + int r; + + read_globals (&data); + r = getopt_internal (argc, argv, shortopts, longopts, longind, 1, &data); + write_globals (&data); + return r; +} + +int +__getopt_r (int argc, char *const argv[], const char *optstring, + struct getopt_data *data) +{ + return getopt_internal (argc, argv, optstring, 0, 0, 0, data); +} + +int +__getopt_long_r (int argc, char *const argv[], const char *shortopts, + const struct option *longopts, int *longind, + struct getopt_data *data) +{ + return getopt_internal (argc, argv, shortopts, longopts, longind, 0, data); +} + +int +__getopt_long_only_r (int argc, char *const argv[], const char *shortopts, + const struct option *longopts, int *longind, + struct getopt_data *data) +{ + return getopt_internal (argc, argv, shortopts, longopts, longind, 1, data); +} + +#endif /* !HAVE_GETOPT */ + +/* end of file GETOPT.C */ diff --git a/licenses/getopt.txt b/licenses/getopt.txt new file mode 100644 index 0000000000000000000000000000000000000000..e74d2892e97af47429a03c0869d87b410cd232d5 --- /dev/null +++ b/licenses/getopt.txt @@ -0,0 +1,9 @@ + +COPYRIGHT NOTICE AND DISCLAIMER: + +Copyright (C) 1997 Gregory Pietsch + +This file and the accompanying getopt.h header file are hereby placed in the +public domain without restrictions. Just give the author credit, don't +claim you wrote it or prevent anyone else from using it. + diff --git a/loader.cc b/loader.cc index c256e66521d55ddc447efe50dad8ad349af94f6c..0cae942a5fb7cb3f6386d092526c28849bc78c69 100644 --- a/loader.cc +++ b/loader.cc @@ -12,6 +12,8 @@ #include "drivers/device-factory.hh" #include <jni.h> #include <string.h> +#include <sys/stat.h> +#include <unistd.h> //#include <locale> #include "drivers/virtio-net.hh" @@ -187,24 +189,66 @@ void test_clock_events() clock_event->set_callback(old_callback); } -#define TESTSO_PATH "/usr/lib/tst-dir.so" - -void load_test(elf::program& prog) +void load_test(elf::program& prog, char *path) { - prog.add(TESTSO_PATH); + printf("running %s\n", path); + + prog.add_object(path); auto test_main - = prog.lookup_function<int (void)>("test_main"); - int ret = test_main(); + = prog.lookup_function<int (int, const char **)>("main"); + std::string str = "test"; + const char *name = str.c_str(); + int ret = test_main(1, &name); if (ret) - debug("FAIL"); + printf("failed.\n"); + else + printf("ok.\n"); +} + + +int load_tests(elf::program& prog) +{ +#define TESTDIR "/tests" + DIR *dir = opendir(TESTDIR); + char path[PATH_MAX]; + struct dirent *d; + struct stat st; + + if (!dir) { + perror("failed to open testdir"); + return EXIT_FAILURE; + } + + while ((d = readdir(dir))) { + if (strcmp(d->d_name, ".") == 0 || + strcmp(d->d_name, "..") == 0) + continue; + + snprintf(path, PATH_MAX, "%s/%s", TESTDIR, d->d_name); + if (__xstat(1, path, &st) < 0) { + printf("failed to stat %s\n", path); + continue; + } + if (!S_ISREG(st.st_mode)) { + printf("ignoring %s, not a regular file\n", path); + continue; + } + load_test(prog, path); + } + if (closedir(dir) < 0) { + perror("failed to close testdir"); + return EXIT_FAILURE; + } + + return 0; } #define JVM_PATH "/usr/lib/jvm/jre/lib/amd64/server/libjvm.so" void start_jvm(elf::program& prog) { - prog.add(JVM_PATH); + prog.add_object(JVM_PATH); auto JNI_GetDefaultJavaVMInitArgs = prog.lookup_function<void (void*)>("JNI_GetDefaultJavaVMInitArgs"); @@ -241,7 +285,7 @@ void main_thread(elf::program& prog) debug(fmt("clock@t1 %1%") % t1); debug(fmt("clock@t2 %1%") % t2); -// load_test(prog); +// load_tests(prog); start_jvm(prog); while (true) diff --git a/mempool.cc b/mempool.cc index f445b436b0627bb5fb9e6f088053bf152875d2f6..b15555767c5d11dd228c0d2e7120c2895cd01cf6 100644 --- a/mempool.cc +++ b/mempool.cc @@ -6,6 +6,7 @@ #include <new> #include <boost/utility.hpp> #include <string.h> +#include "libc/libc.hh" namespace memory { @@ -271,6 +272,9 @@ extern "C" { void* malloc(size_t size) { + if ((ssize_t)size < 0) + return libc_error_ptr<void *>(ENOMEM); + if (size <= memory::pool::max_object_size) { size = std::max(size, memory::pool::min_object_size); unsigned n = ilog2_roundup(size); diff --git a/runtime.cc b/runtime.cc index 0130f1cf41ca47ec0683226093420e81afda7b16..5e20935323f555301160757cd0da46866576a7b7 100644 --- a/runtime.cc +++ b/runtime.cc @@ -84,7 +84,7 @@ extern "C" { __locale_t __l) __THROW __nonnull ((2, 4)); size_t __wcsxfrm_l(wchar_t *__s1, __const wchar_t *__s2, size_t __n, __locale_t __loc) __THROW; - + int mallopt(int param, int value); } void *__dso_handle; @@ -412,7 +412,11 @@ int puts(const char *s) UNIMPL(size_t wcslen(const wchar_t *s)) UNIMPL(int wmemcmp(const wchar_t *s1, const wchar_t *s2, size_t n)) UNIMPL(wchar_t *wmemcpy(wchar_t *dest, const wchar_t *src, size_t n)) -UNIMPL(int setvbuf(FILE *stream, char *buf, int mode, size_t size)) +int setvbuf(FILE *stream, char *buf, int mode, size_t size) +{ + debug("stub setvbuf()"); + return 0; +} UNIMPL(size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)) UNIMPL(size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)) UNIMPL(wint_t fgetwc(FILE *stream)) @@ -620,6 +624,12 @@ size_t confstr(int name, char* buf, size_t len) abort(); } +int mallopt(int param, int value) +{ + debug(fmt("mallopt: unimplemented paramater %1%") % param); + return 0; +} + long timezone; char* __environ_array[1]; diff --git a/scripts/run.sh b/scripts/run.sh index b231732e1cc5fe1a1e356c6339f8fa881a4e15f8..dd48c88d85584b833933885bd0f9dd41d81de908 100644 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -5,4 +5,5 @@ qemu-system-x86_64 \ -chardev stdio,mux=on,id=stdio \ -mon chardev=stdio,mode=readline,default \ -device isa-serial,chardev=stdio \ + -device virtio-net-pci \ -drive file=build/debug/loader.img,if=virtio,cache=unsafe diff --git a/tests/tst-dir.c b/tests/tst-dir.c deleted file mode 100644 index 1b8df93d1b3efe602ee1829cf25982638f6b207e..0000000000000000000000000000000000000000 --- a/tests/tst-dir.c +++ /dev/null @@ -1,99 +0,0 @@ - -#include <sys/types.h> -#include <fcntl.h> -#include <dirent.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> - -int sys_mount(char *dev, char *dir, char *fsname, int flags, void *data); -int ll_readdir(int fd, struct dirent *d); - -int test_vfs(void) -{ - struct dirent d; - int fd, ret; - const char test[] = "Hello World! HelloHello!"; - char buf[512]; - ssize_t len; - - fd = open("/test", O_RDWR|O_CREAT, 666); - if (fd < 0) { - printf("open returned %d", fd); - } - - len = sizeof(test); - if ((ret = write(fd, test, len)) != len) { - printf("write failed, len %d out of %zd, errno %d\n", - ret, len, errno); - } - - if (lseek(fd, 0, SEEK_SET) != 0) - printf("lseek returned %d", errno); - - if ((ret = read(fd, buf, sizeof(buf))) < len) { - printf("read failed, len %d out of %ld, errno %d\n", - ret, sizeof(buf), errno); - } - - printf("payload: %s\n", buf); - - close(fd); - - fd = open("/", O_RDONLY, 0); - if (fd < 0) - printf("open root returned %d", fd); - - while (ll_readdir(fd, &d) == 0) { - printf("name: %s, ino: %ld, off: %ld, reclen: %d, type %d\n", - d.d_name, d.d_ino, d.d_off, d.d_reclen, d.d_type); - } - - return ret; -} - -int test_main(void) -{ - DIR *dir = opendir("/usr"); - struct dirent entry, *d; - int ret; - - if (!dir) { - perror("failed to open /usr"); - return EXIT_FAILURE; - } - - printf("testing readdir:\n"); - while ((d = readdir(dir))) { - printf("name: %s, ino: %ld, off: %ld, reclen: %d, type %d\n", - d->d_name, d->d_ino, d->d_off, d->d_reclen, d->d_type); - } - - if (!d && errno) { - perror("readdir failed"); - return EXIT_FAILURE; - } - - printf("testing readdir_r:\n"); - for (;;) { - ret = readdir_r(dir, &entry, &d); - if (ret) { - errno = ret; - perror("readdir_r failed"); - return EXIT_FAILURE; - } - if (!d) - break; - printf("name: %s, ino: %ld, off: %ld, reclen: %d, type %d\n", - d->d_name, d->d_ino, d->d_off, d->d_reclen, d->d_type); - } - - if (closedir(dir) < 0) { - perror("failed to close /"); - return EXIT_FAILURE; - } - - test_vfs(); - return 0; -} diff --git a/tests/tst-pthread.c b/tests/tst-pthread.c index 63bc8619a9453e196fdcd04509702d07739c9bef..bef8bc619aa117e5f041a0cf348920cfbffd505a 100644 --- a/tests/tst-pthread.c +++ b/tests/tst-pthread.c @@ -84,7 +84,7 @@ void* secondary(void *ignore) return NULL; } -int test_main(void) +int main(void) { printf("starting pthread test\n"); pthread_mutex_init(&mutex, NULL);