xref: /haiku/src/system/boot/loader/load_driver_settings.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
1 /*
2  * Copyright 2008, Rene Gollent, rene@gollent.com. All rights reserved.
3  * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
4  * Distributed under the terms of the MIT License.
5  */
6 
7 
8 #include "load_driver_settings.h"
9 
10 #include <OS.h>
11 #include <drivers/driver_settings.h>
12 
13 #include <boot/driver_settings.h>
14 #include <boot/kernel_args.h>
15 #include <boot/stage2.h>
16 #include <boot/platform.h>
17 
18 #include <string.h>
19 #include <unistd.h>
20 
21 
22 static driver_settings_file *
23 find_driver_settings_file(const char *name)
24 {
25 	for (driver_settings_file *file = gKernelArgs.driver_settings; file != NULL; file = file->next) {
26 		if (!strcmp(file->name, name))
27 			return file;
28 	}
29 
30 	return NULL;
31 }
32 
33 
34 static status_t
35 load_driver_settings_file(Directory *directory, const char *name)
36 {
37 	int fd = open_from(directory, name, O_RDONLY);
38 	if (fd < 0)
39 		return fd;
40 
41 	struct stat stat;
42 	fstat(fd, &stat);
43 
44 	char *buffer = (char *)kernel_args_malloc(stat.st_size + 1);
45 	if (buffer == NULL)
46 		return B_NO_MEMORY;
47 
48 	if (read(fd, buffer, stat.st_size) != stat.st_size)
49 		return B_IO_ERROR;
50 
51 	driver_settings_file *file = (driver_settings_file *)kernel_args_malloc(sizeof(driver_settings_file));
52 	if (file == NULL) {
53 		kernel_args_free(buffer);
54 		return B_NO_MEMORY;
55 	}
56 
57 	buffer[stat.st_size] = '\0';
58 		// null terminate the buffer
59 
60 	strlcpy(file->name, name, sizeof(file->name));
61 	file->buffer = buffer;
62 	file->size = stat.st_size;
63 
64 	// add it to the list
65 	file->next = gKernelArgs.driver_settings;
66 	gKernelArgs.driver_settings = file;
67 
68 	return B_OK;
69 }
70 
71 
72 status_t
73 load_driver_settings(stage2_args */*args*/, Directory *volume)
74 {
75 	int fd = open_from(volume, "home/config/settings/kernel/drivers", O_RDONLY);
76 	if (fd < B_OK)
77 		return fd;
78 
79 	Directory *settings = (Directory *)get_node_from(fd);
80 	if (settings == NULL)
81 		return B_ENTRY_NOT_FOUND;
82 
83 	void *cookie;
84 	if (settings->Open(&cookie, O_RDONLY) == B_OK) {
85 		char name[B_FILE_NAME_LENGTH];
86 		while (settings->GetNextEntry(cookie, name, sizeof(name)) == B_OK) {
87 			if (!strcmp(name, ".") || !strcmp(name, ".."))
88 				continue;
89 
90 			status_t status = load_driver_settings_file(settings, name);
91 			if (status != B_OK)
92 				dprintf("Could not load \"%s\" error %ld\n", name, status);
93 		}
94 
95 		settings->Close(cookie);
96 	}
97 
98 	// check if a kernel settings file exists
99 	// if it does, prepend it to the safe mode settings. This allows the
100 	// settings from the kernel file to take effect while still allowing
101 	// overrides by safe mode since the settings are searched
102 	// in reverse order. This allows us to permanently set things like
103 	// disable_smp
104 	driver_settings_file *kernelFile = find_driver_settings_file("kernel");
105 	if (kernelFile != NULL) {
106 		driver_settings_file *safemodeFile =
107 			find_driver_settings_file(B_SAFEMODE_DRIVER_SETTINGS);
108 		if (safemodeFile != NULL) {
109 			char *buffer = (char *)kernel_args_malloc(
110 				safemodeFile->size + kernelFile->size + 2);
111 			if (buffer != NULL) {
112 				memcpy(buffer, kernelFile->buffer,
113 					kernelFile->size);
114 
115 				// insert a newline just in case the kernel settings file
116 				// doesn't end with one
117 				buffer[kernelFile->size] = '\n';
118 
119 				memcpy(buffer + kernelFile->size + 1,
120 					safemodeFile->buffer,
121 					safemodeFile->size);
122 
123 				kernel_args_free(safemodeFile->buffer);
124 				safemodeFile->buffer = buffer;
125 				safemodeFile->size = safemodeFile->size +
126 					kernelFile->size + 1;
127 				buffer[safemodeFile->size] = '\0';
128 			}
129 		} else
130 			add_safe_mode_settings(kernelFile->buffer);
131 	}
132 
133 	return B_OK;
134 }
135 
136 
137 status_t
138 add_stage2_driver_settings(stage2_args *args)
139 {
140 	const char **p = args->arguments;
141 	//TODO: split more intelligently
142 	for (; p && *p; p++) {
143 		dprintf("adding args: '%s'\n", *p);
144 		add_safe_mode_settings((char *)*p);
145 	}
146 	return B_OK;
147 }
148 
149 
150 status_t
151 add_safe_mode_settings(char *settings)
152 {
153 	if (settings == NULL || settings[0] == '\0')
154 		return B_OK;
155 
156 	size_t length = strlen(settings);
157 	char *buffer = (char *)kernel_args_malloc(length + 1);
158 	if (buffer == NULL)
159 		return B_NO_MEMORY;
160 
161 	driver_settings_file *file = (driver_settings_file *)kernel_args_malloc(sizeof(driver_settings_file));
162 	if (file == NULL) {
163 		kernel_args_free(buffer);
164 		return B_NO_MEMORY;
165 	}
166 
167 	strlcpy(file->name, B_SAFEMODE_DRIVER_SETTINGS, sizeof(file->name));
168 	memcpy(buffer, settings, length + 1);
169 	file->buffer = buffer;
170 	file->size = length;
171 
172 	// add it to the list
173 	file->next = gKernelArgs.driver_settings;
174 	gKernelArgs.driver_settings = file;
175 
176 	return B_OK;
177 }
178 
179