1 /* tag: plugin interface for openbios forth kernel
2  *
3  * Copyright (C) 2003, 2004 Stefan Reinauer
4  *
5  * See the file "COPYING" for further information about
6  * the copyright and warranty status of this work.
7  */
8 
9 #include "sysinclude.h"
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <dlfcn.h>
14 
15 #include "unix/plugins.h"
16 
17 unsigned char *plugindir = "/usr/share/OpenBIOS/plugins";
18 #define PLUGINDIR  plugindir
19 #define PATHSIZE   256
20 
21 #define CONFIG_DEBUG_PLUGINS
22 
23 typedef struct iorange iorange_t;
24 struct iorange {
25 	const char *name;
26 	unsigned int start;
27 	unsigned int end;
28 	io_ops_t *ops;
29 	iorange_t *next;
30 };
31 
32 static iorange_t *ioranges = NULL;
33 
34 typedef struct plugin plugin_t;
35 struct plugin {
36 	const char *name;
37 	plugin_t *next;
38 };
39 
40 static plugin_t *plugins = NULL;
41 
find_iorange(u32 reg)42 io_ops_t *find_iorange(u32 reg)
43 {
44 	iorange_t *range = ioranges;
45 	while (range) {
46 		if (range->start <= reg && range->end >= reg)
47 			return range->ops;
48 		range = range->next;
49 	}
50 	return NULL;
51 }
52 
register_iorange(const char * name,io_ops_t * ops,unsigned int rstart,unsigned int rend)53 int register_iorange(const char *name, io_ops_t * ops, unsigned int rstart,
54 		     unsigned int rend)
55 {
56 	iorange_t *newrange;
57 
58 	/* intersection check */
59 	newrange = ioranges;
60 	while (newrange) {
61 		int fail = 0;
62 		/* new section swallows old section */
63 		if (newrange->start >= rstart && newrange->end <= rend)
64 			fail = -1;
65 		/* new section start or end point are within range */
66 		if (newrange->start <= rstart && newrange->end >= rstart)
67 			fail = -1;
68 		if (newrange->start <= rend && newrange->end >= rend)
69 			fail = -1;
70 		if (fail) {
71 			printf("Error: overlapping IO regions: %s and %s\n",
72 				newrange->name, name);
73 			return -1;
74 		}
75 		newrange = newrange->next;
76 	}
77 
78 	newrange = malloc(sizeof(iorange_t));
79 
80 	newrange->name = name;
81 	newrange->ops = ops;
82 	newrange->start = rstart;
83 	newrange->end = rend;
84 	newrange->next = ioranges;
85 
86 	ioranges = newrange;
87 
88 	return 0;
89 }
90 
is_loaded(const char * plugin_name)91 int is_loaded(const char *plugin_name)
92 {
93 	plugin_t *p = plugins;
94 	while (p) {
95 		if (!strcmp(plugin_name, p->name))
96 			return -1;
97 		p = p->next;
98 	}
99 	return 0;
100 }
101 
load_plugin(const char * plugin_name)102 int load_plugin(const char *plugin_name)
103 {
104 	void *handle;
105 	char *error;
106 	char path[PATHSIZE];
107 
108 	int (*init_plugin) (void);
109 	char **deps;
110 	char **plugin_info;
111 	plugin_t *p;
112 
113 	if (is_loaded(plugin_name)) {
114 		printf("Plugin %s already loaded.\n", plugin_name);
115 		return 0;
116 	}
117 
118 	strncpy(path, PLUGINDIR, PATHSIZE);
119 	strncat(path, "/plugin_", PATHSIZE);
120 	strncat(path, plugin_name, PATHSIZE);
121 	strncat(path, ".so", PATHSIZE);
122 
123 #if DEBUG
124 	printf("Opening plugin %s\n", path);
125 #endif
126 
127 	handle = dlopen(path, RTLD_LAZY | RTLD_GLOBAL);
128 	if (!handle) {
129 		error = dlerror();
130 		printf("Error: Could not open plugin \"%s\": %s\n",
131 		       plugin_name, error);
132 		exit(1);
133 	}
134 #ifdef CONFIG_DEBUG_PLUGINS
135 	plugin_info = dlsym(handle, "plugin_author");
136 	if ((error = dlerror()) == NULL)
137 		printf("Plugin %s author:  %s\n", plugin_name, *plugin_info);
138 	plugin_info = dlsym(handle, "plugin_license");
139 	if ((error = dlerror()) == NULL)
140 		printf("Plugin %s license: %s\n", plugin_name, *plugin_info);
141 	plugin_info = dlsym(handle, "plugin_description");
142 	if ((error = dlerror()) == NULL)
143 		printf("Plugin %s descr.: %s\n", plugin_name, *plugin_info);
144 #endif
145 	p = malloc(sizeof(plugin_t));
146 	p->next = plugins;
147 	p->name = plugin_name;
148 	plugins = p;
149 
150 	deps = dlsym(handle, "plugin_deps");
151 	if ((error = dlerror()) != NULL)
152 		deps = NULL;
153 
154 
155 	strncpy(path, "plugin_", PATHSIZE);
156 	strncat(path, plugin_name, PATHSIZE);
157 	strncat(path, "_init", PATHSIZE);
158 
159 	init_plugin = dlsym(handle, path);
160 	if ((error = dlerror()) != NULL) {
161 		printf("error: %s\n", error);
162 		exit(1);
163 	}
164 
165 	if (deps) {
166 		int i = 0;
167 		char *walk = deps[0];
168 #ifdef CONFIG_DEBUG_PLUGINS
169 		printf("\nPlugin %s dependencies:", plugin_name);
170 #endif
171 		while (walk) {
172 			printf(" %s", walk);
173 			if (!is_loaded(walk)) {
174 #ifdef CONFIG_DEBUG_PLUGINS
175 				printf("(loading)\n");
176 #endif
177 				load_plugin(walk);
178 			}
179 #ifdef CONFIG_DEBUG_PLUGINS
180 			else {
181 				printf("(loaded)");
182 			}
183 #endif
184 			walk = deps[++i];
185 		}
186 	}
187 
188 	printf("\n");
189 #if DEBUG
190 	printf("Initializing module:\n");
191 #endif
192 
193 	return init_plugin();
194 
195 	// We don't dlclose the handle here since
196 	// we want to keep our symbols for later use.
197 }
198