diff options
-rw-r--r-- | Makefile | 22 | ||||
-rw-r--r-- | README | 2 | ||||
-rw-r--r-- | dist-files.mk | 3 | ||||
-rw-r--r-- | install-from-cwd.c | 14 | ||||
-rw-r--r-- | kernel.c | 286 | ||||
-rw-r--r-- | misc.c | 1 | ||||
-rw-r--r-- | nvidia-installer.h | 3 | ||||
-rwxr-xr-x | rtld_test_Linux-armv7l-gnueabi | bin | 2808 -> 0 bytes | |||
-rwxr-xr-x | rtld_test_Linux-armv7l-gnueabihf | bin | 2820 -> 0 bytes | |||
-rwxr-xr-x | rtld_test_Linux-x86_64 | bin | 3800 -> 0 bytes | |||
-rw-r--r-- | utils.mk | 36 | ||||
-rw-r--r-- | version.mk | 2 |
12 files changed, 161 insertions, 208 deletions
@@ -94,7 +94,11 @@ else endif RTLD_TEST_C = $(OUTPUTDIR)/g_rtld_test.c -RTLD_TEST = rtld_test_$(TARGET_OS)-$(TARGET_ARCH)$(if $(TARGET_ARCH_ABI),-$(TARGET_ARCH_ABI)) +RTLD_TEST = $(OUTPUTDIR)/rtld_test + +# Use a precompiled rtld_test-Linux-x86 binary to simplify the Linux-x86_64 +# build. If a fresh rtld_test-Linux-x86 binary is needed, it can be copied +# from a Linux-x86 build of nvidia-settings. RTLD_TEST_32_C = $(OUTPUTDIR)/g_rtld_test_32.c RTLD_TEST_32 = rtld_test_$(TARGET_OS)-x86 @@ -328,18 +332,12 @@ rebuild_tls_test_dso: tls_test_dso.c tls_test: tls_test.c touch $@ -# rule to rebuild rtld_test; a precompiled rtld_test is distributed with -# nvidia-installer to simplify x86-64 builds. - -$(eval $(call DEBUG_INFO_RULES, rebuild_rtld_test)) -rebuild_rtld_test.unstripped: rtld_test.c $(CONFIG_H) - $(call quiet_cmd,LINK) $(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) -o $(RTLD_TEST) -lGL -lEGL $< +# rule to build a native rtld_test; a precompiled Linux-x86 rtld_test is +# distributed with nvidia-installer to simplify Linux-x86_64 builds. -# dummy rule to override implicit rule that builds dls_test from -# rtld_test.c - -rtld_test: rtld_test.c - touch $@ +$(eval $(call DEBUG_INFO_RULES, $(RTLD_TEST))) +$(RTLD_TEST).unstripped: rtld_test.c $(CONFIG_H) + $(call quiet_cmd,LINK) $(CFLAGS) $(LDFLAGS) $(BIN_LDFLAGS) -o $@ -lGL -lEGL $< ############################################################################## @@ -19,7 +19,7 @@ well commented. Build dependencies of nvidia-installer include: - libkmod ncurses pciutils + ncurses pciutils Please ensure that the appropriate development packages for these dependencies have been installed before building nvidia-installer. diff --git a/dist-files.mk b/dist-files.mk index 0958853..a085691 100644 --- a/dist-files.mk +++ b/dist-files.mk @@ -64,9 +64,6 @@ DIST_FILES += README DIST_FILES += dist-files.mk DIST_FILES += rtld_test_Linux-x86 -DIST_FILES += rtld_test_Linux-x86_64 -DIST_FILES += rtld_test_Linux-armv7l-gnueabi -DIST_FILES += rtld_test_Linux-armv7l-gnueabihf DIST_FILES += tls_test_Linux-x86 DIST_FILES += tls_test_Linux-x86_64 diff --git a/install-from-cwd.c b/install-from-cwd.c index a11f639..43266a1 100644 --- a/install-from-cwd.c +++ b/install-from-cwd.c @@ -536,19 +536,19 @@ precompiled_done: if (!check_development_tools(op, p)) return FALSE; /* - * make sure that the selected or default system compiler - * is compatible with the target kernel; the user may choose - * to override the check. - */ - if (!check_cc_version(op, p)) return FALSE; - - /* * we do not have a prebuilt kernel interface; thus we'll need * to compile the kernel interface, so determine where the * kernel source files are. */ if (!determine_kernel_source_path(op, p)) return FALSE; + + /* + * make sure that the selected or default system compiler + * is compatible with the target kernel; the user may choose + * to override the check. + */ + if (!check_cc_version(op, p)) return FALSE; /* and now, build the kernel interface */ @@ -32,8 +32,7 @@ #include <string.h> #include <limits.h> #include <fts.h> -#include <dlfcn.h> -#include <libkmod.h> +#include <syscall.h> #include "nvidia-installer.h" #include "kernel.h" @@ -63,8 +62,6 @@ static PrecompiledInfo *scan_dir(Options *op, Package *p, static char *build_distro_precompiled_kernel_interface_dir(Options *op); static char *convert_include_path_to_source_path(const char *inc); static char *get_machine_arch(Options *op); -static int init_libkmod(void); -static void close_libkmod(void); static int run_conftest(Options *op, const char *dir, const char *args, char **result); static int run_make(Options *op, Package *p, const char *dir, const char *target, @@ -74,16 +71,6 @@ static void modprobe_remove_kernel_module_quiet(Options *op, const char *name); static int kernel_configuration_conflict(Options *op, Package *p, int target_system_checks); -/* libkmod handle and function pointers */ -static void *libkmod = NULL; -static struct kmod_ctx* (*lkmod_new)(const char*, const char* const*) = NULL; -static struct kmod_ctx* (*lkmod_unref)(struct kmod_ctx*) = NULL; -static struct kmod_module* (*lkmod_module_unref)(struct kmod_module *) = NULL; -static int (*lkmod_module_new_from_path)(struct kmod_ctx*, const char*, - struct kmod_module**) = NULL; -static int (*lkmod_module_insert_module)(struct kmod_module*, unsigned int, - const char*) = NULL; - /* * Message text that is used by several error messages. */ @@ -1063,61 +1050,6 @@ void check_for_warning_messages(Options *op) -/* - * init_libkmod() - Attempt to dlopen() libkmod and the function symbols we - * need from it. Set the global libkmod handle and function pointers on - * success. Return TRUE if loading all symbols succeeded; FALSE otherwise. - */ -static int init_libkmod(void) -{ - if (!libkmod) { - libkmod = dlopen("libkmod.so.2", RTLD_LAZY); - if(!libkmod) { - return FALSE; - } - - lkmod_new = dlsym(libkmod, "kmod_new"); - lkmod_unref = dlsym(libkmod, "kmod_unref"); - lkmod_module_unref = dlsym(libkmod, "kmod_module_unref"); - lkmod_module_new_from_path = dlsym(libkmod, "kmod_module_new_from_path"); - lkmod_module_insert_module = dlsym(libkmod, "kmod_module_insert_module"); - } - - if (libkmod) { - /* libkmod was already open, or was just successfully dlopen()ed: - * check to make sure all of the symbols are set */ - if (lkmod_new && lkmod_unref && lkmod_module_unref && - lkmod_module_new_from_path && lkmod_module_insert_module) { - return TRUE; - } else { - /* One or more symbols missing; abort */ - close_libkmod(); - return FALSE; - } - } - return FALSE; -} /* init_libkmod() */ - - - -/* - * close_libkmod() - clear all libkmod function pointers and dlclose() libkmod - */ -static void close_libkmod(void) -{ - if (libkmod) { - dlclose(libkmod); - } - - libkmod = NULL; - lkmod_new = NULL; - lkmod_unref = NULL; - lkmod_module_unref = NULL; - lkmod_module_new_from_path = NULL; - lkmod_module_insert_module = NULL; -} /* close_libkmod() */ - - #define PRINTK_LOGLEVEL_KERN_ALERT 1 @@ -1168,23 +1100,14 @@ static int set_loglevel(int level, int *old_level) /* - * do_insmod() - load the kernel module using libkmod if available; fall back - * to insmod otherwise. Returns the result of kmod_module_insert_module() if - * available, or of insmod otherwise. Pass the result of module loading up - * through the data argument, regardless of whether we used libkmod or insmod. + * do_insmod() - mmap(2) the kernel module and load it with init_module(2). + * Returns 0 on success, or errno on failure. */ -static int do_insmod(Options *op, const char *module, char **data, - const char *module_opts) +static int do_insmod(Options *op, const char *module, const char *module_opts) { - int ret = 0, libkmod_failed = FALSE, old_loglevel, loglevel_set, i; - - /* SELinux type labels to add to kernel modules */ - static const char *selinux_kmod_types[] = { - "modules_object_t", - NULL - }; - - *data = NULL; + int ret = ENOENT, loglevel_set, old_loglevel, fd = -1; + void *buf = MAP_FAILED; + struct stat st; /* * Temporarily disable most console messages to keep the curses @@ -1195,76 +1118,42 @@ static int do_insmod(Options *op, const char *module, char **data, loglevel_set = set_loglevel(PRINTK_LOGLEVEL_KERN_ALERT, &old_loglevel); - /* Some SELinux policies require specific file type labels for inserting - * kernel modules. Attempt to set known types until one succeeds. If all - * types fail, hopefully it's just because no type is needed. */ - for (i = 0; selinux_kmod_types[i]; i++) { - if (set_security_context(op, module, selinux_kmod_types[i])) { - break; - } + fd = open(module, O_RDONLY); + if (fd < 0) { + goto done; } - if (init_libkmod()) { - struct kmod_ctx *ctx = NULL; - struct kmod_module *mod = NULL; - const char *config_paths = NULL; - - ctx = lkmod_new(NULL, &config_paths); - if (!ctx) { - libkmod_failed = TRUE; - goto kmod_done; - } - - ret = lkmod_module_new_from_path(ctx, module, &mod); - if (ret < 0) { - libkmod_failed = TRUE; - goto kmod_done; - } - - ret = lkmod_module_insert_module(mod, 0, module_opts); - if (ret < 0) { - /* insmod ignores > 0 return codes of kmod_module_insert_module(), - * so we should do it too. On failure, strdup() the error string to - * *data to ensure that it can be freed later. */ - *data = nvstrdup(strerror(-ret)); - } - -kmod_done: - if (mod) { - lkmod_module_unref(mod); - } - if (ctx) { - lkmod_unref(ctx); - } - } else { - if (op->expert) { - ui_log(op, "Unable to load module with libkmod; " - "falling back to insmod."); - } - libkmod_failed = TRUE; + if (fstat(fd, &st) != 0) { + goto done; } - if (!libkmod || libkmod_failed) { - char *cmd; - - /* Fall back to insmod */ + buf = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (buf == MAP_FAILED) { + goto done; + } - cmd = nvstrcat(op->utils[INSMOD], " ", module, " ", module_opts, NULL); + ret = syscall(SYS_init_module, buf, st.st_size, module_opts); + if (ret != 0) { + ret = errno; + } - /* only output the result of the test if in expert mode */ +done: - ret = run_command(op, cmd, data, op->expert, 0, TRUE); - nvfree(cmd); + if (buf != MAP_FAILED) { + /* st is always populated by the time mmap(2) is called */ + munmap(buf, st.st_size); } - close_libkmod(); + if (fd >= 0) { + close(fd); + } if (loglevel_set) { set_loglevel(old_loglevel, NULL); } return ret; -} /* do_insmod() */ +} /* @@ -1275,13 +1164,13 @@ kmod_done: */ static int ignore_load_error(Options *op, Package *p, - const char *module_filename, - const char* data, int insmod_status) + const char *module_filename, int insmod_status) { int ignore_error = FALSE, secureboot, module_sig_force, enokey; const char *probable_reason, *signature_related; + char *error = strerror(insmod_status); - enokey = (-insmod_status == ENOKEY); + enokey = (insmod_status == ENOKEY); secureboot = (secure_boot_enabled() == 1); module_sig_force = (test_kernel_config_option(op, p, "CONFIG_MODULE_SIG_FORCE") == @@ -1357,7 +1246,7 @@ static int ignore_load_error(Options *op, Package *p, if (ignore_error) { ui_log(op, "An error was encountered when loading the kernel " "module, but that error was ignored, and the kernel module " - "will be installed, anyway. The error was: %s", data); + "will be installed, anyway. The error was: %s", error); } else { ui_error(op, "Unable to load the kernel module '%s'. This " "happens most frequently when this kernel module was " @@ -1380,11 +1269,11 @@ static int ignore_load_error(Options *op, Package *p, * the output now. */ - if (!op->expert) ui_log(op, "Kernel module load error: %s", data); + if (!op->expert) ui_log(op, "Kernel module load error: %s", error); } return ignore_error; -} /* ignore_load_error() */ +} /* @@ -1410,8 +1299,9 @@ static void unload_kernel_modules(Options *op, Package *p) { int test_kernel_modules(Options *op, Package *p) { char *cmd = NULL, *data = NULL; - int ret, i; - const char *depmods[] = { "i2c-core", "drm", "drm-kms-helper", "vfio_mdev" }; + int ret = FALSE, i; + const char *depmods[] = { "i2c-core", "drm", "drm-kms-helper", "vfio_mdev", + "ipmi_msghandler" }; /* * If we're building/installing for a different kernel, then we @@ -1436,8 +1326,7 @@ int test_kernel_modules(Options *op, Package *p) */ for (i = 0; i < p->num_kernel_modules; i++) { - int module_success = FALSE; - char *cmd_output; + int module_success = FALSE, insmod_ret; char *module_path = nvstrcat(p->kernel_module_build_directory, "/", p->kernel_modules[i].module_filename, NULL); @@ -1448,14 +1337,14 @@ int test_kernel_modules(Options *op, Package *p) "NVreg_DeviceFileMode=0 NVreg_ModifyDeviceFiles=0"; } - ret = do_insmod(op, module_path, &cmd_output, module_opts); + insmod_ret = do_insmod(op, module_path, module_opts); nvfree(module_path); - if (ret == 0) { + if (insmod_ret == 0) { module_success = TRUE; } else { ret = ignore_load_error(op, p, p->kernel_modules[i].module_filename, - cmd_output, ret); + insmod_ret); if (ret) { op->skip_module_load = TRUE; ui_log(op, "Ignoring failure to load %s.", @@ -1466,8 +1355,6 @@ int test_kernel_modules(Options *op, Package *p) } } - nvfree(cmd_output); - if (!module_success) { goto test_exit; } @@ -2173,12 +2060,6 @@ int check_cc_version(Options *op, Package *p) { char *result; int ret; - Options dummyop; - - const char *choices[2] = { - "Ignore CC version check", - "Abort installation" - }; /* * If we're building/installing for a different kernel, then we @@ -2193,30 +2074,33 @@ int check_cc_version(Options *op, Package *p) return TRUE; } - /* Kernel source/output paths may not be set yet; we don't need them - * for this test, anyway. */ - dummyop = *op; - dummyop.kernel_source_path = "DUMMY_SOURCE_PATH"; - dummyop.kernel_output_path = "DUMMY_OUTPUT_PATH"; - - ret = run_conftest(&dummyop, p->kernel_module_build_directory, + ret = run_conftest(op, p->kernel_module_build_directory, "cc_version_check just_msg", &result); - if (ret) return TRUE; + if (!ret) { + const char *choices[2] = { + "Ignore CC version check", + "Abort installation" + }; + + ret = (ui_multiple_choice(op, choices, 2, 0, + "The CC version check failed:\n\n%s\n\n" + "This may lead to subtle problems; if you " + "are not certain whether the mismatched " + "compiler will be compatible with your " + "kernel, you may wish to abort installation, " + "set the CC environment variable to the name " + "of the compiler used to compile your kernel, " + "and restart installation.", result) == 0); + + if (ret) { + setenv("IGNORE_CC_MISMATCH", "1", 1); + ui_warn(op, "Ignoring CC version mismatch:\n\n%s", result); + } + } - ret = (ui_multiple_choice(op, choices, 2, 1, "The CC version check failed:" - "\n\n%s\n\nIf you know what you are doing you " - "can either ignore the CC version check and " - "continue installation, or abort installation, " - "set the CC environment variable to the name of " - "the compiler used to compile your kernel, and " - "restart installation.", result) == 1); nvfree(result); - - if (!ret) setenv("IGNORE_CC_MISMATCH", "1", 1); - - return !ret; - + return ret; } /* check_cc_version() */ @@ -2561,6 +2445,39 @@ static NVOptionalBool auto_online_blocks(void) return ret; } + +/* + * Get the CPU type from /proc/cpuinfo: this is ppc64le-only for now because + * it's only used by ppc64le-only code, and because the contents of the cpuinfo + * file in procfs vary greatly by CPU architecture. + */ +static char *get_cpu_type(const Options *op) +{ + char *proc_cpuinfo = nvstrcat(op->proc_mount_point, "/", "cpuinfo", NULL); + FILE *fp = fopen(proc_cpuinfo, "r"); + + nvfree(proc_cpuinfo); + if (fp) { + char *line, *ret = NULL; + int eof; + + while((line = fget_next_line(fp, &eof))) { + ret = nvrealloc(ret, strlen(line) + 1); + + if (sscanf(line, "cpu : %s", ret) == 1) { + return ret; + } + + if (eof) { + break; + } + } + + nvfree(ret); + } + + return NULL; +} #endif /* @@ -2579,6 +2496,15 @@ static int kernel_configuration_conflict(Options *op, Package *p, NVOptionalBool auto_online = NV_OPTIONAL_BOOL_DEFAULT; if (target_system_checks) { + char *cpu_type = get_cpu_type(op); + int cpu_is_power8 = strncmp(cpu_type, "POWER8", strlen("POWER8")) == 0; + + nvfree(cpu_type); + if (cpu_is_power8) { + /* No conflict on pre-POWER9 systems */ + return FALSE; + } + auto_online = auto_online_blocks(); } @@ -460,7 +460,6 @@ static const Util __utils[] = { [DKMS] = { "dkms", "dkms" }, /* ModuleUtils */ - [INSMOD] = { "insmod", "module-init-tools' or 'kmod" }, [MODPROBE] = { "modprobe", "module-init-tools' or 'kmod" }, [RMMOD] = { "rmmod", "module-init-tools' or 'kmod" }, [LSMOD] = { "lsmod", "module-init-tools' or 'kmod" }, diff --git a/nvidia-installer.h b/nvidia-installer.h index 3d0dcad..932123d 100644 --- a/nvidia-installer.h +++ b/nvidia-installer.h @@ -69,8 +69,7 @@ typedef enum { typedef enum { MIN_MODULE_UTILS = MAX_SYSTEM_OPTIONAL_UTILS, - INSMOD = MIN_MODULE_UTILS, - MODPROBE, + MODPROBE = MIN_MODULE_UTILS, RMMOD, LSMOD, DEPMOD, diff --git a/rtld_test_Linux-armv7l-gnueabi b/rtld_test_Linux-armv7l-gnueabi Binary files differdeleted file mode 100755 index 9afef55..0000000 --- a/rtld_test_Linux-armv7l-gnueabi +++ /dev/null diff --git a/rtld_test_Linux-armv7l-gnueabihf b/rtld_test_Linux-armv7l-gnueabihf Binary files differdeleted file mode 100755 index 221965d..0000000 --- a/rtld_test_Linux-armv7l-gnueabihf +++ /dev/null diff --git a/rtld_test_Linux-x86_64 b/rtld_test_Linux-x86_64 Binary files differdeleted file mode 100755 index 037cf90..0000000 --- a/rtld_test_Linux-x86_64 +++ /dev/null @@ -80,6 +80,7 @@ HOSTNAME_CMD ?= hostname DATE ?= date GZIP_CMD ?= gzip CHMOD ?= chmod +OBJCOPY ?= objcopy NV_AUTO_DEPEND ?= 1 NV_VERBOSE ?= 0 @@ -271,10 +272,14 @@ endif NV_MODULE_LOGGING_NAME ?= ifeq ($(NV_VERBOSE),0) - quiet_cmd = @$(PRINTF) \ + at_if_quiet := @ + quiet_cmd_no_at = $(PRINTF) \ " $(if $(NV_MODULE_LOGGING_NAME),[ %-17.17s ],%s) $(quiet_$(1))\n" \ "$(NV_MODULE_LOGGING_NAME)" && $($(1)) + quiet_cmd = @$(quiet_cmd_no_at) else + at_if_quiet := + quiet_cmd_no_at = $($(1)) quiet_cmd = $($(1)) endif @@ -295,6 +300,8 @@ quiet_HOST_LINK = $(call define_quiet_cmd,HOST_LINK ,$@) quiet_M4 = $(call define_quiet_cmd,M4 ,$<) quiet_STRIP_CMD = $(call define_quiet_cmd,STRIP ,$@) quiet_HARDLINK = $(call define_quiet_cmd,HARDLINK ,$@) +quiet_LD = $(call define_quiet_cmd,LD ,$@) +quiet_OBJCOPY = $(call define_quiet_cmd,OBJCOPY ,$@) ############################################################################## # Tell gmake to delete the target of a rule if it has changed and its @@ -447,3 +454,30 @@ define DEFINE_STAMP_C_RULE @ $$(PRINTF) "%s\n" "const char *pNV_ID = NV_ID + 11;" >> $$@ endef + +############################################################################## +# Define rules that can be used for embedding a file into an ELF object that +# contains the raw contents of that file and symbols pointing to the embedded +# data. +# +# Note that objcopy will name the symbols in the resulting object file based on +# the filename specified in $(1). For example, +# +# $(eval $(call $(READ_ONLY_OBJECT_FROM_FILE_RULE),a/b/c)) +# +# will create an object named $(OUTPUTDIR)/c.o with the symbols _binary_c_start, +# _binary_c_end, and _binary_c_size. +# +# Arguments: +# $(1): Path to the file to convert +############################################################################## + +define READ_ONLY_OBJECT_FROM_FILE_RULE + $$(OUTPUTDIR)/$$(notdir $(1)).o: $(1) + $(at_if_quiet)cd $$(dir $(1)); \ + $$(call quiet_cmd_no_at,LD) -r -z noexecstack --format=binary \ + $$(notdir $(1)) -o $$(OUTPUTDIR_ABSOLUTE)/$$(notdir $$@) + $$(call quiet_cmd,OBJCOPY) \ + --rename-section .data=.rodata,contents,alloc,load,data,readonly \ + $$@ +endef @@ -1 +1 @@ -NVIDIA_VERSION = 384.90 +NVIDIA_VERSION = 387.12 |