├── .gitignore
├── LICENSE.txt
├── Makefile
├── cliclient
├── Makefile
├── kexec.c
└── resource.rc
├── clientdll
├── KexecCommon.c
├── KexecCommon.def
├── Makefile
├── about.c
├── resource.h
└── resource.rc
├── common.mk
├── driver
├── Makefile
├── bin2h.py
├── boot
│ ├── bootcode.asm
│ ├── bootinfo.h
│ ├── console.c
│ ├── console.h
│ ├── pagesort.c
│ ├── pagesort.h
│ ├── reassemble.c
│ ├── reassemble.ld
│ ├── stdlib.c
│ ├── stdlib.h
│ ├── string.c
│ ├── string.h
│ ├── verify.c
│ └── verify.h
├── buffer.c
├── buffer.h
├── entry.c
├── io.c
├── io.h
├── kexec.inf.in
├── libpe.c
├── libpe.h
├── linuxboot.c
├── linuxboot.h
├── reboot.c
├── reboot.h
├── resource.rc
├── sha1.c
├── sha1.h
├── util.asm
└── util.h
├── guiclient
├── KexecGui.c
├── Makefile
├── resource.h
└── resource.rc
├── icon
├── Icon.ico
├── IconFull.xcf
├── Icon_16x16.png
├── Icon_16x16.xcf
├── Icon_32x32.png
├── Icon_32x32.xcf
├── Icon_48x48.png
└── Icon_48x48.xcf
├── include
├── KexecCommon.h
└── kexec.h
├── revtag
├── Makefile
└── revtag.py
└── setup
├── EnvVarUpdate.nsh
├── KexecDriver.nsi
├── KexecSetup.nsi
└── Makefile
/.gitignore:
--------------------------------------------------------------------------------
1 | revtag/revtag.h
2 | revtag/revtag.nsh
3 | *.o
4 | *.exe
5 | *.dll
6 | *.sys
7 | *.lib
8 | *.bin
9 | driver/kexec.inf
10 | driver/boot/bootcode.h
11 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # WinKexec: kexec for Windows
2 | # Copyright (C) 2008-2009 John Stumpo
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | include common.mk
18 |
19 | SUBDIRS = revtag driver clientdll cliclient guiclient setup
20 |
21 | all :
22 | set -e; \
23 | for dir in $(SUBDIRS); do \
24 | $(MAKE) -C $$dir ; \
25 | done
26 | .PHONY : all
27 |
28 | clean :
29 | for dir in $(SUBDIRS); do \
30 | $(MAKE) -C $$dir clean ; \
31 | done
32 | .PHONY : clean
33 |
--------------------------------------------------------------------------------
/cliclient/Makefile:
--------------------------------------------------------------------------------
1 | # WinKexec: kexec for Windows
2 | # Copyright (C) 2008-2009 John Stumpo
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | include ../common.mk
18 |
19 | CFLAGS += -I../include
20 |
21 | KEXEC_EXE_OBJECTS = kexec.o resource.o
22 | KEXEC_EXE_LIBS = ../clientdll/KexecCommon.lib -lkernel32 -lmsvcrt
23 |
24 | __main_target : kexec.exe
25 |
26 | kexec.exe : $(KEXEC_EXE_OBJECTS)
27 | $(CC) $(CFLAGS) -o kexec.exe $(KEXEC_EXE_OBJECTS) $(KEXEC_EXE_LIBS)
28 |
29 | clean :
30 | -rm -f kexec.exe *.o
31 | .PHONY : clean
32 |
--------------------------------------------------------------------------------
/cliclient/kexec.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include
22 | #include
23 |
24 | #include "../revtag/revtag.h"
25 |
26 |
27 | /* Handle kexec /l */
28 | static int DoLoad(int argc, char** argv)
29 | {
30 | DWORD klen, ilen, cmdlen;
31 | unsigned char* kbuf;
32 | unsigned char* ibuf = NULL;
33 | unsigned char* cmdline = NULL;
34 | int i;
35 |
36 | /* No args: just load the driver and do nothing else. */
37 | if (argc < 1) {
38 | if (!KxcIsDriverLoaded()) {
39 | printf("Loading the kexec driver... ");
40 | if (!KxcLoadDriver()) {
41 | KxcReportErrorStderr();
42 | exit(EXIT_FAILURE);
43 | }
44 | printf("ok\n");
45 | } else
46 | printf("The kexec driver was already loaded; nothing to do.\n");
47 | exit(EXIT_SUCCESS);
48 | }
49 |
50 | printf("Using kernel: %s\n", argv[0]);
51 |
52 | /* Read the kernel into a buffer. */
53 | printf("Reading kernel... ");
54 | if (!(kbuf = KxcLoadFile(argv[0], &klen))) {
55 | KxcReportErrorStderr();
56 | exit(EXIT_FAILURE);
57 | }
58 | printf("ok\n");
59 |
60 | /* Magic numbers in a Linux kernel image */
61 | if (*(unsigned short*)(kbuf+510) != 0xaa55 ||
62 | strncmp(kbuf+514, "HdrS", 4) != 0)
63 | {
64 | fprintf(stderr, "warning: This does not look like a Linux kernel.\n");
65 | fprintf(stderr, "warning: Loading it anyway.\n");
66 | }
67 |
68 | /* Look for an initrd. */
69 | ilen = cmdlen = 0;
70 | for (i = 1; i < argc; i++) {
71 | /* While we're parsing the cmdline, also tally up how much RAM we need
72 | to hold the final cmdline we send to kexec.sys. */
73 | cmdlen += strlen(argv[i]) + 1;
74 | if (!strncasecmp(argv[i], "initrd=", 7)) {
75 | printf("Using initrd: %s\n", argv[i]+7);
76 |
77 | /* Read the initrd into a buffer. */
78 | printf("Reading initrd... ");
79 | if (!(ibuf = KxcLoadFile(argv[i]+7, &ilen))) {
80 | KxcReportErrorStderr();
81 | exit(EXIT_FAILURE);
82 | }
83 | printf("ok\n");
84 | }
85 | }
86 |
87 | /* Build the final buffer for the cmdline. */
88 | if (cmdlen) {
89 | if ((cmdline = malloc(cmdlen+1)) == NULL) {
90 | perror("Could not allocate buffer for kernel command line");
91 | exit(EXIT_FAILURE);
92 | }
93 | cmdline[0] = '\0';
94 | for (i = 1; i < argc; i++) {
95 | strcat(cmdline, argv[i]);
96 | strcat(cmdline, " ");
97 | }
98 | cmdline[strlen(cmdline)-1] = '\0';
99 | printf("Kernel command line is: %s\n", cmdline);
100 | } else {
101 | printf("Kernel command line is blank.\n");
102 | }
103 |
104 | /* Now let kexec.sys know about it. */
105 | if (!KxcIsDriverLoaded()) {
106 | printf("Loading the kexec driver... ");
107 | if (!KxcLoadDriver()) {
108 | KxcReportErrorStderr();
109 | exit(EXIT_FAILURE);
110 | }
111 | printf("ok\n");
112 | }
113 |
114 | /* Do the kernel... */
115 | printf("Loading kernel into kexec driver... ");
116 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_KERNEL, kbuf, klen, NULL, 0)) {
117 | KxcReportErrorStderr();
118 | exit(EXIT_FAILURE);
119 | }
120 | free(kbuf);
121 | printf("ok\n");
122 |
123 | /* ...and the initrd. */
124 | if (ibuf) {
125 | printf("Loading initrd into kexec driver... ");
126 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_INITRD, ibuf, ilen, NULL, 0)) {
127 | KxcReportErrorStderr();
128 | exit(EXIT_FAILURE);
129 | }
130 | free(ibuf);
131 | printf("ok\n");
132 | } else {
133 | printf("Setting null initrd... ");
134 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_INITRD, NULL, 0, NULL, 0)) {
135 | KxcReportErrorStderr();
136 | exit(EXIT_FAILURE);
137 | }
138 | printf("ok\n");
139 | }
140 |
141 | printf("Setting kernel command line... ");
142 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_KERNEL_COMMAND_LINE, cmdline, cmdlen, NULL, 0)) {
143 | KxcReportErrorStderr();
144 | exit(EXIT_FAILURE);
145 | }
146 | if (cmdline)
147 | free(cmdline);
148 | printf("ok\n");
149 |
150 | exit(EXIT_SUCCESS);
151 | }
152 |
153 |
154 | /* Handle kexec /u */
155 | static int DoUnload(int argc KEXEC_UNUSED, char** argv KEXEC_UNUSED)
156 | {
157 | if (KxcIsDriverLoaded()) {
158 | printf("Unloading the kexec driver... ");
159 | if (!KxcUnloadDriver()) {
160 | KxcReportErrorStderr();
161 | exit(EXIT_FAILURE);
162 | }
163 | printf("ok\n");
164 | } else
165 | printf("The kexec driver was not loaded; nothing to do.\n");
166 | exit(EXIT_SUCCESS);
167 | }
168 |
169 |
170 | /* Handle kexec /c */
171 | static int DoClear(int argc KEXEC_UNUSED, char** argv KEXEC_UNUSED)
172 | {
173 | /* We can't do it without kexec.sys loaded... */
174 | if (!KxcIsDriverLoaded()) {
175 | printf("The kexec driver is not loaded.\n");
176 | exit(EXIT_FAILURE);
177 | }
178 |
179 | printf("Setting null kernel... ");
180 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_KERNEL, NULL, 0, NULL, 0)) {
181 | KxcReportErrorStderr();
182 | exit(EXIT_FAILURE);
183 | }
184 | printf("ok\n");
185 |
186 | printf("Setting null initrd... ");
187 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_INITRD, NULL, 0, NULL, 0)) {
188 | KxcReportErrorStderr();
189 | exit(EXIT_FAILURE);
190 | }
191 | printf("ok\n");
192 |
193 | printf("Setting null kernel command line... ");
194 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_KERNEL_COMMAND_LINE, NULL, 0, NULL, 0)) {
195 | KxcReportErrorStderr();
196 | exit(EXIT_FAILURE);
197 | }
198 | printf("ok\n");
199 |
200 | exit(EXIT_SUCCESS);
201 | }
202 |
203 |
204 | /* Handle kexec /s */
205 | static int DoShow(int argc KEXEC_UNUSED, char** argv KEXEC_UNUSED)
206 | {
207 | DWORD bytecount;
208 | unsigned char* cmdline;
209 |
210 | /* kexec.sys can't tell us anything if it's not loaded... */
211 | if (!KxcIsDriverLoaded()) {
212 | printf("The kexec driver is not loaded. (Use `kexec /l' to load it.)\n");
213 | exit(EXIT_FAILURE);
214 | }
215 |
216 | /* Well, we know this much. */
217 | printf("The kexec driver is active. (Use `kexec /u' to unload it.)\n");
218 |
219 | /* Check the loaded kernel. */
220 | if (!KxcDriverOperation(KEXEC_GET_SIZE | KEXEC_KERNEL, NULL, 0, &bytecount, sizeof(DWORD))) {
221 | fprintf(stderr, "getting kernel size: ");
222 | KxcReportErrorStderr();
223 | exit(EXIT_FAILURE);
224 | }
225 | if (bytecount > 0)
226 | printf("Kernel size: %lu bytes\n", bytecount);
227 | else {
228 | printf("No kernel is loaded.\n");
229 | exit(EXIT_SUCCESS); /* no point in continuing... */
230 | }
231 |
232 | /* Check the loaded initrd. */
233 | if (!KxcDriverOperation(KEXEC_GET_SIZE | KEXEC_INITRD, NULL, 0, &bytecount, sizeof(DWORD))) {
234 | fprintf(stderr, "getting initrd size: ");
235 | KxcReportErrorStderr();
236 | exit(EXIT_FAILURE);
237 | }
238 | if (bytecount > 0)
239 | printf("Initrd size: %lu bytes\n", bytecount);
240 | else
241 | printf("No initrd is loaded.\n");
242 |
243 | /* Check the loaded kernel command line. */
244 | if (!KxcDriverOperation(KEXEC_GET_SIZE | KEXEC_KERNEL_COMMAND_LINE, NULL, 0, &bytecount, sizeof(DWORD))) {
245 | fprintf(stderr, "getting kernel command line size: ");
246 | KxcReportErrorStderr();
247 | exit(EXIT_FAILURE);
248 | }
249 | if (bytecount > 0) {
250 | if (!(cmdline = malloc(bytecount + 1))) {
251 | perror("malloc failure");
252 | exit(EXIT_FAILURE);
253 | }
254 | if (!KxcDriverOperation(KEXEC_GET | KEXEC_KERNEL_COMMAND_LINE, NULL, 0, cmdline, bytecount)) {
255 | fprintf(stderr, "getting kernel command line: ");
256 | KxcReportErrorStderr();
257 | exit(EXIT_FAILURE);
258 | }
259 | cmdline[bytecount] = '\0';
260 | printf("Kernel command line: %s\n", cmdline);
261 | free(cmdline);
262 | } else
263 | printf("No kernel command line is set.\n");
264 |
265 |
266 | exit(EXIT_SUCCESS);
267 | }
268 |
269 |
270 | /* Show help on cmdline usage of kexec. */
271 | static void usage()
272 | {
273 | fprintf(stderr, "%s",
274 | "\n\
275 | WinKexec: kexec for Windows, version " VERSION_STR "\n\
276 | Copyright (C) 2008-2009 John Stumpo\n\
277 | \n\
278 | This program is free software; you may redistribute or modify it under the\n\
279 | terms of the GNU General Public License, version 3 or later. There is\n\
280 | ABSOLUTELY NO WARRANTY, not even for MERCHANTABILITY or FITNESS FOR A\n\
281 | PARTICULAR PURPOSE. See the GPL version 3 for full details.\n\
282 | \n\
283 | Usage: kexec [action] [options]...\n\
284 | Actions:\n\
285 | /l /load Load a Linux kernel.\n\
286 | The next option is the kernel filename. All subsequent options are\n\
287 | passed as the kernel command line. If an initrd= option is given,\n\
288 | the named file will be loaded as an initrd. The kexec driver will\n\
289 | be loaded automatically if it is not loaded. With no options, just\n\
290 | load the kexec driver without loading a kernel.\n\
291 | /u /unload Unload the kexec driver. (Naturally, this causes it to\n\
292 | forget the currently loaded kernel, if any, as well.)\n\
293 | /c /clear Clear the currently loaded Linux kernel, but leave the\n\
294 | kexec driver loaded.\n\
295 | /s /show Show current state of kexec.\n\
296 | /h /? /help Show this help.\n\
297 | \n");
298 | exit(EXIT_FAILURE);
299 | }
300 |
301 |
302 | /* Entry point */
303 | int main(int argc, char** argv)
304 | {
305 | int (*action)(int, char**) = NULL;
306 |
307 | /* No args given, no sense in doing anything. */
308 | if (argc < 2)
309 | usage();
310 |
311 | KxcInit();
312 |
313 | /* Allow Unix-style cmdline options. */
314 | if (argv[1][0] == '-') {
315 | if (argv[1][1] == '-')
316 | argv[1]++;
317 | argv[1][0] = '/';
318 | }
319 |
320 | /* Decide what to do... */
321 | if (!strcasecmp(argv[1], "/l") || !strcasecmp(argv[1], "/load"))
322 | action = DoLoad;
323 |
324 | if (!strcasecmp(argv[1], "/u") || !strcasecmp(argv[1], "/unload"))
325 | action = DoUnload;
326 |
327 | if (!strcasecmp(argv[1], "/c") || !strcasecmp(argv[1], "/clear"))
328 | action = DoClear;
329 |
330 | if (!strcasecmp(argv[1], "/s") || !strcasecmp(argv[1], "/show"))
331 | action = DoShow;
332 |
333 | if (!action)
334 | usage();
335 |
336 | /* ...and do it. */
337 | exit(action(argc - 2, argv + 2));
338 | }
339 |
--------------------------------------------------------------------------------
/cliclient/resource.rc:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include "../revtag/revtag.h"
22 |
23 | LANGUAGE 9, 1
24 |
25 | VS_VERSION_INFO VERSIONINFO
26 | FILEVERSION RES_VERSION
27 | PRODUCTVERSION RES_VERSION
28 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
29 | FILEOS VOS_NT_WINDOWS32
30 | FILETYPE VFT_APP
31 | FILESUBTYPE VFT2_UNKNOWN
32 | BEGIN
33 | BLOCK "StringFileInfo"
34 | BEGIN
35 | BLOCK "040904B0"
36 | BEGIN
37 | VALUE "CompanyName", "John Stumpo"
38 | VALUE "FileDescription", "Kexec for Windows"
39 | VALUE "FileVersion", VERSION_STR
40 | VALUE "InternalName", "kexec.exe"
41 | VALUE "LegalCopyright", "\251 2008-2009 John Stumpo. GNU GPL v3 or later."
42 | VALUE "OriginalFilename", "kexec.exe"
43 | VALUE "ProductName", "WinKexec"
44 | VALUE "ProductVersion", VERSION_STR
45 | END
46 | END
47 | BLOCK "VarFileInfo"
48 | BEGIN
49 | VALUE "Translation", 0x409, 1200
50 | END
51 | END
52 |
--------------------------------------------------------------------------------
/clientdll/KexecCommon.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #define IN_KEXEC_COMMON
19 | #undef NDEBUG
20 | #include
21 | #include
22 |
23 | static char kxciLastErrorMsg[256];
24 |
25 | HINSTANCE hInst;
26 |
27 |
28 | /* Convenient wrapper around FormatMessage() and GetLastError() */
29 | static LPSTR KxciTranslateError(void)
30 | {
31 | static LPSTR msgbuf = NULL;
32 |
33 | if (msgbuf) {
34 | LocalFree(msgbuf);
35 | msgbuf = NULL;
36 | }
37 |
38 | FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
39 | NULL, GetLastError(), LANG_USER_DEFAULT, (LPSTR)&msgbuf, 0, NULL);
40 |
41 | return msgbuf;
42 | }
43 |
44 |
45 | /* Set the most recent KexecCommon-related error message. */
46 | static void KxciBuildErrorMessage(LPSTR errmsg)
47 | {
48 | snprintf(kxciLastErrorMsg, 255, "%s: %s", errmsg, KxciTranslateError());
49 | kxciLastErrorMsg[255] = '\0';
50 | }
51 |
52 |
53 | /* Reset the error message. */
54 | static void KxciResetErrorMessage(void)
55 | {
56 | memset(kxciLastErrorMsg, 0, 256);
57 | }
58 |
59 |
60 | /* Did an error occur? */
61 | KEXEC_DLLEXPORT BOOL KxcErrorOccurred(void)
62 | {
63 | return (strlen(kxciLastErrorMsg) > 0);
64 | }
65 |
66 | /* Get the KexecCommon error message. */
67 | KEXEC_DLLEXPORT const char* KxcGetErrorMessage(void)
68 | {
69 | if (KxcErrorOccurred())
70 | return kxciLastErrorMsg;
71 | else
72 | return NULL;
73 | }
74 |
75 |
76 | /* Report an error to stderr. */
77 | KEXEC_DLLEXPORT void KxcReportErrorStderr(void)
78 | {
79 | if (KxcErrorOccurred())
80 | fprintf(stderr, "%s\n", kxciLastErrorMsg);
81 | }
82 |
83 |
84 | /* Report an error to stderr. */
85 | KEXEC_DLLEXPORT void KxcReportErrorMsgbox(HWND parent)
86 | {
87 | if (KxcErrorOccurred())
88 | MessageBox(parent, kxciLastErrorMsg, "KexecCommon", MB_ICONERROR | MB_OK);
89 | }
90 |
91 |
92 | /* Read a file into memory. */
93 | KEXEC_DLLEXPORT PVOID KxcLoadFile(const char* filename, DWORD* length)
94 | {
95 | HANDLE hFile;
96 | PVOID buf;
97 | DWORD filelen, readlen;
98 |
99 | /* Open it... */
100 | if ((hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
101 | KxciBuildErrorMessage("Failed to load file");
102 | return NULL;
103 | }
104 |
105 | /* ...get the size... */
106 | if ((filelen = GetFileSize(hFile, NULL)) == INVALID_FILE_SIZE) {
107 | KxciBuildErrorMessage("Failed to get file size");
108 | CloseHandle(hFile);
109 | return NULL;
110 | }
111 |
112 | /* ...grab a buffer... */
113 | if ((buf = malloc(filelen)) == NULL) {
114 | snprintf(kxciLastErrorMsg, 255, "%s: %s", "Could not allocate buffer for file", strerror(errno));
115 | kxciLastErrorMsg[255] = '\0';
116 | CloseHandle(hFile);
117 | return NULL;
118 | }
119 | /* ...read it in... */
120 | if (!ReadFile(hFile, buf, filelen, &readlen, NULL)) {
121 | KxciBuildErrorMessage("Could not read file");
122 | CloseHandle(hFile);
123 | return NULL;
124 | }
125 | assert(filelen == readlen);
126 | /* ...and close it. */
127 | CloseHandle(hFile);
128 |
129 | *length = readlen;
130 | return buf;
131 | }
132 |
133 |
134 | /* Perform a driver operation by ioctl'ing the kexec virtual device. */
135 | KEXEC_DLLEXPORT BOOL KxcDriverOperation(DWORD opcode, LPVOID ibuf, DWORD ibuflen, LPVOID obuf, DWORD obuflen)
136 | {
137 | HANDLE dev;
138 | DWORD foo;
139 | DWORD filemode;
140 |
141 | KxciResetErrorMessage();
142 |
143 | if ((opcode & KEXEC_OPERATION_MASK) == KEXEC_SET)
144 | filemode = GENERIC_WRITE;
145 | else
146 | filemode = GENERIC_READ;
147 |
148 | /* \\.\kexec is the interface to kexec.sys. */
149 | if ((dev = CreateFile("\\\\.\\kexec", filemode, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) {
150 | KxciBuildErrorMessage("Failed to open \\\\.\\kexec");
151 | return FALSE;
152 | }
153 |
154 | if (!DeviceIoControl(dev, opcode, ibuf, ibuflen, obuf, obuflen, &foo, NULL)) {
155 | KxciBuildErrorMessage("Driver operation failed");
156 | CloseHandle(dev);
157 | return FALSE;
158 | }
159 |
160 | CloseHandle(dev);
161 | return TRUE;
162 | }
163 |
164 |
165 | /* Is the kexec driver loaded? */
166 | KEXEC_DLLEXPORT BOOL KxcIsDriverLoaded(void)
167 | {
168 | SC_HANDLE Scm;
169 | SC_HANDLE KexecService;
170 | SERVICE_STATUS_PROCESS ServiceStatus;
171 | BOOL retval;
172 | DWORD ExtraBytes;
173 |
174 | KxciResetErrorMessage();
175 |
176 | Scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
177 | if (!Scm) {
178 | KxciBuildErrorMessage("Could not open SCM");
179 | KxcReportErrorMsgbox(NULL);
180 | exit(EXIT_FAILURE);
181 | }
182 |
183 | KexecService = OpenService(Scm, "kexec", SERVICE_ALL_ACCESS);
184 | if (!KexecService) {
185 | KxciBuildErrorMessage("Could not open the kexec service");
186 | KxcReportErrorMsgbox(NULL);
187 | CloseServiceHandle(Scm);
188 | exit(EXIT_FAILURE);
189 | }
190 |
191 | if (!QueryServiceStatusEx(KexecService, SC_STATUS_PROCESS_INFO, (LPBYTE)&ServiceStatus,
192 | sizeof(ServiceStatus), &ExtraBytes))
193 | {
194 | KxciBuildErrorMessage("Could not query the kexec service");
195 | KxcReportErrorMsgbox(NULL);
196 | CloseServiceHandle(KexecService);
197 | CloseServiceHandle(Scm);
198 | exit(EXIT_FAILURE);
199 | }
200 |
201 | retval = (ServiceStatus.dwCurrentState == SERVICE_RUNNING);
202 | CloseServiceHandle(KexecService);
203 | CloseServiceHandle(Scm);
204 | return retval;
205 | }
206 |
207 |
208 | /* Load kexec.sys into the kernel, if it isn't already. */
209 | KEXEC_DLLEXPORT BOOL KxcLoadDriver(void)
210 | {
211 | SC_HANDLE Scm;
212 | SC_HANDLE KexecService;
213 |
214 | KxciResetErrorMessage();
215 |
216 | if (KxcIsDriverLoaded())
217 | return TRUE;
218 |
219 | Scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
220 | if (!Scm) {
221 | KxciBuildErrorMessage("Could not open SCM");
222 | return FALSE;
223 | }
224 |
225 | KexecService = OpenService(Scm, "kexec", SERVICE_ALL_ACCESS);
226 | if (!KexecService) {
227 | KxciBuildErrorMessage("Could not open the kexec service");
228 | CloseServiceHandle(Scm);
229 | return FALSE;
230 | }
231 |
232 | /* This does not return until DriverEntry() has completed in kexec.sys. */
233 | if (!StartService(KexecService, 0, NULL)) {
234 | KxciBuildErrorMessage("Could not start the kexec service");
235 | CloseServiceHandle(KexecService);
236 | CloseServiceHandle(Scm);
237 | return FALSE;
238 | }
239 |
240 | CloseServiceHandle(KexecService);
241 | CloseServiceHandle(Scm);
242 | return TRUE;
243 | }
244 |
245 |
246 | /* If kexec.sys is loaded into the kernel, unload it. */
247 | KEXEC_DLLEXPORT BOOL KxcUnloadDriver(void)
248 | {
249 | SC_HANDLE Scm;
250 | SC_HANDLE KexecService;
251 | SERVICE_STATUS ServiceStatus;
252 |
253 | KxciResetErrorMessage();
254 |
255 | if (!KxcIsDriverLoaded())
256 | return TRUE;
257 |
258 | Scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
259 | if (!Scm) {
260 | KxciBuildErrorMessage("Could not open SCM");
261 | return FALSE;
262 | }
263 |
264 | KexecService = OpenService(Scm, "kexec", SERVICE_ALL_ACCESS);
265 | if (!KexecService) {
266 | KxciBuildErrorMessage("Could not open the kexec service");
267 | CloseServiceHandle(Scm);
268 | return FALSE;
269 | }
270 |
271 | /* This does not return until DriverUnload() has completed in kexec.sys. */
272 | if (!ControlService(KexecService, SERVICE_CONTROL_STOP, &ServiceStatus)) {
273 | KxciBuildErrorMessage("Could not stop the kexec service");
274 | CloseServiceHandle(KexecService);
275 | CloseServiceHandle(Scm);
276 | return FALSE;
277 | }
278 |
279 | CloseServiceHandle(KexecService);
280 | CloseServiceHandle(Scm);
281 | return TRUE;
282 | }
283 |
284 |
285 | KEXEC_DLLEXPORT void KxcInit(void)
286 | {
287 | KxciResetErrorMessage();
288 | }
289 |
290 | BOOL WINAPI DllMain(HINSTANCE in_hInst, DWORD reason KEXEC_UNUSED,
291 | LPVOID lpvReserved KEXEC_UNUSED)
292 | {
293 | hInst = in_hInst;
294 | return TRUE;
295 | }
296 |
--------------------------------------------------------------------------------
/clientdll/KexecCommon.def:
--------------------------------------------------------------------------------
1 | ; WinKexec: kexec for Windows
2 | ; Copyright (C) 2008 John Stumpo
3 | ;
4 | ; This program is free software: you can redistribute it and/or modify
5 | ; it under the terms of the GNU General Public License as published by
6 | ; the Free Software Foundation, either version 3 of the License, or
7 | ; (at your option) any later version.
8 | ;
9 | ; This program is distributed in the hope that it will be useful,
10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | ; GNU General Public License for more details.
13 | ;
14 | ; You should have received a copy of the GNU General Public License
15 | ; along with this program. If not, see .
16 |
17 | EXPORTS
18 | KxcErrorOccurred
19 | KxcGetErrorMessage
20 | KxcReportErrorStderr
21 | KxcReportErrorMsgbox
22 | KxcAboutWinKexec
23 | KxcLoadFile
24 | KxcDriverOperation
25 | KxcIsDriverLoaded
26 | KxcLoadDriver
27 | KxcUnloadDriver
28 | KxcInit
29 |
--------------------------------------------------------------------------------
/clientdll/Makefile:
--------------------------------------------------------------------------------
1 | # WinKexec: kexec for Windows
2 | # Copyright (C) 2008-2009 John Stumpo
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | include ../common.mk
18 |
19 | CFLAGS += -I../include
20 |
21 | KEXECCOMMON_DLL_OBJECTS = about.o KexecCommon.o resource.o
22 | KEXECCOMMON_DLL_LIBS = -lkernel32 -lmsvcrt -ladvapi32 -luser32 -lshell32 -lgdi32
23 |
24 | __main_target : KexecCommon.dll KexecCommon.lib
25 |
26 | # We use -mdll so then only DLLEXPORTed stuff is exported.
27 | KexecCommon.dll : $(KEXECCOMMON_DLL_OBJECTS)
28 | $(CC) $(CFLAGS) -mdll -o KexecCommon.dll $(KEXECCOMMON_DLL_OBJECTS) $(KEXECCOMMON_DLL_LIBS)
29 |
30 | KexecCommon.lib : KexecCommon.dll KexecCommon.def
31 | $(DLLTOOL) -l KexecCommon.lib -D KexecCommon.dll -d KexecCommon.def
32 |
33 | clean :
34 | -rm -f KexecCommon.dll KexecCommon.lib *.o
35 | .PHONY : clean
36 |
--------------------------------------------------------------------------------
/clientdll/about.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | *
17 | *
18 | * Some code for the implementation of the "About WinKexec" dialog box
19 | * (specifically, the code supporting the hyperlink to the home page) is
20 | * derived from the nsDialogs plugin for NSIS.
21 | *
22 | * Copyright (C) 1995-2009 Contributors
23 | *
24 | * This software is provided 'as-is', without any express or implied
25 | * warranty. In no event will the authors be held liable for any damages
26 | * arising from the use of this software.
27 | *
28 | * Permission is granted to anyone to use this software for any purpose,
29 | * including commercial applications, and to alter it and redistribute it
30 | * freely, subject to the following restrictions:
31 | *
32 | * 1. The origin of this software must not be misrepresented; you must
33 | * not claim that you wrote the original software. If you use this
34 | * software in a product, an acknowledgment in the product
35 | * documentation would be appreciated but is not required.
36 | *
37 | * 2. Altered source versions must be plainly marked as such, and must
38 | * not be misrepresented as being the original software.
39 | *
40 | * 3. This notice may not be removed or altered from any source
41 | * distribution.
42 | */
43 |
44 | #define IN_KEXEC_COMMON
45 | #include
46 | #include "resource.h"
47 |
48 | #ifndef ODS_NOFOCUSRECT
49 | #define ODS_NOFOCUSRECT 0x0200
50 | #endif
51 |
52 | extern HINSTANCE hInst;
53 |
54 |
55 | /* Window procedure for links in the "About WinKexec" dialog. */
56 | static BOOL CALLBACK KxciLinkWndProc(HWND hWnd, UINT msg,
57 | WPARAM wParam, LPARAM lParam)
58 | {
59 | switch (msg) {
60 | case WM_SETCURSOR:
61 | SetCursor(LoadCursor(NULL, IDC_HAND));
62 | return TRUE;
63 |
64 | default:
65 | return CallWindowProc((WNDPROC)GetWindowLong(hWnd, GWL_USERDATA),
66 | hWnd, msg, wParam, lParam);
67 | }
68 | return TRUE;
69 | }
70 |
71 |
72 | /* Procedure for the "About WinKexec" dialog. */
73 | static BOOL CALLBACK KxciAboutDlgProc(HWND hDlg, UINT msg,
74 | WPARAM wParam, LPARAM lParam)
75 | {
76 | HWND hCtl;
77 | DRAWITEMSTRUCT* dis;
78 | char linktext[1024];
79 | RECT rect;
80 | COLORREF oldcolor;
81 |
82 | switch (msg) {
83 | case WM_INITDIALOG:
84 | /* Set the chained window procedure on the link. */
85 | hCtl = GetDlgItem(hDlg, KXC_ID_HOMEPAGE);
86 | SetWindowLong(hCtl, GWL_USERDATA,
87 | SetWindowLong(hCtl, GWL_WNDPROC, (LONG)KxciLinkWndProc));
88 | break;
89 |
90 | case WM_COMMAND:
91 | /* A widget was triggered. */
92 | hCtl = (HWND)lParam;
93 | switch (LOWORD(wParam)) {
94 | case IDCANCEL:
95 | EndDialog(hDlg, IDCANCEL);
96 | break;
97 |
98 | case KXC_ID_HOMEPAGE:
99 | ShellExecute(hDlg, "open", "http://www.jstump.com/",
100 | NULL, NULL, SW_SHOW);
101 | break;
102 |
103 | default:
104 | return FALSE;
105 | }
106 | break;
107 |
108 | case WM_DRAWITEM:
109 | /* The custom drawing routine for the hyperlinks. */
110 | dis = (DRAWITEMSTRUCT*)lParam;
111 | rect = dis->rcItem;
112 | linktext[0] = '\0';
113 | if (dis->itemAction & ODA_DRAWENTIRE) {
114 | GetWindowText(dis->hwndItem, linktext, 1024);
115 | oldcolor = SetTextColor(dis->hDC, RGB(0, 0, 192));
116 | DrawText(dis->hDC, linktext, -1, &rect, 0);
117 | SetTextColor(dis->hDC, oldcolor);
118 | }
119 | if (( (dis->itemAction & ODA_FOCUS) ||
120 | ((dis->itemAction & ODA_DRAWENTIRE) && (dis->itemState & ODS_FOCUS))
121 | ) && !(dis->itemState & ODS_NOFOCUSRECT))
122 | DrawFocusRect(dis->hDC, &rect);
123 | break;
124 |
125 | default:
126 | return FALSE;
127 | }
128 | return TRUE;
129 | }
130 |
131 |
132 | /* Display the "About WinKexec" dialog. */
133 | KEXEC_DLLEXPORT void KxcAboutWinKexec(HWND parent)
134 | {
135 | DialogBox(hInst, MAKEINTRESOURCE(KXC_ABOUT_DLG), parent, KxciAboutDlgProc);
136 | }
137 |
--------------------------------------------------------------------------------
/clientdll/resource.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KXC_RESOURCE_H
19 | #define KXC_RESOURCE_H
20 |
21 | #define KXC_ABOUT_DLG 1
22 |
23 | #define KXC_ID_HOMEPAGE 20
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/clientdll/resource.rc:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include "resource.h"
22 |
23 | #include "../revtag/revtag.h"
24 |
25 | LANGUAGE 9, 1
26 |
27 | VS_VERSION_INFO VERSIONINFO
28 | FILEVERSION RES_VERSION
29 | PRODUCTVERSION RES_VERSION
30 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
31 | FILEOS VOS_NT_WINDOWS32
32 | FILETYPE VFT_DLL
33 | FILESUBTYPE VFT2_UNKNOWN
34 | BEGIN
35 | BLOCK "StringFileInfo"
36 | BEGIN
37 | BLOCK "040904B0"
38 | BEGIN
39 | VALUE "CompanyName", "John Stumpo"
40 | VALUE "FileDescription", "Kexec for Windows common functions"
41 | VALUE "FileVersion", VERSION_STR
42 | VALUE "InternalName", "KexecCommon.dll"
43 | VALUE "LegalCopyright", "\251 2008-2009 John Stumpo. GNU GPL v3 or later."
44 | VALUE "OriginalFilename", "KexecCommon.dll"
45 | VALUE "ProductName", "WinKexec"
46 | VALUE "ProductVersion", VERSION_STR
47 | END
48 | END
49 | BLOCK "VarFileInfo"
50 | BEGIN
51 | VALUE "Translation", 0x409, 1200
52 | END
53 | END
54 |
55 | KXC_ABOUT_DLG DIALOGEX 0, 0, 260, 135
56 | STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
57 | CAPTION "About WinKexec"
58 | FONT 8, "MS Shell Dlg", 0, 0, 1
59 | BEGIN
60 | DEFPUSHBUTTON "OK", IDCANCEL, 203, 114, 50, 14
61 |
62 | GROUPBOX "About WinKexec", 50, 7, 7, 246, 103
63 |
64 | LTEXT "WinKexec version " VERSION_STR "\r\n"
65 | "Copyright \251 2008-2009 John Stumpo\r\n"
66 | "\r\n"
67 | "WinKexec is free software under the GNU General Public License version "
68 | "3 or later; you are free to modify and redistribute it under certain "
69 | "conditions. There is ABSOLUTELY NO WARRANTY, to the extent allowable "
70 | "by applicable law.", 2000, 13, 18, 234, 72
71 |
72 | PUSHBUTTON "Home page: http://www.jstump.com/", KXC_ID_HOMEPAGE, 13, 93, 234, 10, BS_OWNERDRAW
73 | END
74 |
--------------------------------------------------------------------------------
/common.mk:
--------------------------------------------------------------------------------
1 | # WinKexec: kexec for Windows
2 | # Copyright (C) 2008-2009 John Stumpo
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | CC = $(CROSS)gcc
18 | ifdef DEBUG
19 | CFLAGS = -g3 -O2 -W -Wall -mno-cygwin
20 | else
21 | CFLAGS = -s -O2 -W -Wall -mno-cygwin
22 | endif
23 | CYGPATH = cygpath
24 | DLLTOOL = $(CROSS)dlltool
25 | LD = $(CROSS)ld
26 | ifeq ($(CROSS),)
27 | # Use the Registry to locate the NSIS install path.
28 | MAKENSIS = "$(shell $(CYGPATH) "$(shell cat /proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/NSIS/@)")/makensis.exe"
29 | else
30 | MAKENSIS = makensis
31 | endif
32 | NASM = nasm
33 | OBJCOPY = $(CROSS)objcopy
34 | PYTHON = python
35 | WINDRES = $(CROSS)windres
36 |
37 | all : __main_target
38 | .PHONY : all
39 | .PHONY : __main_target
40 |
41 | .rc.o :
42 | $(WINDRES) $(RCFLAGS) -o $@ $<
43 |
44 | .asm.o :
45 | $(NASM) $(NASMFLAGS) -f coff -o $@ $<
46 |
47 | .asm.bin :
48 | $(NASM) $(NASMFLAGS) -f bin -o $@ $<
49 |
50 | .SUFFIXES :
51 | .SUFFIXES : .c .o .rc .asm .bin
52 |
--------------------------------------------------------------------------------
/driver/Makefile:
--------------------------------------------------------------------------------
1 | # WinKexec: kexec for Windows
2 | # Copyright (C) 2008-2009 John Stumpo
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | include ../common.mk
18 |
19 | CFLAGS += -I../include -DDRIVER
20 |
21 | KEXEC_SYS_OBJECTS = buffer.o entry.o io.o libpe.o linuxboot.o reboot.o resource.o sha1.o util.o
22 | KEXEC_SYS_LIBS = -lntoskrnl -lhal
23 |
24 | # boot/reassemble.o *must* be first!
25 | # The entry point is the first function in the first file given.
26 | BOOT_REASSEMBLE_EXE_OBJECTS = boot/reassemble.o boot/console.o boot/pagesort.o boot/stdlib.o boot/string.o boot/verify.o sha1.o util.o
27 |
28 | __main_target : kexec.sys kexec.inf
29 |
30 | # Using -shared exports every symbol, but otherwise it would be impossible to debug it efficiently with WinDbg...
31 | kexec.sys : $(KEXEC_SYS_OBJECTS)
32 | $(CC) $(CFLAGS) -shared -nostdlib -Wl,--entry,_DriverEntry@8 -o kexec.sys $(KEXEC_SYS_OBJECTS) $(KEXEC_SYS_LIBS)
33 |
34 | kexec.inf : kexec.inf.in
35 | $(PYTHON) ../revtag/revtag.py --tag-file .. kexec.inf.in >kexec.inf
36 |
37 | clean :
38 | -rm -f kexec.sys kexec.inf *.o boot/*.bin boot/*.exe boot/*.o boot/bootcode.h
39 | .PHONY : clean
40 |
41 | linuxboot.o : boot/bootcode.h
42 |
43 | boot/bootcode.bin : boot/reassemble.bin
44 |
45 | boot/reassemble.bin : boot/reassemble.exe
46 | $(OBJCOPY) -O binary -j .text boot/reassemble.exe boot/reassemble.bin
47 |
48 | boot/reassemble.exe : $(BOOT_REASSEMBLE_EXE_OBJECTS)
49 | $(LD) -s -T boot/reassemble.ld -o boot/reassemble.exe $(BOOT_REASSEMBLE_EXE_OBJECTS)
50 |
51 | .bin.h :
52 | $(PYTHON) bin2h.py $< $@ "$(shell basename $< | sed -e 's/[^a-z]/_/g')"
53 |
54 | .SUFFIXES : .bin .h
55 |
--------------------------------------------------------------------------------
/driver/bin2h.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # WinKexec: kexec for Windows
3 | # Copyright (C) 2008-2009 John Stumpo
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import sys
19 | import time
20 |
21 | def usage():
22 | sys.stderr.write('''usage: %s [bin_file] [h_file] [array_name]
23 |
24 | Converts a binary file to an unsigned char array in a C header file.
25 | ''' % sys.argv[0])
26 | sys.exit(1)
27 |
28 | if len(sys.argv) != 4:
29 | usage()
30 |
31 | bin_file = open(sys.argv[1], 'rb').read()
32 |
33 | h_file = open(sys.argv[2], 'w')
34 | h_file.write('''/* This file is generated by a script.
35 | * DO NOT EDIT THIS FILE!
36 | *
37 | * Created by %s from %s.
38 | * %s
39 | */
40 |
41 | #define %s_SIZE %d
42 | static const unsigned char %s[] = {''' %
43 | (sys.argv[0], sys.argv[1], time.asctime(),
44 | sys.argv[3].upper(), len(bin_file), sys.argv[3]))
45 |
46 | for i in range(len(bin_file)):
47 | if i % 8 == 0:
48 | h_file.write('\n /* 0x%08x */ 0x%02x,' % (i, ord(bin_file[i])))
49 | else:
50 | h_file.write(' 0x%02x,' % ord(bin_file[i]))
51 |
52 | h_file.write('\n};\n')
53 | h_file.close()
54 |
--------------------------------------------------------------------------------
/driver/boot/bootcode.asm:
--------------------------------------------------------------------------------
1 | ; WinKexec: kexec for Windows
2 | ; Copyright (C) 2008-2009 John Stumpo
3 | ;
4 | ; This program is free software: you can redistribute it and/or modify
5 | ; it under the terms of the GNU General Public License as published by
6 | ; the Free Software Foundation, either version 3 of the License, or
7 | ; (at your option) any later version.
8 | ;
9 | ; This program is distributed in the hope that it will be useful,
10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | ; GNU General Public License for more details.
13 | ;
14 | ; You should have received a copy of the GNU General Public License
15 | ; along with this program. If not, see .
16 |
17 | ; This gets compiled into the data segment of kexec.sys as a flat binary.
18 | ; kexec.sys will load this to physical address 0x00008000, identity-map
19 | ; that piece of RAM, and finally jump to it so we can turn off paging,
20 | ; drop back to real mode, build a minimal protected mode environment,
21 | ; use that to reassemble the kernel and initrd, and finally boot the kernel.
22 |
23 | ; Where is stuff at the moment?
24 | ; 0x00008000 = this code
25 | ; in the struct at the end = pointer to page directory showing us
26 | ; where the kernel and initrd are
27 | ; somewhere further up = Windows
28 | ; somewhere else up there = the kernel and initrd we're going to load
29 |
30 | org 0x00008000
31 |
32 | _start:
33 | bits 32
34 |
35 | ; Initialize the real mode stack; it will begin at 0x0000:0x4ffe.
36 | ; This leaves a gap of three pages (12 KB) below this code so we can
37 | ; put the identity-mapping page directory and page table there and
38 | ; have a scratch page available.
39 | mov word [real_stack_segment], 0x0000
40 | mov word [real_stack_pointer], 0x4ffe
41 |
42 | ; Leave protected mode. When we return, the stack we set up above
43 | ; will be in effect.
44 | call protToReal
45 | bits 16
46 |
47 | ; Reset the control registers that might affect what we are doing
48 | ; to a known state. (Now we don't have to worry about potential
49 | ; nasties like Windows' page mappings still being cached due to
50 | ; cr4.pge, which Windows likes to set.)
51 | mov eax, 0x60000010
52 | mov cr0, eax
53 | xor eax, eax
54 | mov cr4, eax
55 |
56 | ; Initialize the protected mode stack; it will begin at 0x000047fc.
57 | ; This leaves 2 KB for the real mode stack, just in case the BIOS is
58 | ; overly greedy with regard to stack space. This stack will go into
59 | ; effect when realToProt is called.
60 | mov word [prot_stack_segment], 0x0010
61 | mov dword [prot_stack_pointer], 0x000047fc
62 |
63 | ; Populate the page directory pointer table embedded within us.
64 | ; (Really, that just means copying kx_page_directory to its second
65 | ; entry, effectively mapping the kernel and initrd to 0x40000000.)
66 | ; The first page directory will go at 0x00006000 and is already filled
67 | ; in for us; the second is the one we are passed from the final bit of
68 | ; Windows kernel API-using code; the rest are not present.
69 | mov eax, dword [kx_page_directory]
70 | mov dword [pdpt_entry1], eax
71 | mov eax, dword [kx_page_directory+4]
72 | mov dword [pdpt_entry1+4], eax
73 |
74 | ; Build the first page directory at 0x00006000.
75 | ; We only need one page table: it will identity-map the entire first
76 | ; megabyte of physical RAM (where we are), and let us map the areas
77 | ; of higher RAM that we need into the second megabyte in order to
78 | ; move stuff around. We also add the page directory that maps the kernel
79 | ; as a page table, giving us simple access to the kernel map page tables.
80 | cld
81 | mov ecx, 1024
82 | mov edi, 0x00006000
83 | rep stosd
84 | mov dword [0x00006000], 0x00007023
85 | mov eax, dword [pdpt_entry1]
86 | or al, 0x23
87 | mov dword [0x00006ff8], eax
88 | mov eax, dword [pdpt_entry1+4]
89 | mov dword [0x00006ffc], eax
90 |
91 | ; Build the page table for the first two megabytes of address space
92 | ; at 0x00007000. The first megabyte is entirely an identity mapping,
93 | ; with the exception of the bottom-most page (so we can detect if the
94 | ; C code tries to follow a null pointer); the second megabyte is left
95 | ; unmapped. We zero the page out first because it is likely to contain
96 | ; garbage from system boot, as boot sectors often like to put their
97 | ; stack in this area. We also map the kernel map page directory (by
98 | ; copying the page directory entry) so we can access it.
99 | xor eax, eax
100 | mov ecx, 1024
101 | mov edi, 0x00007000
102 | rep stosd
103 | mov eax, 0x00001023
104 | mov edi, 0x00007008
105 | .writeAnotherEntry:
106 | stosd
107 | add edi, 4
108 | add eax, 0x00001000
109 | cmp eax, 0x00100000
110 | jb .writeAnotherEntry
111 | mov eax, dword [0x00006ff8]
112 | mov dword [0x00007ff8], eax
113 | mov eax, dword [0x00006ffc]
114 | mov dword [0x00007ffc], eax
115 |
116 | ; So it's come to this. We're in real mode now, and our task now is to
117 | ; reassemble and boot the kernel. Hopefully the BIOS services (at least
118 | ; int 0x10 and especially 0x15) will work.
119 |
120 | ; We really should leave interrupts disabled just in case Windows did
121 | ; something really strange. We don't really need interrupts to be
122 | ; delivered anyway as all we're doing is shuffling tiny pieces of the
123 | ; kernel and initrd around in RAM before we boot the kernel.
124 |
125 | ; Virtual memory map for when we're in protected mode:
126 | ; 0x00001000 - 0x00100000 = identity mapping
127 | ; 0x001ff000 = kernel map page directory
128 | ; 0x3fe00000 = kernel map page tables
129 | ; (only as much is mapped as actually is used)
130 | ; 0x40000000 = kernel, etc.
131 | ; (kernel, initrd, and kernel command line, each separated by
132 | ; an unmapped page)
133 |
134 | ; Drop to text mode with a clean screen.
135 | mov ax, 0x0003
136 | xor bx, bx
137 | int 0x10
138 |
139 | ; Say hello.
140 | mov si, banner
141 | call display
142 |
143 | ; Make sure PAE is supported.
144 | mov eax, 0x00000001
145 | cpuid
146 | test edx, 0x00000040
147 | jnz .havePAE
148 | mov si, noPAEmsg
149 | jmp short kaboom
150 | .havePAE:
151 |
152 | ; Build the int 0x15 eax=0xe820 memory map.
153 | call build_e820
154 |
155 | ; Go into protected mode.
156 | call realToProt
157 | bits 32
158 |
159 | ; Call the C code to put the kernel and initrd back together.
160 | ; Pass it a pointer to the boot information structure,
161 | ; a pointer to the character output routine, a pointer to
162 | ; a routine that disables paging and stores the fact that we
163 | ; no longer need it, and a pointer to the int 0x15 eax=0xe820
164 | ; physical memory map (prefixed with its entry count).
165 | push dword e820map_count
166 | push dword doneWithPaging
167 | push dword bios_putchar
168 | push dword bootinfo
169 | call c_code
170 | add esp, 16
171 |
172 | ; Go back into real mode.
173 | call protToReal
174 | bits 16
175 |
176 | ; Invoke the kernel!
177 | mov ax, 0x8000
178 | mov ds, ax
179 | mov es, ax
180 | mov fs, ax
181 | mov gs, ax
182 | mov ss, ax
183 | mov sp, 0xdffe
184 | jmp 0x8020:0x0000
185 |
186 |
187 | ; Show an error message and halt.
188 | ; Message is at ds:si.
189 | kaboom:
190 | call display
191 | cli
192 | .hltloop:
193 | hlt
194 | jmp short .hltloop
195 |
196 |
197 | ; Display a message on the screen.
198 | ; Message is at ds:si.
199 | ; Trashes all registers.
200 | display:
201 | cld
202 | .readMore:
203 | lodsb
204 | test al, al
205 | jz .done
206 | mov ah, 0x0e
207 | mov bx, 0x0007
208 | int 0x10
209 | jmp short .readMore
210 | .done:
211 | ret
212 |
213 |
214 | ; Build the int 0x15 eax=0xe820 memory map.
215 | ; Trashes all registers.
216 | build_e820:
217 | xor ebx, ebx
218 | mov di, e820map
219 |
220 | .fetchAnother:
221 | mov eax, 0x0000e820
222 | mov ecx, 20
223 | mov edx, 0x534d4150
224 | int 0x15
225 | jc .e820fail
226 | cmp eax, 0x534d4150
227 | jnz .e820fail
228 | cmp ecx, 20
229 | jnz .e820fail
230 | add di, 20
231 | cmp di, bootinfo
232 | jnb .e820toobig
233 | inc dword [e820map_count]
234 | test ebx, ebx
235 | jz .done
236 | jmp short .fetchAnother
237 |
238 | .e820fail:
239 | ; Apparently some buggy BIOSes return error instead of clearing
240 | ; ebx when we reach the end of the list.
241 | cmp dword [e820map_count], 0
242 | jnz .done
243 | mov si, e820failmsg
244 | jmp kaboom
245 |
246 | .e820toobig:
247 | mov si, e820toobigmsg
248 | jmp kaboom
249 |
250 | .done:
251 | ret
252 |
253 |
254 | ; Switch from real mode to protected mode.
255 | ; Preconditions:
256 | ; - Interrupts are disabled.
257 | ; - The page directory pointer table in our data section is valid and
258 | ; identity-maps this routine and the routine we are returning to.
259 | ; - The stored protected mode stack is valid.
260 | ; - The caller's code and data segments are zero.
261 | ; - The processor supports PAE.
262 | ; Postconditions:
263 | ; - Real mode stack is stored.
264 | ; - Returns in 32-bit protected mode with paging and PAE enabled.
265 | ; - The active page directory pointer table is the one in our data section.
266 | realToProt:
267 | bits 16
268 |
269 | ; Save our return address.
270 | pop dx
271 |
272 | ; Save the real mode stack.
273 | mov ax, ss
274 | mov word [real_stack_segment], ax
275 | mov word [real_stack_pointer], sp
276 |
277 | ; Install the GDT just in case.
278 | lgdt [gdttag]
279 |
280 | ; Protected mode ON!
281 | mov eax, cr0
282 | or al, 0x01
283 | mov cr0, eax
284 |
285 | ; Fix up CS for 32-bit protected mode.
286 | jmp 0x0008:.inProtectedMode
287 | .inProtectedMode:
288 | bits 32
289 |
290 | ; Fix up the segments we're going to need in 32-bit protected mode.
291 | ; Also switch to the protected mode stack.
292 | mov ax, 0x0010
293 | mov ds, ax
294 | mov es, ax
295 | mov fs, ax
296 | mov gs, ax
297 | mov ss, word [prot_stack_segment]
298 | mov esp, dword [prot_stack_pointer]
299 |
300 | ; Apply the protected mode interrupt descriptor table.
301 | lidt [idttag]
302 |
303 | ; Bypass the activation of paging if it's no longer necessary.
304 | mov al, byte [dont_need_paging_anymore]
305 | test al, al
306 | jnz .skipPaging
307 |
308 | ; Turn on PAE.
309 | mov eax, cr4
310 | or al, 0x20
311 | mov cr4, eax
312 |
313 | ; Turn on paging.
314 | mov eax, page_directory_pointer_table
315 | mov cr3, eax
316 | mov eax, cr0
317 | or eax, 0x80000000
318 | mov cr0, eax
319 | .skipPaging:
320 |
321 | ; Return to the saved return address.
322 | movzx eax, dx
323 | push eax
324 | ret
325 |
326 |
327 | ; Switch from protected mode to real mode.
328 | ; Preconditions:
329 | ; - If paging is on, this routine is in identity-mapped memory.
330 | ; - The return address is strictly less than 0x00010000 (64 KB).
331 | ; - Interrupts are disabled.
332 | ; - The stored real mode stack is valid.
333 | ; Postconditions:
334 | ; - Protected mode stack is stored.
335 | ; - Returns in 16-bit real mode.
336 | protToReal:
337 | bits 32
338 |
339 | ; Save our return address.
340 | pop edx
341 |
342 | ; Save the protected mode stack.
343 | mov ax, ss
344 | mov word [prot_stack_segment], ax
345 | mov dword [prot_stack_pointer], esp
346 |
347 | ; Paging, be gone!
348 | mov eax, cr0
349 | and eax, 0x7fffffff
350 | mov cr0, eax
351 | xor eax, eax
352 | mov cr3, eax ; Paging, be very gone. (Nuke the TLB.)
353 |
354 | ; Turn off PAE, if it's on.
355 | mov eax, cr4
356 | and al, 0xdf
357 | mov cr4, eax
358 |
359 | ; Install the new GDT, just in case this is the first time we're switching.
360 | lgdt [gdttag]
361 |
362 | ; Enter 16-bit protected mode through the new GDT.
363 | jmp 0x0018:.in16bitpmode
364 | .in16bitpmode:
365 | bits 16
366 |
367 | ; Load real-mode-appropriate segments so the descriptor
368 | ; cache registers don't get royally messed up.
369 | mov ax, 0x0020
370 | mov ds, ax
371 | mov es, ax
372 | mov fs, ax
373 | mov gs, ax
374 | mov ss, ax
375 |
376 | ; Apply the real mode interrupt vector table.
377 | lidt [real_idttag]
378 |
379 | ; Drop back to real mode.
380 | mov eax, cr0
381 | and al, 0xfe
382 | mov cr0, eax
383 |
384 | ; Make an absolute jump below to put us in full-blown 16-bit real mode.
385 | jmp 0x0000:.in16bitrmode
386 | .in16bitrmode:
387 |
388 | ; Finally load the segment registers with genuine real-mode values.
389 | ; Also switch to the real mode stack.
390 | xor ax, ax
391 | mov ds, ax
392 | mov es, ax
393 | mov fs, ax
394 | mov gs, ax
395 | mov ax, word [real_stack_segment]
396 | mov ss, ax
397 | mov sp, word [real_stack_pointer]
398 |
399 | ; Return to the saved return address.
400 | push dx
401 | ret
402 |
403 |
404 | ; Stub handlers for protected mode exceptions.
405 | ; Macro arguments: [int number], [0 or 1 for whether an error code is pushed]
406 | bits 32
407 | %macro define_isr 2
408 | int%1_isr:
409 | %if %2 == 0
410 | push dword 0 ; as a dummy since the processor doesn't push an error code
411 | %endif
412 | push dword %1
413 | jmp isr_common
414 | %endmacro
415 | define_isr 0x00, 0 ; division by zero
416 | define_isr 0x01, 0 ; debug exception
417 | define_isr 0x02, 0 ; non-maskable interrupt
418 | define_isr 0x03, 0 ; breakpoint
419 | define_isr 0x04, 0 ; overflow
420 | define_isr 0x05, 0 ; bound range exceeded
421 | define_isr 0x06, 0 ; invalid opcode
422 | define_isr 0x08, 1 ; double fault
423 | define_isr 0x0a, 1 ; invalid task state segment
424 | define_isr 0x0b, 1 ; segment not present
425 | define_isr 0x0c, 1 ; stack segment fault
426 | define_isr 0x0d, 1 ; general protection fault
427 | define_isr 0x0e, 1 ; page fault
428 | define_isr 0x10, 0 ; floating point exception
429 |
430 | ; The common interrupt service routine.
431 | ; Stack state: [bottom; top of previous stack]
432 | ; previous EFL
433 | ; previous CS
434 | ; previous EIP
435 | ; error code (or placeholder zero)
436 | ; exception number
437 | ; [top]
438 | isr_common:
439 | ; Stash all other registers.
440 | pushad
441 | push ds
442 | push es
443 | push fs
444 | push gs
445 | ; stack (top to bottom):
446 | ; gs fs es ds edi esi ebp esp-0x14 ebx ecx edx eax excno errcode eip cs efl
447 | ; offsets from esp (hex):
448 | ; 00 04 08 0c 10 14 18 1c 20 24 28 2c 30 34 38 3c 40
449 |
450 | ; Display the proper error message.
451 | mov eax, dword [esp+0x30]
452 | mov esi, dword [error_code_table + 4*eax]
453 | call bios_putstr
454 | mov esi, errcode_separator
455 | call bios_putstr
456 | mov eax, dword [esp+0x34]
457 | call bios_puthex
458 |
459 | ; Dump the registers.
460 | %macro dump_reg 2
461 | mov esi, %1_is
462 | call bios_putstr
463 | mov eax, dword [esp+%2]
464 | call bios_puthex
465 | %endmacro
466 | %macro dump_real_reg 1
467 | mov esi, %1_is
468 | call bios_putstr
469 | mov eax, %1
470 | call bios_puthex
471 | %endmacro
472 | dump_reg eax, 0x2c
473 | dump_reg ebx, 0x20
474 | dump_reg ecx, 0x24
475 | dump_reg edx, 0x28
476 | dump_reg esi, 0x14
477 | dump_reg edi, 0x10
478 | dump_reg ebp, 0x18
479 | mov esi, esp_is
480 | call bios_putstr
481 | mov eax, dword [esp+0x1c]
482 | add eax, 0x14
483 | call bios_puthex
484 | dump_reg eip, 0x38
485 | dump_reg efl, 0x40
486 | dump_reg cs, 0x3c
487 | dump_real_reg ss
488 | dump_reg ds, 0x0c
489 | dump_reg es, 0x08
490 | dump_reg fs, 0x04
491 | dump_reg gs, 0x00
492 | dump_real_reg cr0
493 | dump_real_reg cr2
494 | dump_real_reg cr3
495 | dump_real_reg cr4
496 |
497 | ; Halt the system.
498 | mov esi, system_halted
499 | call bios_putstr
500 | cli
501 | .hltloop:
502 | hlt
503 | jmp short .hltloop
504 |
505 | ; Were we to return, though, we'd restore register state...
506 | pop gs
507 | pop fs
508 | pop es
509 | pop ds
510 | popad
511 | ; ...discard the error code and exception number, and then return.
512 | add esp, 8
513 | iret
514 |
515 |
516 | ; Used only by exception handlers.
517 | ; Takes address of string in esi, which must be in real mode segment zero.
518 | bios_putstr:
519 | bits 32
520 | call protToReal
521 | bits 16
522 | call display
523 | call realToProt
524 | bits 32
525 | ret
526 |
527 | ; Used only by exception handlers.
528 | ; Writes eax out in hex.
529 | bios_puthex:
530 | bits 32
531 | push ebp
532 | mov ebp, esp
533 | sub esp, 4
534 |
535 | mov ebx, eax
536 | mov edi, 8
537 |
538 | mov dword [esp], '0'
539 | call bios_putchar
540 | mov dword [esp], 'x'
541 | call bios_putchar
542 |
543 | .printloop:
544 | rol ebx, 4
545 | mov al, bl
546 | and al, 0x0f
547 | cmp al, 0x0a
548 | jl .usedigit
549 | add al, 'a' - 0x0a ; convert to a-f
550 | jmp short .converted
551 | .usedigit:
552 | add al, '0'
553 | .converted:
554 | movzx eax, al
555 | mov dword [esp], eax
556 | call bios_putchar
557 | sub edi, 1
558 | jnz .printloop
559 |
560 | leave
561 | ret
562 |
563 |
564 | ; Runs int 0x10 AH=0x0e with the passed value as AL.
565 | ; C prototype: void bios_putchar(unsigned char);
566 | align 16
567 | bios_putchar:
568 | bits 32
569 |
570 | push ebp
571 | mov ebp, esp
572 | push edi
573 | push esi
574 | push ebx
575 |
576 | ; Grab the character from the argument list.
577 | mov ecx, dword [ebp + 8]
578 |
579 | ; Do it.
580 | call protToReal
581 | bits 16
582 | mov ah, 0x0e
583 | mov al, cl
584 | mov bx, 0x0007
585 | int 0x10
586 | call realToProt
587 | bits 32
588 |
589 | pop ebx
590 | pop esi
591 | pop edi
592 | pop ebp
593 | ret
594 |
595 |
596 | ; Disable paging and store the fact that we don't need it anymore.
597 | ; C prototype: void done_with_paging(void);
598 | ;
599 | ; We have this because at a specific point the C code doesn't need
600 | ; paging to be activated anymore. Paging is only used to bring the
601 | ; kernel pages together into physically contiguous memory. We can
602 | ; do all the rest with just plain old unpaged physical memory access;
603 | ; in fact, we need it that way once we've reassembled the kernel so
604 | ; we can move stuff around freely in physical memory to prepare for
605 | ; boot. If we don't store the fact that we've reached that point,
606 | ; though, paging will be activated again as soon as we return from
607 | ; something that drops to real mode, and the C code will almost
608 | ; surely attempt to access some unmapped piece of memory, and the
609 | ; resulting page fault will kill us.
610 | align 16
611 | doneWithPaging:
612 | bits 32
613 |
614 | push ebp
615 | mov ebp, esp
616 |
617 | ; Turn off paging...
618 | mov eax, cr0
619 | and eax, 0x7fffffff
620 | mov cr0, eax
621 |
622 | ; ...reset the TLBs...
623 | xor eax, eax
624 | mov cr3, eax
625 |
626 | ; ...and turn off PAE.
627 | mov eax, cr4
628 | and al, 0xdf
629 | mov cr4, eax
630 |
631 | ; Store the fact that we did it, and return.
632 | mov byte [dont_need_paging_anymore], 1
633 |
634 | leave
635 | ret
636 |
637 |
638 | ; Variables
639 | align 4
640 | real_stack_pointer dw 0
641 | real_stack_segment dw 0
642 | prot_stack_pointer dd 0
643 | prot_stack_segment dw 0
644 | dont_need_paging_anymore db 0
645 |
646 | ; Strings
647 | banner db 'WinKexec: Linux bootloader implemented as a Windows device driver',\
648 | 0x0d,0x0a,'Copyright (C) 2008-2009 John Stumpo',0x0d,0x0a,0x0d,0x0a,0x00
649 | noPAEmsg db 'This processor does not support PAE.',0x0d,0x0a,\
650 | 'PAE support is required in order to use WinKexec.',0x0d,0x0a,0x00
651 | e820failmsg db 'The BIOS does not support int 0x15 eax=0xe820.',0x0d,0x0a,\
652 | 'WinKexec requires this function to work.',0x0d,0x0a,0x00
653 | e820toobigmsg db 'The memory table returned by int 0x15 eax=0xe820',0x0d,0x0a,\
654 | 'overflowed the buffer allocated to contain it.',0x0d,0x0a,0x00
655 | stumpmsg db 'This program is a stump. You can help by expanding it.',\
656 | 0x0d,0x0a,0x00 ; in honor of Kyle
657 | errcode_separator db ', errcode=',0x00
658 | eax_is db 0x0d,0x0a,'eax=',0x00
659 | ebx_is db ' ebx=',0x00
660 | ecx_is db ' ecx=',0x00
661 | edx_is db ' edx=',0x00
662 | esi_is db 0x0d,0x0a,'esi=',0x00
663 | edi_is db ' edi=',0x00
664 | ebp_is db ' ebp=',0x00
665 | esp_is db ' esp=',0x00
666 | eip_is db 0x0d,0x0a,'eip=',0x00
667 | efl_is db ' efl=',0x00
668 | cs_is db ' cs=',0x00
669 | ss_is db ' ss=',0x00
670 | ds_is db 0x0d,0x0a,' ds=',0x00
671 | es_is db ' es=',0x00
672 | fs_is db ' fs=',0x00
673 | gs_is db ' gs=',0x00
674 | cr0_is db 0x0d,0x0a,'cr0=',0x00
675 | cr2_is db ' cr2=',0x00
676 | cr3_is db ' cr3=',0x00
677 | cr4_is db ' cr4=',0x00
678 | system_halted db 0x0d,0x0a,0x0d,0x0a,'System halted.',0x0d,0x0a,0x00
679 | exc0x00_msg db 'Division by zero',0x00
680 | exc0x01_msg db 'Debug exception',0x00
681 | exc0x02_msg db 'Non-maskable interrupt',0x00
682 | exc0x03_msg db 'Breakpoint',0x00
683 | exc0x04_msg db 'Overflow',0x00
684 | exc0x05_msg db 'Bound range exceeded',0x00
685 | exc0x06_msg db 'Invalid opcode',0x00
686 | exc0x08_msg db 'Double fault',0x00
687 | exc0x0a_msg db 'Invalid task state segment',0x00
688 | exc0x0b_msg db 'Segment not present',0x00
689 | exc0x0c_msg db 'Stack segment fault',0x00
690 | exc0x0d_msg db 'General protection fault',0x00
691 | exc0x0e_msg db 'Page fault',0x00
692 | exc0x10_msg db 'Floating point exception',0x00
693 |
694 | ; The table mapping exception numbers to error messages.
695 | align 4
696 | error_code_table:
697 | dd exc0x00_msg
698 | dd exc0x01_msg
699 | dd exc0x02_msg
700 | dd exc0x03_msg
701 | dd exc0x04_msg
702 | dd exc0x05_msg
703 | dd exc0x06_msg
704 | dd 0
705 | dd exc0x08_msg
706 | dd 0
707 | dd exc0x0a_msg
708 | dd exc0x0b_msg
709 | dd exc0x0c_msg
710 | dd exc0x0d_msg
711 | dd exc0x0e_msg
712 | dd 0
713 | dd exc0x10_msg
714 |
715 | ; The global descriptor table used for the deactivation of paging,
716 | ; the initial switch back to real mode, the kernel reshuffling,
717 | ; and the switch back to real mode afterwards.
718 | align 8
719 | gdtstart:
720 | nullseg dq 0x0000000000000000
721 | codeseg dq 0x00cf9b000000ffff
722 | dataseg dq 0x00cf93000000ffff
723 | real_codeseg dq 0x00009b000000ffff
724 | real_dataseg dq 0x000093000000ffff
725 | gdtend:
726 |
727 | ; The interrupt descriptor table used for protected mode exception handling.
728 | ; Since we know that the handler addresses fit entirely in the lower
729 | ; 16 bits, we can cheat when forming the entries and not split the words.
730 | %define IDT_BASE_DESCRIPTOR 0x00008e0000080000
731 | align 8
732 | idtstart:
733 | dq IDT_BASE_DESCRIPTOR + int0x00_isr
734 | dq IDT_BASE_DESCRIPTOR + int0x01_isr
735 | dq IDT_BASE_DESCRIPTOR + int0x02_isr
736 | dq IDT_BASE_DESCRIPTOR + int0x03_isr
737 | dq IDT_BASE_DESCRIPTOR + int0x04_isr
738 | dq IDT_BASE_DESCRIPTOR + int0x05_isr
739 | dq IDT_BASE_DESCRIPTOR + int0x06_isr
740 | dq 0
741 | dq IDT_BASE_DESCRIPTOR + int0x08_isr
742 | dq 0
743 | dq IDT_BASE_DESCRIPTOR + int0x0a_isr
744 | dq IDT_BASE_DESCRIPTOR + int0x0b_isr
745 | dq IDT_BASE_DESCRIPTOR + int0x0c_isr
746 | dq IDT_BASE_DESCRIPTOR + int0x0d_isr
747 | dq IDT_BASE_DESCRIPTOR + int0x0e_isr
748 | dq 0
749 | dq IDT_BASE_DESCRIPTOR + int0x10_isr
750 | idtend:
751 |
752 | ; The pointer to the global descriptor table, used when loading it.
753 | gdttag:
754 | gdtsize dw (gdtend - gdtstart - 1)
755 | gdtptr dd gdtstart
756 |
757 | ; The pointer to the interrupt descriptor table, used when loading it.
758 | idttag:
759 | idtsize dw (idtend - idtstart - 1)
760 | idtptr dd idtstart
761 |
762 | ; The pointer to the real mode interrupt vector table,
763 | ; used when loading it.
764 | real_idttag:
765 | real_idtsize dw 0x03ff
766 | real_idtptr dd 0x00000000
767 |
768 | ; The page directory pointer table used when re-entering protected mode.
769 | align 32
770 | page_directory_pointer_table:
771 | pdpt_entry0 dq 0x0000000000006001
772 | pdpt_entry1 dq 0x0000000000000000
773 | pdpt_entry2 dq 0x0000000000000000
774 | pdpt_entry3 dq 0x0000000000000000
775 |
776 | ; Space for building the int 0x15 eax=0xe820 memory map.
777 | ; Make sure we leave enough space for 32 entries, but the code will
778 | ; be willing to go farther (though it will not overwrite bootinfo),
779 | ; so this has to be the last thing before we pad up to bootinfo.
780 | e820map_count dd 0
781 | e820map times (20 * 32) db 0x00
782 |
783 | times (4016 - ($ - $$)) db 0x00 ; pad to 4KB minus 80 bytes
784 |
785 | ; An 80-byte structure giving the information that we need...
786 | ; (Corresponds to struct bootinfo in bootinfo.h)
787 | bootinfo:
788 | kernel_size dd 0 ; length of kernel (0x8fb0)
789 | kernel_hash times 20 db 0 ; SHA1 of kernel (0x8fb4)
790 | initrd_size dd 0 ; length of initrd (0x8fc8)
791 | initrd_hash times 20 db 0 ; SHA1 of initrd (0x8fcc)
792 | cmdline_size dd 0 ; length of cmdline (0x8fe0)
793 | cmdline_hash times 20 db 0 ; SHA1 of cmdline (0x8fe4)
794 | kx_page_directory times 8 db 0 ; PDPT entry for kernel PD (0x8ff8)
795 |
796 | ; Incorporate the C code.
797 | c_code incbin 'boot/reassemble.bin'
798 |
--------------------------------------------------------------------------------
/driver/boot/bootinfo.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | /* The declaration for the information structure passed to the boot code. */
19 |
20 | #ifndef BOOTINFO_H
21 | #define BOOTINFO_H
22 |
23 | #include
24 | #include
25 |
26 | struct bootinfo {
27 | uint32_t kernel_size;
28 | unsigned char kernel_hash[20];
29 | uint32_t initrd_size;
30 | unsigned char initrd_hash[20];
31 | uint32_t cmdline_size;
32 | unsigned char cmdline_hash[20];
33 | uint64_t page_directory_ptr;
34 | } KEXEC_PACKED;
35 |
36 | struct e820 {
37 | uint64_t base;
38 | uint64_t size;
39 | uint32_t type;
40 | } KEXEC_PACKED;
41 |
42 | struct e820_table {
43 | uint32_t count;
44 | struct e820 entries[];
45 | } KEXEC_PACKED;
46 |
47 | #endif
48 |
--------------------------------------------------------------------------------
/driver/boot/console.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include "console.h"
19 |
20 | extern const char* hexdigits;
21 | static bios_putchar_t __bios_putchar;
22 |
23 |
24 | /* Initialize the console functions by storing a
25 | function pointer wrapping around int 0x10 ah=0x0e. */
26 | void console_init(bios_putchar_t putch)
27 | {
28 | __bios_putchar = putch;
29 | }
30 |
31 |
32 | /* Output a single character.
33 | Handle newline appropriately. */
34 | int putchar(int c)
35 | {
36 | if (c == '\n')
37 | __bios_putchar('\r');
38 | __bios_putchar((unsigned char)c);
39 | return c;
40 | }
41 |
42 |
43 | /* Output a null-terminated string. */
44 | void putstr(const char* str)
45 | {
46 | const char* i;
47 | for (i = str; *i; i++)
48 | putchar(*i);
49 | }
50 |
51 |
52 | /* Output a 32-bit word in hexadecimal. */
53 | void puthex(uint32_t w)
54 | {
55 | int i;
56 |
57 | putstr("0x");
58 | for (i = 28; i >= 0; i -= 4)
59 | putchar(hexdigits[(w >> i) & 0x0000000f]);
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/driver/boot/console.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef CONSOLE_H
19 | #define CONSOLE_H
20 |
21 | #include
22 |
23 | typedef void(*bios_putchar_t)(unsigned char);
24 |
25 | void console_init(bios_putchar_t putch);
26 |
27 | int putchar(int c);
28 | void putstr(const char* str);
29 | void puthex(uint32_t w);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/driver/boot/pagesort.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include "pagesort.h"
19 | #include "verify.h"
20 | #include "console.h"
21 | #include "string.h"
22 | #include "stdlib.h"
23 | #include "../util.h"
24 |
25 | static void* kernel_vbase;
26 | static void* initrd_vbase;
27 | static void* cmdline_vbase;
28 | static struct bootinfo* boot_info;
29 | static uint64_t* kmap_pagedir;
30 | static uint64_t* kmap_pagedir_end;
31 | static uint64_t* kmap_pagetables;
32 | static uint64_t* kmap_pagetables_end;
33 | static void* scratch_page;
34 | static struct e820_table* e820;
35 |
36 | static doneWithPaging_t doneWithPaging;
37 |
38 | #ifdef DEBUG
39 | #define DEBUG_OUTPUT(a) putstr(#a " = "); puthex((uint32_t)a); putchar('\n');
40 | #else
41 | #define DEBUG_OUTPUT(a) /*nothing*/
42 | #endif
43 |
44 | /* For qsort(). */
45 | static int e820_compare(const void* lhs, const void* rhs)
46 | {
47 | const struct e820* l = (const struct e820*)lhs;
48 | const struct e820* r = (const struct e820*)rhs;
49 | if (l->base < r->base)
50 | return -1;
51 | else if (l->base == r->base)
52 | return 0;
53 | else
54 | return 1;
55 | }
56 |
57 |
58 | void pagesort_init(struct bootinfo* info, doneWithPaging_t dwp, struct e820_table* mem_table)
59 | {
60 | kernel_vbase = (void*)0x40000000;
61 | initrd_vbase = (void*)((uint32_t)(kernel_vbase + info->kernel_size + 4095) & 0xfffff000) + 4096;
62 | cmdline_vbase = (void*)((uint32_t)(initrd_vbase + info->initrd_size + 4095) & 0xfffff000) + 4096;
63 | kmap_pagetables = (uint64_t*)0x3fe00000;
64 | kmap_pagetables_end = kmap_pagetables + ((cmdline_vbase - kernel_vbase) / 4096) + 1;
65 | kmap_pagedir = (uint64_t*)0x001ff000;
66 | kmap_pagedir_end = kmap_pagedir + ((kmap_pagetables_end - kmap_pagetables + 4095) / 4096);
67 | scratch_page = (void*)0x00005000;
68 |
69 | DEBUG_OUTPUT(kernel_vbase);
70 | DEBUG_OUTPUT(initrd_vbase);
71 | DEBUG_OUTPUT(cmdline_vbase);
72 | DEBUG_OUTPUT(kmap_pagetables);
73 | DEBUG_OUTPUT(kmap_pagetables_end);
74 | DEBUG_OUTPUT(kmap_pagedir);
75 | DEBUG_OUTPUT(kmap_pagedir_end);
76 | DEBUG_OUTPUT(scratch_page);
77 |
78 | boot_info = info;
79 | doneWithPaging = dwp;
80 |
81 | /* Sort the e820 table. */
82 | e820 = mem_table;
83 | qsort(e820->entries, e820->count, sizeof(struct e820), e820_compare);
84 |
85 | #if 0
86 | size_t i;
87 | putstr("e820 map:\n");
88 | for (i = 0; i < e820->count; i++) {
89 | putstr("base=");
90 | puthex((uint32_t)(e820->entries[i].base >> 32));
91 | putchar('`');
92 | puthex((uint32_t)(e820->entries[i].base & 0xffffffff));
93 | putstr(" size=");
94 | puthex((uint32_t)(e820->entries[i].size >> 32));
95 | putchar('`');
96 | puthex((uint32_t)(e820->entries[i].size & 0xffffffff));
97 | putstr(" type=");
98 | puthex(e820->entries[i].type);
99 | putchar('\n');
100 | }
101 | #endif
102 | }
103 |
104 |
105 | /* Verify the SHA1 hashes as an internal consistency check. */
106 | void pagesort_verify(void)
107 | {
108 | putstr("Verifying kernel integrity...\n");
109 | verify_hash(kernel_vbase, boot_info->kernel_size, boot_info->kernel_hash);
110 | putstr("Verifying initrd integrity...\n");
111 | verify_hash(initrd_vbase, boot_info->initrd_size, boot_info->initrd_hash);
112 | putstr("Verifying kernel command line integrity...\n");
113 | verify_hash(cmdline_vbase, boot_info->cmdline_size, boot_info->cmdline_hash);
114 | }
115 |
116 |
117 | /* Convert a pointer into the page tables to the
118 | corresponding virtual address. */
119 | static void* pagesort_convert_ptr(const uint64_t* p)
120 | {
121 | if (p >= kmap_pagetables)
122 | return kernel_vbase + (4096 * (p - kmap_pagetables));
123 | else if (p >= kmap_pagedir)
124 | return kmap_pagetables + (4096 * (p - kmap_pagedir));
125 | else
126 | return NULL;
127 | }
128 |
129 |
130 | /* Sort the kernel pages and page tables so that all of the pages are in
131 | order starting at 0x00100000, followed by the page tables. This will
132 | make it safe to just copy the kernel pages into their final places in
133 | increasing order without having to worry about grinding our feet over
134 | not-yet-done pages. The order of the page tables doesn't matter.
135 |
136 | Note that our idea of "in order" starts at 0x00100000 and goes up to
137 | the top of physical memory, then wraps around to the beginning of
138 | memory and continues up to strictly less than 0x00100000.
139 |
140 | Since swapping pages is far more expensive an operation than checking
141 | the pointers, we will use selection sort. */
142 | void pagesort_sort(void)
143 | {
144 | uint64_t* pos;
145 | uint64_t* lowest;
146 | uint64_t* x;
147 | void* virt_a;
148 | void* virt_b;
149 |
150 | putstr("Sorting pages...\n");
151 |
152 | for (pos = kmap_pagetables; pos < kmap_pagetables_end; pos++) {
153 | if (!*pos)
154 | continue; /* leave the null separators as-is */
155 |
156 | lowest = pos;
157 | for (x = pos; x < kmap_pagetables_end; x++)
158 | if (*x && !((*x < *lowest) ^ !((*x < 0x00100000) ^ (*lowest < 0x00100000))))
159 | lowest = x;
160 | for (x = kmap_pagedir; x < kmap_pagedir_end; x++)
161 | if (*x && !((*x < *lowest) ^ !((*x < 0x00100000) ^ (*lowest < 0x00100000))))
162 | lowest = x;
163 |
164 | if (pos != lowest) {
165 | /* Page swapping time! */
166 | virt_a = pagesort_convert_ptr(pos);
167 | virt_b = pagesort_convert_ptr(lowest);
168 |
169 | #if 0
170 | putstr("Swapping ");
171 | puthex((uint32_t)virt_a);
172 | putstr(" (phys=");
173 | puthex(*(uint32_t*)pos);
174 | putstr(") with ");
175 | puthex((uint32_t)virt_b);
176 | putstr(" (phys=");
177 | puthex(*(uint32_t*)lowest);
178 | putstr(")\n");
179 | #endif
180 |
181 | /* Copy and remap A to the scratch page while
182 | mapping 0x00100000 to the original location of A. */
183 | memcpy(scratch_page, virt_a, 4096);
184 | *(uint64_t*)0x00007800 = *pos;
185 | *pos = 0x0000000000005023ULL;
186 | util_invlpg((uint32_t)virt_a);
187 | util_invlpg(0x00100000);
188 |
189 | /* Copy and remap B to the original location of A while
190 | mapping 0x00101000 to the original location of B. */
191 | memcpy((void*)0x00100000, virt_b, 4096);
192 | *(uint64_t*)0x00007808 = *lowest;
193 | *lowest = *(uint64_t*)0x00007800;
194 | util_invlpg((uint32_t)virt_b);
195 | util_invlpg(0x00101000);
196 |
197 | /* Copy the scratch page to the original location of B and
198 | remap A to the original location of B. */
199 | memcpy((void*)0x00101000, scratch_page, 4096);
200 | *pos = *(uint64_t*)0x00007808;
201 | util_invlpg((uint32_t)virt_a);
202 |
203 | /* Unmap the temporary pages. */
204 | *(uint64_t*)0x00007800 = *(uint64_t*)0x00007808 = 0;
205 | util_invlpg(0x00100000);
206 | util_invlpg(0x00101000);
207 |
208 | }
209 |
210 | }
211 |
212 | /* Verify that the pages are in the correct order. */
213 | x = 0;
214 | for (pos = kmap_pagetables; pos < kmap_pagetables_end; pos++) {
215 | #if 0
216 | putstr("*(uint32_t*)pos = ");
217 | puthex(*(uint32_t*)pos);
218 | putchar('\n');
219 | #endif
220 | if (!*pos)
221 | continue;
222 | if (x == 0) {
223 | x = pos;
224 | continue;
225 | } else if (*pos >= 0x00100000) {
226 | if (*pos <= *x || *x < 0x00100000) {
227 | putstr("Inconsistency detected after sort.\n");
228 | abort();
229 | }
230 | } else {
231 | if (*pos <= *x && *x < 0x00100000) {
232 | putstr("Inconsistency detected after sort.\n");
233 | abort();
234 | }
235 | }
236 | x = pos;
237 | }
238 |
239 | /* Verify that all page tables are after the last kernel page. */
240 | for (pos = kmap_pagedir; pos < kmap_pagedir_end; pos++) {
241 | #if 0
242 | putstr("*(uint32_t*)pos = ");
243 | puthex(*(uint32_t*)pos);
244 | putchar('\n');
245 | #endif
246 | if (*pos >= 0x00100000) {
247 | if (*pos <= *x || *x < 0x00100000) {
248 | putstr("Inconsistency detected after sort.\n");
249 | abort();
250 | }
251 | } else {
252 | if (*pos <= *x && *x < 0x00100000) {
253 | putstr("Inconsistency detected after sort.\n");
254 | abort();
255 | }
256 | }
257 | /* Don't set x to pos; we don't care about the order,
258 | as long as it's all after the last kernel page. */
259 | }
260 |
261 | }
262 |
263 |
264 | /* Collapse the sorted pages into place in memory at 0x00100000 and
265 | invoke the done-paging callback. Then fix up our pointers to the
266 | physical addresses. */
267 | void pagesort_collapse(void)
268 | {
269 | uint32_t pdpt_addr;
270 | uint64_t* pos;
271 | uint32_t dest;
272 |
273 | /* First, move the kernel page directory to the scratch page
274 | so we don't accidentally hit it. */
275 | memcpy(scratch_page, kmap_pagedir, 4096);
276 | pdpt_addr = util_get_cr3();
277 | *(uint64_t*)(pdpt_addr + 8) = (uint64_t)((uint32_t)scratch_page | 0x00000001);
278 | /* Force the PDPT to be reloaded by reloading cr3. */
279 | util_reload_cr3();
280 |
281 | kmap_pagedir = scratch_page;
282 |
283 | putstr("Moving pages to contiguous memory...\n");
284 |
285 | dest = 0x00100000;
286 | for (pos = kmap_pagetables; pos < kmap_pagetables_end; pos++) {
287 | if (!*pos) {
288 | dest += 4096;
289 | continue; /* leave the null separators as-is */
290 | }
291 |
292 | #if 0
293 | putstr("Moving ");
294 | puthex(*(uint32_t*)pos);
295 | putstr(" to ");
296 | puthex(dest);
297 | putstr(".\n");
298 | #endif
299 |
300 | /* Map 0x00100000 to the destination. */
301 | *(uint64_t*)0x00007800 = dest | 0x0000000000000023ULL;
302 | util_invlpg(0x00100000);
303 |
304 | /* Copy the page to the destination. */
305 | memcpy((void*)0x00100000, pagesort_convert_ptr(pos), 4096);
306 |
307 | /* Remap the page to the destination. */
308 | *pos = *(uint64_t*)0x00007800;
309 | util_invlpg((uint32_t)pagesort_convert_ptr(pos));
310 |
311 | /* Unmap 0x00100000. */
312 | *(uint64_t*)0x00007800 = 0;
313 | util_invlpg(0x00100000);
314 |
315 | dest += 4096;
316 | }
317 |
318 | doneWithPaging();
319 |
320 | kernel_vbase -= (0x40000000 - 0x00100000);
321 | initrd_vbase -= (0x40000000 - 0x00100000);
322 | cmdline_vbase -= (0x40000000 - 0x00100000);
323 | }
324 |
325 |
326 | /* Set up the real mode segment used to boot the kernel. This does
327 | everything needed to get the kernel ready to go, including filling
328 | in the header structures. This makes the copy of the cmdline after
329 | the initrd not matter anymore, allowing us to shift the initrd up
330 | afterward without accounting for the cmdline. The segment is built
331 | at 0x00080000, so the real mode code can jump to 0x8020:0x0000. */
332 | void pagesort_prepare_for_boot(void)
333 | {
334 | int rmcode_size;
335 | uint16_t proto;
336 | uint32_t cmdlimit;
337 | int i;
338 | uint32_t initrd_limit;
339 | uint32_t initrd_loadaddr;
340 |
341 | rmcode_size = 512 * (1 + *(uint8_t*)(kernel_vbase + 0x01f1));
342 | if (rmcode_size == 0)
343 | rmcode_size = 512 * 5;
344 | memcpy((void*)0x00080000, kernel_vbase, rmcode_size);
345 | memmove((void*)0x00100000, kernel_vbase + rmcode_size, boot_info->kernel_size - rmcode_size);
346 |
347 | /* Now we can forget about the 32-or-64-bit meat of the kernel and just
348 | reference header fields relative to 0x00080000, where we put
349 | the 16-bit setup code. Let's fill in some fields while we're here. */
350 | if (*(uint16_t*)0x000801fe != 0xaa55 || *(uint32_t*)0x00080202 != 0x53726448) {
351 | putstr("Invalid magic numbers in kernel.\n");
352 | abort();
353 | }
354 |
355 | proto = *(uint16_t*)0x00080206;
356 | if (proto < 0x0202) {
357 | putstr("Kernel boot protocol is too old (must be at least 2.02).\n");
358 | putstr("Any released 2.4 or 2.6 kernel should do the trick.\n");
359 | abort();
360 | }
361 |
362 | /* If we get an ID from hpa, here is its place to shine. */
363 | *(uint8_t*)0x00080210 = 0xff; /* type_of_loader */
364 |
365 | /* Set CAN_USE_HEAP and the heap_end_ptr. */
366 | *(uint8_t*)0x00080211 |= 0x80;
367 | *(uint16_t*)0x00080224 = 0xde00;
368 |
369 | /* Check the command line length. */
370 | if (proto >= 0x0206)
371 | cmdlimit = *(uint32_t*)0x00080238;
372 | else
373 | cmdlimit = 255;
374 | if (boot_info->cmdline_size > cmdlimit) {
375 | putstr("Kernel command line is too long for the kernel given.\n");
376 | abort();
377 | }
378 |
379 | /* Set the command line. */
380 | memcpy((void*)0x0008e000, cmdline_vbase, boot_info->cmdline_size);
381 | cmdline_vbase = (void*)0x0008e000;
382 | *(uint32_t*)0x00080228 = 0x0008e000;
383 |
384 | /* Find a big enough block of usable RAM in the e820 table
385 | and put the initrd there. But first make sure there
386 | actually *is* an initrd. */
387 | if (boot_info->initrd_size == 0)
388 | return;
389 |
390 | /* It's the highest safe byte that is reported; a
391 | boundary is easier to work with. */
392 | if (proto >= 0x0203)
393 | initrd_limit = 1 + *(uint32_t*)0x0008022c;
394 | else
395 | initrd_limit = 0x38000000;
396 |
397 | /* Look backwards through the e820 table for a suitable location. */
398 | for (i = e820->count - 1; i >= 0; i--) {
399 | if (e820->entries[i].type != 1 ||
400 | e820->entries[i].base > (initrd_limit - boot_info->initrd_size))
401 | continue;
402 |
403 | if (e820->entries[i].base + e820->entries[i].size > initrd_limit)
404 | initrd_loadaddr = initrd_limit - boot_info->initrd_size;
405 | else
406 | initrd_loadaddr = e820->entries[i].base + e820->entries[i].size - boot_info->initrd_size;
407 | initrd_loadaddr &= 0xfffff000; /* round down to multiple of 4 KB */
408 |
409 | memmove((void*)initrd_loadaddr, initrd_vbase, boot_info->initrd_size);
410 | initrd_vbase = (void*)initrd_loadaddr;
411 | *(uint32_t*)0x00080218 = initrd_loadaddr;
412 | *(uint32_t*)0x0008021c = boot_info->initrd_size;
413 | return;
414 | }
415 | putstr("No suitable memory location found for initrd.\n");
416 | abort();
417 |
418 | }
419 |
--------------------------------------------------------------------------------
/driver/boot/pagesort.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef PAGESORT_H
19 | #define PAGESORT_H
20 |
21 | #include "bootinfo.h"
22 |
23 | typedef void(*doneWithPaging_t)(void);
24 |
25 | void pagesort_init(struct bootinfo* info, doneWithPaging_t dwp, struct e820_table* mem_table);
26 | void pagesort_verify(void);
27 | void pagesort_sort(void);
28 | void pagesort_collapse(void);
29 | void pagesort_prepare_for_boot(void);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/driver/boot/reassemble.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | /* Some code to help reassemble the kernel and initrd in memory.
19 | Execution of this chunk of C code will begin with the only function
20 | in this file, which is _reassemble_start, as we link this first into the
21 | flat binary. */
22 |
23 | #include "bootinfo.h"
24 | #include "console.h"
25 | #include "pagesort.h"
26 |
27 | /* The entry point. Takes a pointer to the boot info structure,
28 | a pointer to the character output function, a pointer to the
29 | done-paging callback, and a pointer to the int 0x15 eax=0xe820
30 | table. */
31 | void _reassemble_start(struct bootinfo* info, bios_putchar_t putch,
32 | doneWithPaging_t dwp, struct e820_table* mem_table)
33 | {
34 | console_init(putch);
35 |
36 | pagesort_init(info, dwp, mem_table);
37 |
38 | /* Sort the kernel pages and the page tables. */
39 | pagesort_sort();
40 |
41 | /* Collapse the pages into place. */
42 | pagesort_collapse();
43 |
44 | /* Verify the hashes to make sure everything is right so far. */
45 | pagesort_verify();
46 |
47 | /* Prepare the initrd and the real mode segment. */
48 | pagesort_prepare_for_boot();
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/driver/boot/reassemble.ld:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | ENTRY(__reassemble_start);
19 |
20 | SECTIONS
21 | {
22 | /* Lump everything together at 0x00009000. */
23 | . = 0x00009000;
24 | .text : {
25 | *(.text);
26 | *(.rdata);
27 | *(.data);
28 | *(.bss);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/driver/boot/stdlib.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include "console.h"
19 | #include "stdlib.h"
20 | #include "string.h"
21 | #include "../util.h"
22 |
23 | void KEXEC_NORETURN abort(void)
24 | {
25 | putstr("abort() was called!\n");
26 | util_int3();
27 | util_hlt();
28 | }
29 |
30 |
31 | /* Not quicksort (in the interest of stack space) but insertion sort.
32 | Sure, it's O(n^2) in time, but we're not going to be sorting huge
33 | lists with it. */
34 | void qsort(void* base, size_t num, size_t size,
35 | int(*compare)(const void*, const void*))
36 | {
37 | size_t pos1;
38 | size_t pos2;
39 | unsigned char buf[32];
40 |
41 | if (size > 32) {
42 | putstr("qsort: Maximum element size exceeded\n");
43 | abort();
44 | }
45 |
46 | for (pos1 = 1; pos1 < num; pos1++) {
47 | for (pos2 = pos1;
48 | compare(base + ((pos2 - 1) * size),
49 | base + ( pos2 * size)) > 0 && pos2 > 0;
50 | pos2--)
51 | {
52 | memcpy(buf, base + ((pos2 - 1) * size), size);
53 | memcpy(base + ((pos2 - 1) * size), base + (pos2 * size), size);
54 | memcpy(base + (pos2 * size), buf, size);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/driver/boot/stdlib.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KX_STDLIB_H
19 | #define KX_STDLIB_H
20 |
21 | #include
22 | #include
23 |
24 | void KEXEC_NORETURN abort(void);
25 |
26 | void qsort(void* base, size_t num, size_t size,
27 | int(*compare)(const void*, const void*));
28 |
29 | #endif
30 |
--------------------------------------------------------------------------------
/driver/boot/string.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include "string.h"
19 |
20 | int memcmp(const void* a, const void* b, size_t len)
21 | {
22 | const unsigned char* c = a;
23 | const unsigned char* d = b;
24 | size_t i;
25 |
26 | for (i = 0; i < len; i++)
27 | if (c[i] != d[i])
28 | return c[i] - d[i];
29 |
30 | return 0;
31 | }
32 |
33 |
34 | void* memmove(void* dest, const void* src, size_t len)
35 | {
36 | const unsigned char* a = src;
37 | unsigned char* b = dest;
38 | size_t i;
39 |
40 | if (b < a) {
41 | for (i = 0; i < len; i++)
42 | b[i] = a[i];
43 | } else {
44 | for (i = len; i > 0; i--)
45 | b[i-1] = a[i-1];
46 | }
47 |
48 | return dest;
49 | }
50 |
--------------------------------------------------------------------------------
/driver/boot/string.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KX_STRING_H
19 | #define KX_STRING_H
20 |
21 | #include
22 |
23 | int memcmp(const void*, const void*, size_t);
24 | void* memmove(void*, const void*, size_t);
25 | #define memcpy memmove
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/driver/boot/verify.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include "verify.h"
19 | #include "string.h"
20 | #include "console.h"
21 | #include "stdlib.h"
22 | #include "../sha1.h"
23 |
24 | const char* hexdigits = "0123456789abcdef";
25 |
26 | void verify_hash(const void* data, size_t len, const unsigned char* hash)
27 | {
28 | unsigned char sha1hash[20];
29 | unsigned char c;
30 | int i;
31 |
32 | sha1(sha1hash, data, len);
33 |
34 | if (memcmp(sha1hash, hash, 20) != 0) {
35 | putstr("Hash is incorrect.\nIt should be: ");
36 | for (i = 0; i < 20; i++) {
37 | c = hash[i];
38 | putchar(hexdigits[c >> 4]);
39 | putchar(hexdigits[c & 0x0f]);
40 | }
41 | putstr("\nIt really is: ");
42 | for (i = 0; i < 20; i++) {
43 | c = sha1hash[i];
44 | putchar(hexdigits[c >> 4]);
45 | putchar(hexdigits[c & 0x0f]);
46 | }
47 | putstr("\nAborting.\n");
48 | abort();
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/driver/boot/verify.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KX_VERIFY_H
19 | #define KX_VERIFY_H
20 |
21 | #include
22 |
23 | void verify_hash(const void* data, size_t len, const unsigned char* hash);
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/driver/buffer.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include "buffer.h"
19 | #include "sha1.h"
20 |
21 | #define LOCK_BUFFER(buf) ExAcquireFastMutex(&((buf)->Mutex))
22 | #define UNLOCK_BUFFER(buf) ExReleaseFastMutex(&((buf)->Mutex))
23 |
24 | /* Buffers for the data we need to keep track of */
25 | KEXEC_BUFFER KexecKernel;
26 | KEXEC_BUFFER KexecInitrd;
27 | KEXEC_BUFFER KexecKernelCommandLine;
28 |
29 | /* Update the SHA1 hash of a buffer's contents. */
30 | static void KexecUpdateBufferHash(PKEXEC_BUFFER KexecBuffer)
31 | {
32 | ASSERT(KeGetCurrentIrql() == APC_LEVEL);
33 | sha1(KexecBuffer->Sha1Hash, KexecBuffer->Data, KexecBuffer->Size);
34 | }
35 |
36 | /* Set a buffer to be empty. */
37 | static void KexecClearBuffer(PKEXEC_BUFFER KexecBuffer)
38 | {
39 | ASSERT(KeGetCurrentIrql() == APC_LEVEL);
40 | KexecBuffer->Size = 0;
41 | KexecBuffer->Data = NULL;
42 | KexecUpdateBufferHash(KexecBuffer);
43 | }
44 |
45 | /* Free the contents (if any) of a buffer, and reinitialize it. */
46 | static void KexecFreeBuffer(PKEXEC_BUFFER KexecBuffer)
47 | {
48 | ASSERT(KeGetCurrentIrql() == APC_LEVEL);
49 | if (KexecBuffer->Data)
50 | ExFreePool(KexecBuffer->Data);
51 | KexecClearBuffer(KexecBuffer);
52 | }
53 |
54 | /* Initialize a buffer. */
55 | void KexecInitBuffer(PKEXEC_BUFFER KexecBuffer)
56 | {
57 | ExInitializeFastMutex(&KexecBuffer->Mutex);
58 | LOCK_BUFFER(KexecBuffer);
59 | KexecClearBuffer(KexecBuffer);
60 | UNLOCK_BUFFER(KexecBuffer);
61 | }
62 |
63 | /* Destroy a buffer. */
64 | void KexecDestroyBuffer(PKEXEC_BUFFER KexecBuffer)
65 | {
66 | LOCK_BUFFER(KexecBuffer);
67 | KexecFreeBuffer(KexecBuffer);
68 | UNLOCK_BUFFER(KexecBuffer);
69 | }
70 |
71 | /* Load data into a buffer. */
72 | NTSTATUS KexecLoadBuffer(PKEXEC_BUFFER KexecBuffer, ULONG size, PVOID data)
73 | {
74 | ULONG alloc_size;
75 | /* Round the size up to the nearest multiple of 4096 to ensure that
76 | the buffer ends up on a page boundary. */
77 | alloc_size = (size + 4095) & 0xffff000;
78 |
79 | LOCK_BUFFER(KexecBuffer);
80 | KexecFreeBuffer(KexecBuffer);
81 | KexecBuffer->Data = ExAllocatePoolWithTag(NonPagedPool,
82 | alloc_size, TAG('K', 'x', 'e', 'c'));
83 | if (!KexecBuffer->Data) {
84 | UNLOCK_BUFFER(KexecBuffer);
85 | return STATUS_INSUFFICIENT_RESOURCES;
86 | }
87 | KexecBuffer->Size = size;
88 | RtlCopyMemory(KexecBuffer->Data, data, size);
89 | KexecUpdateBufferHash(KexecBuffer);
90 | UNLOCK_BUFFER(KexecBuffer);
91 | return STATUS_SUCCESS;
92 | }
93 |
94 | /* Retrieve data from a buffer. */
95 | NTSTATUS KexecGetBuffer(PKEXEC_BUFFER KexecBuffer, ULONG size, PVOID buf, DWORD* osize)
96 | {
97 | LOCK_BUFFER(KexecBuffer);
98 | if (size < KexecBuffer->Size) {
99 | *osize = 0;
100 | UNLOCK_BUFFER(KexecBuffer);
101 | return STATUS_INSUFFICIENT_RESOURCES;
102 | }
103 | RtlCopyMemory(buf, KexecBuffer->Data, KexecBuffer->Size);
104 | *osize = KexecBuffer->Size;
105 | UNLOCK_BUFFER(KexecBuffer);
106 | return STATUS_SUCCESS;
107 | }
108 |
109 | /* Get the size of a buffer. */
110 | ULONG KexecGetBufferSize(PKEXEC_BUFFER KexecBuffer)
111 | {
112 | /* Just one value grab - no lock needed. */
113 | return KexecBuffer->Size;
114 | }
115 |
--------------------------------------------------------------------------------
/driver/buffer.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KEXEC_DRIVER_BUFFER_H
19 | #define KEXEC_DRIVER_BUFFER_H
20 |
21 | #include
22 |
23 | typedef struct {
24 | ULONG Size;
25 | PVOID Data;
26 | FAST_MUTEX Mutex;
27 | unsigned char Sha1Hash[20];
28 | } KEXEC_BUFFER, *PKEXEC_BUFFER;
29 |
30 | extern KEXEC_BUFFER KexecKernel;
31 | extern KEXEC_BUFFER KexecInitrd;
32 | extern KEXEC_BUFFER KexecKernelCommandLine;
33 |
34 | void KexecInitBuffer(PKEXEC_BUFFER KexecBuffer);
35 | void KexecDestroyBuffer(PKEXEC_BUFFER KexecBuffer);
36 | NTSTATUS KexecLoadBuffer(PKEXEC_BUFFER KexecBuffer, ULONG size, PVOID data);
37 | NTSTATUS KexecGetBuffer(PKEXEC_BUFFER KexecBuffer, ULONG size, PVOID buf, DWORD* osize);
38 | ULONG KexecGetBufferSize(PKEXEC_BUFFER KexecBuffer);
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/driver/entry.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include "buffer.h"
22 | #include "io.h"
23 |
24 | /* Called just before kexec.sys is unloaded. */
25 | void DDKAPI DriverUnload(PDRIVER_OBJECT DriverObject)
26 | {
27 | UNICODE_STRING SymlinkName;
28 |
29 | DbgPrint("Unloading kexec driver\n");
30 |
31 | /* Unregister \\.\kexec with the Windows kernel. */
32 | RtlInitUnicodeString(&SymlinkName, L"\\??\\kexec");
33 | IoDeleteSymbolicLink(&SymlinkName);
34 | IoDeleteDevice(DriverObject->DeviceObject);
35 |
36 | /* Don't waste kernel memory! */
37 | KexecDestroyBuffer(&KexecKernel);
38 | KexecDestroyBuffer(&KexecInitrd);
39 | KexecDestroyBuffer(&KexecKernelCommandLine);
40 | }
41 |
42 | /* The entry point - this is called when kexec.sys is loaded, and it
43 | runs to completion before the associated userspace call to
44 | StartService() returns, no matter what. */
45 | NTSTATUS DDKAPI DriverEntry(PDRIVER_OBJECT DriverObject,
46 | PUNICODE_STRING RegistryPath KEXEC_UNUSED)
47 | {
48 | NTSTATUS status;
49 | UNICODE_STRING DeviceName;
50 | UNICODE_STRING SymlinkName;
51 | PDEVICE_OBJECT DeviceObject;
52 |
53 | DbgPrint("Loading kexec driver\n");
54 |
55 | /* Allow kexec.sys to be unloaded. */
56 | DriverObject->DriverUnload = DriverUnload;
57 |
58 | /* Init the buffers. */
59 | KexecInitBuffer(&KexecKernel);
60 | KexecInitBuffer(&KexecInitrd);
61 | KexecInitBuffer(&KexecKernelCommandLine);
62 |
63 | RtlInitUnicodeString(&DeviceName, L"\\Device\\Kexec");
64 | RtlInitUnicodeString(&SymlinkName, L"\\??\\kexec");
65 |
66 | /* Register \\.\kexec with the Windows kernel. */
67 | status = IoCreateDevice(DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN,
68 | 0, FALSE, &DeviceObject);
69 | if (NT_SUCCESS(status)) {
70 | /* Set our handlers for I/O operations on \\.\kexec. */
71 | DriverObject->MajorFunction[IRP_MJ_CREATE] = KexecOpen;
72 | DriverObject->MajorFunction[IRP_MJ_CLOSE] = KexecClose;
73 | DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KexecIoctl;
74 | DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = KexecShutdown;
75 | status = IoCreateSymbolicLink(&SymlinkName, &DeviceName);
76 | if (NT_SUCCESS(status)) {
77 | status = IoRegisterShutdownNotification(DeviceObject);
78 | if (!NT_SUCCESS(status)) {
79 | IoDeleteSymbolicLink(&SymlinkName);
80 | IoDeleteDevice(DeviceObject);
81 | }
82 | } else
83 | IoDeleteDevice(DeviceObject);
84 | }
85 |
86 | return status;
87 | }
88 |
--------------------------------------------------------------------------------
/driver/io.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 |
20 | #include "buffer.h"
21 | #include "io.h"
22 | #include "reboot.h"
23 |
24 | /* Called when \\.\kexec is opened. */
25 | NTSTATUS DDKAPI KexecOpen(PDEVICE_OBJECT DeviceObject KEXEC_UNUSED, PIRP Irp)
26 | {
27 | Irp->IoStatus.Status = STATUS_SUCCESS;
28 | Irp->IoStatus.Information = 0;
29 | IoCompleteRequest(Irp, IO_NO_INCREMENT);
30 | return STATUS_SUCCESS;
31 | }
32 |
33 | /* Called when \\.\kexec is closed. */
34 | NTSTATUS DDKAPI KexecClose(PDEVICE_OBJECT DeviceObject KEXEC_UNUSED, PIRP Irp)
35 | {
36 | Irp->IoStatus.Status = STATUS_SUCCESS;
37 | Irp->IoStatus.Information = 0;
38 | IoCompleteRequest(Irp, IO_NO_INCREMENT);
39 | return STATUS_SUCCESS;
40 | }
41 |
42 | /* Handle an ioctl^H^H^H^H^HDeviceIoControl on /dev/^H^H^H^H^H\\.\kexec */
43 | NTSTATUS DDKAPI KexecIoctl(PDEVICE_OBJECT DeviceObject KEXEC_UNUSED, PIRP Irp)
44 | {
45 | PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
46 | NTSTATUS status;
47 | ULONG IoctlCode;
48 | DWORD info;
49 | PKEXEC_BUFFER buf;
50 |
51 | status = STATUS_SUCCESS;
52 |
53 | IoctlCode = IrpStack->Parameters.DeviceIoControl.IoControlCode;
54 |
55 | /* Select the buffer we are operating on. */
56 | switch (IoctlCode & KEXEC_BUFFER_MASK) {
57 | case KEXEC_KERNEL:
58 | buf = &KexecKernel;
59 | break;
60 | case KEXEC_INITRD:
61 | buf = &KexecInitrd;
62 | break;
63 | case KEXEC_KERNEL_COMMAND_LINE:
64 | buf = &KexecKernelCommandLine;
65 | break;
66 | default:
67 | status = STATUS_INVALID_PARAMETER;
68 | info = 0;
69 | goto end;
70 | }
71 | /* Perform the requested operation. */
72 | switch (IoctlCode & KEXEC_OPERATION_MASK) {
73 | case KEXEC_SET:
74 | status = KexecLoadBuffer(buf,
75 | IrpStack->Parameters.DeviceIoControl.InputBufferLength,
76 | Irp->AssociatedIrp.SystemBuffer);
77 | info = 0;
78 | break;
79 | case KEXEC_GET:
80 | status = KexecGetBuffer(buf,
81 | IrpStack->Parameters.DeviceIoControl.OutputBufferLength,
82 | Irp->AssociatedIrp.SystemBuffer, &info);
83 | break;
84 | case KEXEC_GET_SIZE:
85 | if (IrpStack->Parameters.DeviceIoControl.OutputBufferLength != sizeof(DWORD)) {
86 | status = STATUS_INVALID_PARAMETER;
87 | info = 0;
88 | } else {
89 | *(DWORD*)(Irp->AssociatedIrp.SystemBuffer) = KexecGetBufferSize(buf);
90 | status = STATUS_SUCCESS;
91 | info = sizeof(DWORD);
92 | }
93 | break;
94 | default:
95 | status = STATUS_INVALID_PARAMETER;
96 | goto end;
97 | }
98 |
99 | /* Return the results. */
100 | end:
101 | Irp->IoStatus.Status = status;
102 | Irp->IoStatus.Information = info;
103 | IoCompleteRequest(Irp, IO_NO_INCREMENT);
104 | return status;
105 | }
106 |
107 | /* Called before shutdown - use this chance to hook HalReturnToFirmware() */
108 | NTSTATUS DDKAPI KexecShutdown(PDEVICE_OBJECT DeviceObject KEXEC_UNUSED, PIRP Irp)
109 | {
110 | NTSTATUS status;
111 |
112 | status = KexecHookReboot();
113 |
114 | Irp->IoStatus.Status = status;
115 | Irp->IoStatus.Information = 0;
116 | IoCompleteRequest(Irp, IO_NO_INCREMENT);
117 | return status;
118 | }
119 |
--------------------------------------------------------------------------------
/driver/io.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KEXEC_DRIVER_IO_H
19 | #define KEXEC_DRIVER_IO_H
20 |
21 | #include
22 |
23 | NTSTATUS DDKAPI KexecOpen(PDEVICE_OBJECT DeviceObject, PIRP Irp);
24 | NTSTATUS DDKAPI KexecClose(PDEVICE_OBJECT DeviceObject, PIRP Irp);
25 | NTSTATUS DDKAPI KexecIoctl(PDEVICE_OBJECT DeviceObject, PIRP Irp);
26 | NTSTATUS DDKAPI KexecShutdown(PDEVICE_OBJECT DeviceObject, PIRP Irp);
27 |
28 | #endif
29 |
--------------------------------------------------------------------------------
/driver/kexec.inf.in:
--------------------------------------------------------------------------------
1 | ; WinKexec: kexec for Windows
2 | ; Copyright (C) 2008-2009 John Stumpo
3 | ;
4 | ; This program is free software: you can redistribute it and/or modify
5 | ; it under the terms of the GNU General Public License as published by
6 | ; the Free Software Foundation, either version 3 of the License, or
7 | ; (at your option) any later version.
8 | ;
9 | ; This program is distributed in the hope that it will be useful,
10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | ; GNU General Public License for more details.
13 | ;
14 | ; You should have received a copy of the GNU General Public License
15 | ; along with this program. If not, see .
16 |
17 | ; For the strange syntax: don't blame me, blame Microsoft.
18 |
19 | [Version]
20 | Signature = "$Windows NT$"
21 | Class = System
22 | ClassGuid = {4D36E97D-E325-11CE-BFC1-08002BE10318}
23 | Provider = %Author%
24 |
25 | ; Where stuff goes
26 | [DestinationDirs]
27 | DefaultDestDir = 12
28 | Kexec_SysFiles = 12 ; into %SystemRoot%\System32\Drivers
29 |
30 | [SourceDisksNames]
31 | 1 = "Kexec Installation Source Path"
32 |
33 | [SourceDisksFiles]
34 | kexec.sys = 1
35 |
36 | [Manufacturer]
37 | %Author% = Kexec
38 |
39 | [Kexec]
40 | %Description% = DefaultInstall,kexec
41 |
42 | ; The stuff that's done on installation.
43 | [DefaultInstall.NT]
44 | CopyFiles = Kexec_SysFiles
45 |
46 | [DefaultInstall.NT.Services]
47 | AddService = kexec,,Kexec_Service
48 |
49 | ; The stuff that's done on uninstallation.
50 | [Uninstall.NT]
51 | DelFiles = Kexec_SysFiles
52 |
53 | [Uninstall.NT.Services]
54 | DelService = kexec,0x00000200
55 |
56 | ; Copied to %SystemRoot%\System32\Drivers
57 | [Kexec_SysFiles]
58 | kexec.sys
59 |
60 | ; Register the driver.
61 | [Kexec_Service]
62 | DisplayName = %Description%
63 | ServiceType = 1 ; kernel module
64 | StartType = 3 ; manually loaded
65 | ErrorControl = 1 ; do nothing on error
66 | ServiceBinary = %12%\kexec.sys
67 |
68 | ; Substitution strings for all above sections
69 | [Strings]
70 | Author = "John Stumpo"
71 | Description = "Kexec Driver"
72 |
--------------------------------------------------------------------------------
/driver/libpe.c:
--------------------------------------------------------------------------------
1 | /* libpe: Small library to do interesting things with PE
2 | * executables from kernel mode under Windows.
3 | * Originally developed as part of WinKexec: kexec for Windows
4 | * Copyright (C) 2008-2009 John Stumpo
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * This file is available under a proprietary license as well.
20 | * Contact John Stumpo for details.
21 | */
22 |
23 | /* Some routines to work with PE files from kernel mode.
24 | kexec.sys uses these to change ntoskrnl.exe's idea of where
25 | hal.dll's HalReturnToFirmware() function is. Feel free to
26 | use these in your own drivers too. */
27 |
28 | #include "libpe.h"
29 |
30 | /* M$ makes you declare it yourself... */
31 | int _snwprintf(PWCHAR buffer, size_t count, const PWCHAR format, ...);
32 |
33 | /* Read the entirety of a file from system32 into a nonpaged buffer.
34 | Returns NULL on error. If a buffer is returned, you must
35 | call ExFreePool() on it when you are finished with it. */
36 | PVOID PeReadSystemFile(PWCHAR Filename)
37 | {
38 | HANDLE FileHandle;
39 | NTSTATUS status;
40 | OBJECT_ATTRIBUTES ObjectAttributes;
41 | WCHAR FullFilenameBuffer[256];
42 | UNICODE_STRING FullFilename;
43 | IO_STATUS_BLOCK StatusBlock;
44 | PVOID FileReadBuffer;
45 | FILE_STANDARD_INFORMATION FileInfo;
46 | LARGE_INTEGER FilePointer;
47 |
48 | /* More black magic - \SystemRoot goes to the Windows install root. */
49 | _snwprintf(FullFilenameBuffer, 255, L"\\SystemRoot\\system32\\%s", Filename);
50 | RtlInitUnicodeString(&FullFilename, FullFilenameBuffer);
51 |
52 | InitializeObjectAttributes(&ObjectAttributes, &FullFilename, 0, NULL, NULL);
53 |
54 | /* Open the file. */
55 | status = ZwOpenFile(&FileHandle, GENERIC_READ, &ObjectAttributes, &StatusBlock,
56 | FILE_SHARE_READ, FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
57 | if (!NT_SUCCESS(status))
58 | return NULL;
59 |
60 | /* Figure out how long it is. */
61 | status = ZwQueryInformationFile(FileHandle, &StatusBlock, &FileInfo,
62 | sizeof(FileInfo), FileStandardInformation);
63 | if (!NT_SUCCESS(status)) {
64 | ZwClose(FileHandle);
65 | return NULL;
66 | }
67 |
68 | /* Make sure value is sane. */
69 | if (FileInfo.EndOfFile.HighPart) {
70 | ZwClose(FileHandle);
71 | return NULL;
72 | }
73 |
74 | /* Grab a buffer for the file. */
75 | FileReadBuffer = ExAllocatePoolWithTag(NonPagedPool,
76 | FileInfo.EndOfFile.LowPart, TAG('K', 'x', 'e', 'c'));
77 | if (!FileReadBuffer) {
78 | ZwClose(FileHandle);
79 | return NULL;
80 | }
81 |
82 | /* Read the file in. */
83 | FilePointer.HighPart = FilePointer.LowPart = 0;
84 | status = ZwReadFile(FileHandle, NULL, NULL, NULL, &StatusBlock,
85 | FileReadBuffer, FileInfo.EndOfFile.LowPart, &FilePointer, NULL);
86 | if (!NT_SUCCESS(status)) {
87 | ExFreePool(FileReadBuffer);
88 | ZwClose(FileHandle);
89 | return NULL;
90 | }
91 |
92 | /* Close the file. */
93 | status = ZwClose(FileHandle);
94 | if (!NT_SUCCESS(status)) {
95 | ExFreePool(FileReadBuffer);
96 | return NULL;
97 | }
98 |
99 | return FileReadBuffer;
100 | }
101 |
102 | /* Return the PIMAGE_NT_HEADERS for a loaded PE file.
103 | Returns NULL on error. */
104 | PIMAGE_NT_HEADERS PeGetNtHeaders(PVOID PeFile)
105 | {
106 | PIMAGE_NT_HEADERS PeHeaders;
107 |
108 | /* Verify the MZ magic number. */
109 | if (((PIMAGE_DOS_HEADER)PeFile)->e_magic != 0x5a4d)
110 | return NULL;
111 |
112 | /* Get to the PE header.
113 | Verify the magic number ("PE\0\0") while we're here. */
114 | PeHeaders = PeFile + ((PIMAGE_DOS_HEADER)PeFile)->e_lfanew;
115 | if (PeHeaders->Signature != 0x00004550)
116 | return NULL;
117 |
118 | return PeHeaders;
119 | }
120 |
121 | /* Return a pointer to the first PE section header, or NULL on error. */
122 | PIMAGE_SECTION_HEADER PeGetFirstSectionHeader(PVOID PeFile)
123 | {
124 | if (!PeGetNtHeaders(PeFile))
125 | return NULL;
126 |
127 | return (PIMAGE_SECTION_HEADER)(PeGetNtHeaders(PeFile) + 1);
128 | }
129 |
130 | /* Return a the number of PE section headers, or zero on error. */
131 | WORD PeGetSectionCount(PVOID PeFile)
132 | {
133 | if (!PeGetNtHeaders(PeFile))
134 | return 0;
135 |
136 | return PeGetNtHeaders(PeFile)->FileHeader.NumberOfSections;
137 | }
138 |
139 | /* Get the section header for the section that houses the given address. */
140 | PIMAGE_SECTION_HEADER PeFindSectionHeaderForAddress(PVOID PeFile, DWORD Address)
141 | {
142 | PIMAGE_SECTION_HEADER CurrentSection;
143 |
144 | if (!PeGetNtHeaders(PeFile))
145 | return NULL;
146 |
147 | PeForEachSectionHeader(PeFile, CurrentSection) {
148 | if (Address >= CurrentSection->VirtualAddress &&
149 | Address < CurrentSection->VirtualAddress + CurrentSection->SizeOfRawData)
150 | return CurrentSection;
151 | }
152 | return NULL;
153 | }
154 |
155 | /* Convert a relative virtual address (RVA) into a usable pointer
156 | into the raw PE file data. Returns NULL on error. */
157 | PVOID PeConvertRva(PVOID PeFile, DWORD Rva)
158 | {
159 | PIMAGE_SECTION_HEADER RelevantSection;
160 |
161 | if (!(RelevantSection = PeFindSectionHeaderForAddress(PeFile, Rva)))
162 | return NULL;
163 |
164 | return RelevantSection->PointerToRawData - RelevantSection->VirtualAddress +
165 | PeFile + Rva;
166 | }
167 |
168 | /* Return the export directory from a PE file, or NULL on error. */
169 | PIMAGE_EXPORT_DIRECTORY PeGetExportDirectory(PVOID PeFile)
170 | {
171 | PIMAGE_NT_HEADERS PeHeaders;
172 |
173 | if (!(PeHeaders = PeGetNtHeaders(PeFile)))
174 | return NULL;
175 |
176 | return PeConvertRva(PeFile,
177 | PeHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
178 | }
179 |
180 | /* Return the import directory from a PE file, or NULL on error.
181 | (This is really the first import descriptor - there is no separate
182 | directory, as with the exports.) */
183 | PIMAGE_IMPORT_DESCRIPTOR PeGetFirstImportDescriptor(PVOID PeFile)
184 | {
185 | PIMAGE_NT_HEADERS PeHeaders;
186 |
187 | if (!(PeHeaders = PeGetNtHeaders(PeFile)))
188 | return NULL;
189 |
190 | return PeConvertRva(PeFile,
191 | PeHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
192 | }
193 |
194 | /* Return the address of an exported function, or NULL on error. */
195 | DWORD PeGetExportFunction(PVOID PeFile, PCHAR FunctionName)
196 | {
197 | PIMAGE_EXPORT_DIRECTORY ExportDirectory;
198 | DWORD * Functions;
199 | DWORD * Names;
200 | WORD * Ordinals;
201 | DWORD i;
202 |
203 | if (!(ExportDirectory = PeGetExportDirectory(PeFile)))
204 | return (DWORD)NULL;
205 |
206 | Functions = PeConvertRva(PeFile, ExportDirectory->AddressOfFunctions);
207 | Names = PeConvertRva(PeFile, ExportDirectory->AddressOfNames);
208 | Ordinals = PeConvertRva(PeFile, ExportDirectory->AddressOfNameOrdinals);
209 |
210 | for (i = 0; i < ExportDirectory->NumberOfFunctions; i++) {
211 | if (!strcmp(PeConvertRva(PeFile, Names[i]), FunctionName))
212 | return Functions[Ordinals[ExportDirectory->Base + i - 1]];
213 | }
214 | return (DWORD)NULL;
215 | }
216 |
217 | /* Return the address of the import pointer, or NULL on error. */
218 | DWORD PeGetImportPointer(PVOID PeFile, PCHAR DllName, PCHAR FunctionName)
219 | {
220 | PIMAGE_IMPORT_DESCRIPTOR ImportDescriptor;
221 | PIMAGE_THUNK_DATA NameThunk, CallThunk;
222 | PIMAGE_IMPORT_BY_NAME NamedImport;
223 |
224 | if (!(ImportDescriptor = PeGetFirstImportDescriptor(PeFile)))
225 | return (DWORD)NULL;
226 |
227 | while (ImportDescriptor->Name) {
228 | if (!strcasecmp(PeConvertRva(PeFile, ImportDescriptor->Name), DllName))
229 | goto FoundDll;
230 | ImportDescriptor++;
231 | }
232 | return (DWORD)NULL;
233 |
234 | FoundDll:
235 | for (NameThunk = PeConvertRva(PeFile, ImportDescriptor->OriginalFirstThunk),
236 | CallThunk = (PIMAGE_THUNK_DATA)ImportDescriptor->FirstThunk;
237 | NameThunk->u1.AddressOfData; NameThunk++, CallThunk++)
238 | {
239 | NamedImport = PeConvertRva(PeFile, NameThunk->u1.AddressOfData);
240 | if (!strcmp(NamedImport->Name, FunctionName))
241 | return (DWORD)CallThunk;
242 | }
243 | return (DWORD)NULL;
244 | }
245 |
--------------------------------------------------------------------------------
/driver/libpe.h:
--------------------------------------------------------------------------------
1 | /* libpe: Small library to do interesting things with PE
2 | * executables from kernel mode under Windows.
3 | * Originally developed as part of WinKexec: kexec for Windows
4 | * Copyright (C) 2008-2009 John Stumpo
5 | *
6 | * This program is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This program is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with this program. If not, see .
18 | *
19 | * This file is available under a proprietary license as well.
20 | * Contact John Stumpo for details.
21 | */
22 |
23 | #ifndef __LIBPE_H
24 | #define __LIBPE_H
25 |
26 | #include
27 |
28 | PVOID PeReadSystemFile(PWCHAR Filename);
29 | PIMAGE_NT_HEADERS PeGetNtHeaders(PVOID PeFile);
30 | PIMAGE_SECTION_HEADER PeGetFirstSectionHeader(PVOID PeFile);
31 | WORD PeGetSectionCount(PVOID PeFile);
32 | PIMAGE_SECTION_HEADER PeFindSectionHeaderForAddress(PVOID PeFile, DWORD Address);
33 | PVOID PeConvertRva(PVOID PeFile, DWORD Rva);
34 | PIMAGE_EXPORT_DIRECTORY PeGetExportDirectory(PVOID PeFile);
35 | PIMAGE_IMPORT_DESCRIPTOR PeGetFirstImportDescriptor(PVOID PeFile);
36 | DWORD PeGetExportFunction(PVOID PeFile, PCHAR FunctionName);
37 | DWORD PeGetImportPointer(PVOID PeFile, PCHAR DllName, PCHAR FunctionName);
38 |
39 | #define PeForEachSectionHeader(PeFile, SectionVariable) \
40 | for ((SectionVariable) = PeGetFirstSectionHeader(PeFile); \
41 | (SectionVariable) - PeGetFirstSectionHeader(PeFile) < \
42 | PeGetSectionCount(PeFile); \
43 | (SectionVariable)++)
44 |
45 | #endif
46 |
--------------------------------------------------------------------------------
/driver/linuxboot.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 |
20 | #include "linuxboot.h"
21 | #include "buffer.h"
22 | #include "util.h" /* assembly routines - we avoid inline assembly
23 | in case we try to port to another compiler. */
24 |
25 | /* A binary blob that we are going to need -
26 | namely, the boot code that will finish the job for us. */
27 | #include "boot/bootcode.h"
28 | /* A structure that the binary blob uses. */
29 | #include "boot/bootinfo.h"
30 |
31 | /* Bail out of the boot process - all we can do now is BSoD... */
32 | static void KEXEC_NORETURN BootPanic(PCHAR msg, DWORD code1, DWORD code2,
33 | DWORD code3, DWORD code4)
34 | {
35 | DbgPrint("kexec: *** PANIC: %s\n", msg);
36 | KeBugCheckEx(0x00031337, code1, code2, code3, code4);
37 | }
38 |
39 | /* Stash away a pointer to a block of memory for use during boot. */
40 | static void WriteKernelPointer(DWORD** pd KEXEC_UNUSED,
41 | DWORD** pdpos, DWORD** pt, DWORD** ptpos, PVOID virt_addr)
42 | {
43 | PHYSICAL_ADDRESS p;
44 |
45 | /* Allocate a new page table, if necessary. */
46 | if ((!*ptpos) || (*ptpos - *pt >= 1024)) {
47 | *pt = *ptpos = ExAllocatePoolWithTag(NonPagedPool,
48 | 4096, TAG('K', 'x', 'e', 'c'));
49 | if (!*pt)
50 | BootPanic("Could not allocate page table!", 0x00000002,
51 | (DWORD)virt_addr, 0, 0);
52 | p = MmGetPhysicalAddress(*pt);
53 | *((*pdpos)++) = p.LowPart | 0x00000023;
54 | *((*pdpos)++) = p.HighPart;
55 | }
56 |
57 | /* Write a 64-bit pointer into the page table.
58 | (Note: said table will be used with PAE enabled.) */
59 | if (virt_addr) {
60 | p = MmGetPhysicalAddress(virt_addr);
61 | *((*ptpos)++) = p.LowPart | 0x00000023; /* necessary page flags */
62 | *((*ptpos)++) = p.HighPart;
63 | } else {
64 | *((*ptpos)++) = 0;
65 | *((*ptpos)++) = 0;
66 | }
67 | }
68 |
69 | /* By the time this is called, Windows thinks it just handed control over
70 | to the BIOS to reboot the computer. As a result, nothing is really going
71 | on, and we can take great liberties (such as hard-coding physical memory
72 | addresses) in taking over and booting Linux.
73 |
74 | Does not return.
75 | */
76 | static void KEXEC_NORETURN DoLinuxBoot(void)
77 | {
78 | /* Here's how things are going to go:
79 | We're going to build PAE page tables that point to the
80 | physical addresses of 4K pages that hold the kernel, initrd, and
81 | kernel command line, with unmapped pages in between. We will also
82 | build a PAE page directory pointing to the physical addresses of the
83 | page tables so that we can communicate the physical address of the
84 | page directory to the boot code, it can put it into its PDPT, and
85 | we can have nice easy access to the kernel data using virtual
86 | addresses before we put it back together in contiguous physical
87 | memory.
88 | Maximum length: 1 PAE page directory worth of virtual
89 | address space, which amounts to 1 GB.
90 |
91 | At physical address 0x00008000, we will copy the code that will be used
92 | to escape from protected mode, set things up for the boot, and
93 | reassemble and boot the Linux kernel. In this file, we refer to that
94 | code as the "boot code."
95 | */
96 | PHYSICAL_ADDRESS addr;
97 | PVOID code_dest;
98 | ULONG i;
99 | DWORD* kx_page_directory;
100 | DWORD* kx_pd_position;
101 | DWORD* kx_page_table;
102 | DWORD* kx_pt_position;
103 | struct bootinfo* info_block;
104 |
105 | /* Allocate the page directory for the kernel map. */
106 | kx_page_directory = ExAllocatePoolWithTag(NonPagedPool,
107 | 4096, TAG('K', 'x', 'e', 'c'));
108 | if (!kx_page_directory)
109 | BootPanic("Could not allocate page directory!", 0x00000001, 0, 0, 0);
110 | kx_pd_position = kx_page_directory;
111 |
112 | kx_pt_position = 0;
113 |
114 | #define PAGE(a) WriteKernelPointer(&kx_page_directory, &kx_pd_position, \
115 | &kx_page_table, &kx_pt_position, (a))
116 |
117 | /* Write a series of pointers to pages of the kernel,
118 | followed by a sentinel zero. */
119 | for (i = 0; i < KexecKernel.Size; i += 4096)
120 | PAGE(KexecKernel.Data + i);
121 | PAGE(0);
122 |
123 | /* Same for the initrd. */
124 | for (i = 0; i < KexecInitrd.Size; i += 4096)
125 | PAGE(KexecInitrd.Data + i);
126 | PAGE(0);
127 |
128 | /* And finally the kernel command line.
129 | (This *will* only be a single page [much less, actually!] if our new
130 | kernel [not to mention the boot code!] is to not complain loudly and
131 | fail, but treating it like the other two data chunks we already have
132 | will make things simpler as far as the boot code goes.) */
133 | for (i = 0; i < KexecKernelCommandLine.Size; i += 4096)
134 | PAGE(KexecKernelCommandLine.Data + i);
135 | PAGE(0);
136 |
137 | #undef PAGE
138 |
139 | /* Now that the paging structures are built, we must get the
140 | boot code into the right place and fill in the information
141 | table at the end of the first page of said code. */
142 | addr.QuadPart = 0x0000000000008000ULL;
143 | code_dest = MmMapIoSpace(addr, BOOTCODE_BIN_SIZE, MmNonCached);
144 | RtlCopyMemory(code_dest, bootcode_bin, BOOTCODE_BIN_SIZE);
145 | info_block = (struct bootinfo*)(code_dest + 0x0fb0);
146 | info_block->kernel_size = KexecKernel.Size;
147 | RtlCopyMemory(info_block->kernel_hash, KexecKernel.Sha1Hash, 20);
148 | info_block->initrd_size = KexecInitrd.Size;
149 | RtlCopyMemory(info_block->initrd_hash, KexecInitrd.Sha1Hash, 20);
150 | info_block->cmdline_size = KexecKernelCommandLine.Size;
151 | RtlCopyMemory(info_block->cmdline_hash, KexecKernelCommandLine.Sha1Hash, 20);
152 | addr = MmGetPhysicalAddress(kx_page_directory);
153 | info_block->page_directory_ptr = addr.QuadPart | 0x0000000000000001ULL;
154 | MmUnmapIoSpace(code_dest, BOOTCODE_BIN_SIZE);
155 |
156 | /* Now we must prepare to execute the boot code.
157 | The most important preparation step is to identity-map the memory
158 | containing it - to make its physical and virtual addresses the same.
159 | We do this by direct manipulation of the page table. This has to be
160 | done for it to be able to safely turn off paging, return to
161 | real mode, and do its thing.
162 |
163 | Needless to say, here be dragons!
164 | */
165 |
166 | /* Abandon all interrupts, ye who execute here! */
167 | util_cli();
168 |
169 | /* PAE versus non-PAE means different paging structures.
170 | Naturally, we will have to take that into account.
171 | */
172 | if (util_pae_enabled()) {
173 | /* We have PAE.
174 | 0x00008000 = directory 0, table 0, page 8, offset 0x000
175 | */
176 | DWORD* page_directory_pointer_table;
177 | DWORD* page_directory;
178 | DWORD* page_table;
179 |
180 | /* Where is the page directory pointer table? */
181 | addr.HighPart = 0x00000000;
182 | addr.LowPart = util_get_cr3() & 0xffffffe0;
183 | page_directory_pointer_table = MmMapIoSpace(addr, 4096, MmNonCached);
184 |
185 | /* If the page directory isn't present, use
186 | the second page below the boot code. */
187 | if (!(page_directory_pointer_table[0] & 0x00000001)) {
188 | page_directory_pointer_table[0] = 0x00006000;
189 | page_directory_pointer_table[1] = 0x00000000;
190 | }
191 | page_directory_pointer_table[0] |= 0x00000001;
192 | page_directory_pointer_table[1] &= 0x7fffffff;
193 | util_reload_cr3(); /* so a modification to the PDPT takes effect */
194 |
195 | /* Where is the page directory? */
196 | addr.HighPart = page_directory_pointer_table[1];
197 | addr.LowPart = page_directory_pointer_table[0] & 0xfffff000;
198 | page_directory = MmMapIoSpace(addr, 4096, MmNonCached);
199 |
200 | /* If the page table isn't present, use
201 | the next page below the boot code. */
202 | if (!(page_directory[0] & 0x00000001)) {
203 | page_directory[0] = 0x00007000;
204 | page_directory[1] = 0x00000000;
205 | }
206 | page_directory[0] |= 0x00000023;
207 | page_directory[1] &= 0x7fffffff;
208 |
209 | /* Map the page table and tweak it to our needs. */
210 | addr.HighPart = page_directory[1];
211 | addr.LowPart = page_directory[0] & 0xfffff000;
212 | page_table = MmMapIoSpace(addr, 4096, MmNonCached);
213 | page_table[0x10] = 0x00008023;
214 | page_table[0x11] = 0x00000000;
215 | MmUnmapIoSpace(page_table, 4096);
216 |
217 | MmUnmapIoSpace(page_directory, 4096);
218 | MmUnmapIoSpace(page_directory_pointer_table, 4096);
219 | } else {
220 | /* No PAE - it's the original x86 paging mechanism.
221 | 0x00008000 = table 0, page 8, offset 0x000
222 | */
223 | DWORD* page_directory;
224 | DWORD* page_table;
225 |
226 | /* Where is the page directory? */
227 | addr.HighPart = 0x00000000;
228 | addr.LowPart = util_get_cr3() & 0xfffff000;
229 | page_directory = MmMapIoSpace(addr, 4096, MmNonCached);
230 |
231 | /* If the page table isn't present, use
232 | the next page below the boot code. */
233 | if (!(page_directory[0] & 0x00000001))
234 | page_directory[0] = 0x00007000;
235 | page_directory[0] |= 0x00000023;
236 |
237 | /* Map the page table and tweak it to our needs. */
238 | addr.HighPart = 0x00000000;
239 | addr.LowPart = page_directory[0] & 0xfffff000;
240 | page_table = MmMapIoSpace(addr, 4096, MmNonCached);
241 | page_table[0x08] = 0x00008023;
242 | MmUnmapIoSpace(page_table, 4096);
243 |
244 | MmUnmapIoSpace(page_directory, 4096);
245 | }
246 |
247 | /* Flush the page from the TLB... */
248 | util_invlpg(0x00008000);
249 |
250 | /* ...and away we go! */
251 | ((void (*)())0x00008000)();
252 |
253 | /* Should never happen. */
254 | KeBugCheckEx(0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242);
255 | }
256 |
257 | /* A kernel thread routine.
258 | We use this to bring down all but the first processor.
259 | Does not return. */
260 | static VOID KEXEC_NORETURN KexecThreadProc(PVOID Context KEXEC_UNUSED)
261 | {
262 | HANDLE hThread;
263 | ULONG currentProcessor;
264 | KIRQL irql;
265 |
266 | /* Fork-bomb all but the first processor.
267 | To do that, we create a thread that calls this function again. */
268 | PsCreateSystemThread(&hThread, GENERIC_ALL, 0, NULL,
269 | NULL, (PKSTART_ROUTINE)KexecThreadProc, NULL);
270 | ZwClose(hThread);
271 |
272 | /* Prevent thread switching on this processor. */
273 | KeRaiseIrql(DISPATCH_LEVEL, &irql);
274 |
275 | currentProcessor = util_current_processor();
276 | DbgPrint("KexecThreadProc() entered on processor #%d.\n", currentProcessor);
277 |
278 | /* If we're the first processor, go ahead. */
279 | if (currentProcessor == 0)
280 | DoLinuxBoot();
281 |
282 | /* Otherwise, come to a screeching halt. */
283 | DbgPrint("kexec: killing processor #%d", currentProcessor);
284 | util_cli();
285 | util_hlt();
286 | }
287 |
288 | /* Initiate the Linux boot process.
289 | Does not return. */
290 | void KEXEC_NORETURN KexecLinuxBoot(void)
291 | {
292 | KexecThreadProc(NULL);
293 | }
294 |
--------------------------------------------------------------------------------
/driver/linuxboot.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KEXEC_DRIVER_LINUXBOOT_H
19 | #define KEXEC_DRIVER_LINUXBOOT_H
20 |
21 | #include
22 | #include
23 |
24 | void KexecLinuxBoot(void) KEXEC_NORETURN;
25 |
26 | #endif
27 |
--------------------------------------------------------------------------------
/driver/reboot.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | /* Hook system reboot, and define the stuff needed to handle it. */
19 |
20 | #include "libpe.h"
21 | #include "linuxboot.h"
22 | #include "reboot.h"
23 | #include "buffer.h"
24 |
25 | /* NOTE: This is undocumented! */
26 | typedef enum _FIRMWARE_REENTRY {
27 | HalHaltRoutine,
28 | HalPowerDownRoutine,
29 | HalRestartRoutine,
30 | HalRebootRoutine,
31 | HalInteractiveModeRoutine,
32 | HalMaximumRoutine,
33 | } FIRMWARE_REENTRY, *PFIRMWARE_REENTRY;
34 |
35 | typedef VOID KEXEC_NORETURN NTAPI(*halReturnToFirmware_t)(FIRMWARE_REENTRY);
36 |
37 | static halReturnToFirmware_t real_HalReturnToFirmware;
38 |
39 | /* Our "enhanced" version of HalReturnToFirmware.
40 | Drops through if we don't have a kernel to load or if an invalid
41 | operation type is specified. The guts of ntoskrnl.exe will be
42 | tricked into calling this after everything is ready for "reboot." */
43 | static VOID KEXEC_NORETURN NTAPI KexecDoReboot(FIRMWARE_REENTRY RebootType)
44 | {
45 | if (RebootType == HalRebootRoutine && KexecGetBufferSize(&KexecKernel))
46 | KexecLinuxBoot();
47 | else
48 | real_HalReturnToFirmware(RebootType);
49 |
50 | /* Should never happen. */
51 | KeBugCheckEx(0x42424242, 0x42424242, 0x42424242, 0x42424242, 0x42424242);
52 | }
53 |
54 | NTSTATUS KexecHookReboot(void)
55 | {
56 | PVOID Ntoskrnl = NULL;
57 | PVOID KernelBase;
58 | DWORD ImportOffset;
59 | halReturnToFirmware_t* Target;
60 | PMDL Mdl;
61 | int i;
62 | PWCHAR KernelFilenames[] = {L"ntoskrnl.exe", L"ntkrnlpa.exe",
63 | L"ntkrnlmp.exe", L"ntkrpamp.exe", NULL};
64 |
65 | for (i = 0; KernelFilenames[i]; i++) {
66 | if (!(Ntoskrnl = PeReadSystemFile(KernelFilenames[i])))
67 | return STATUS_INSUFFICIENT_RESOURCES;
68 |
69 | /* Compute base load address of ntoskrnl.exe by doing this to
70 | an arbitrary function from ntoskrnl.exe. */
71 | KernelBase = KeBugCheckEx - PeGetExportFunction(Ntoskrnl, "KeBugCheckEx");
72 | if (KernelBase == KeBugCheckEx) {
73 | ExFreePool(Ntoskrnl);
74 | Ntoskrnl = NULL;
75 | continue;
76 | }
77 |
78 | /* Make sure it's right. */
79 | if (!MmIsAddressValid(KernelBase) || !PeGetNtHeaders(KernelBase)) {
80 | ExFreePool(Ntoskrnl);
81 | Ntoskrnl = NULL;
82 | continue;
83 | }
84 |
85 | break;
86 | }
87 |
88 | if (!Ntoskrnl)
89 | return STATUS_UNSUCCESSFUL;
90 |
91 | if (!(ImportOffset = PeGetImportPointer(Ntoskrnl, "hal.dll", "HalReturnToFirmware"))) {
92 | ExFreePool(Ntoskrnl);
93 | return STATUS_UNSUCCESSFUL;
94 | }
95 |
96 | ExFreePool(Ntoskrnl);
97 |
98 | Target = (halReturnToFirmware_t*)(KernelBase + ImportOffset);
99 |
100 | /* Here we go!
101 | We need to unprotect the chunk of RAM the import table is in. */
102 | if (!(Mdl = IoAllocateMdl(Target, sizeof(halReturnToFirmware_t), FALSE, FALSE, NULL)))
103 | return STATUS_UNSUCCESSFUL;
104 | MmBuildMdlForNonPagedPool(Mdl);
105 | Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
106 | if (!(Target = MmMapLockedPagesSpecifyCache(Mdl, KernelMode, MmNonCached,
107 | NULL, FALSE, HighPagePriority)))
108 | {
109 | IoFreeMdl(Mdl);
110 | return STATUS_UNSUCCESSFUL;
111 | }
112 | real_HalReturnToFirmware = *Target;
113 | *Target = KexecDoReboot; /* This is it! */
114 | MmUnmapLockedPages(Target, Mdl);
115 | IoFreeMdl(Mdl);
116 |
117 | return STATUS_SUCCESS;
118 | }
119 |
--------------------------------------------------------------------------------
/driver/reboot.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KEXEC_DRIVER_REBOOT_H
19 | #define KEXEC_DRIVER_REBOOT_H
20 |
21 | #include
22 |
23 | NTSTATUS KexecHookReboot(void);
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/driver/resource.rc:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 |
20 | #include "../revtag/revtag.h"
21 |
22 | LANGUAGE 9, 1
23 |
24 | VS_VERSION_INFO VERSIONINFO
25 | FILEVERSION RES_VERSION
26 | PRODUCTVERSION RES_VERSION
27 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
28 | FILEOS VOS_NT_WINDOWS32
29 | FILETYPE VFT_DRV
30 | FILESUBTYPE VFT2_DRV_SYSTEM
31 | BEGIN
32 | BLOCK "StringFileInfo"
33 | BEGIN
34 | BLOCK "040904B0"
35 | BEGIN
36 | VALUE "CompanyName", "John Stumpo"
37 | VALUE "FileDescription", "Kexec Driver"
38 | VALUE "FileVersion", VERSION_STR
39 | VALUE "InternalName", "kexec.sys"
40 | VALUE "LegalCopyright", "\251 2008-2009 John Stumpo. GNU GPL v3 or later."
41 | VALUE "OriginalFilename", "kexec.sys"
42 | VALUE "ProductName", "WinKexec"
43 | VALUE "ProductVersion", VERSION_STR
44 | END
45 | END
46 | BLOCK "VarFileInfo"
47 | BEGIN
48 | VALUE "Translation", 0x409, 1200
49 | END
50 | END
51 |
--------------------------------------------------------------------------------
/driver/sha1.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Incredibly minimal implementation of SHA1.
3 | * Totally independent of any other code (even libc) so it can be
4 | * run on bare hardware.
5 | *
6 | * Originally developed as part of the WinKexec project.
7 | * (This SHA1 implementation is the only part of WinKexec that is under the
8 | * license given below; the rest is under GPLv3 or later.)
9 | *
10 | * Copyright (C) 2009 John Stumpo
11 | * All rights reserved.
12 | *
13 | * Redistribution and use in source and binary forms, with or without
14 | * modification, are permitted provided that the following conditions are met:
15 | * * Redistributions of source code must retain the above copyright
16 | * notice, this list of conditions and the following disclaimer.
17 | * * Redistributions in binary form must reproduce the above copyright
18 | * notice, this list of conditions and the following disclaimer in the
19 | * documentation and/or other materials provided with the distribution.
20 | *
21 | * THIS SOFTWARE IS PROVIDED BY JOHN STUMPO ''AS IS'' AND ANY
22 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 | * DISCLAIMED. IN NO EVENT SHALL JOHN STUMPO BE LIABLE FOR ANY
25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | #include "sha1.h"
34 |
35 | /* All of these macros assume use on a 32-bit variable.
36 | Additionally, SWAP assumes we're little-endian. */
37 | #define SWAP(a) ((((a) >> 24) & 0x000000ff) | (((a) >> 8) & 0x0000ff00) | \
38 | (((a) << 8) & 0x00ff0000) | (((a) << 24) & 0xff000000))
39 | #define ROL(a, b) (((a) << (b)) | ((a) >> (32 - (b))))
40 | #define ROR(a, b) ROL((a), (32 - (b)))
41 |
42 | /* Copy srclen bytes of src to dest, padding with zeros to dstlen. */
43 | static void _copy_buffer(void* dest, const void* src, size_t srclen, size_t dstlen)
44 | {
45 | size_t i;
46 | for (i = 0; i < dstlen; i++) {
47 | if (i < srclen)
48 | *(unsigned char*)(dest + i) = *(unsigned char*)(src + i);
49 | else
50 | *(unsigned char*)(dest + i) = 0;
51 | }
52 | }
53 |
54 | /* The SHA1 implementation proper. */
55 | void sha1(void* outbuf, const void* inbuf, size_t length)
56 | {
57 | size_t i, j;
58 | int remaining_bytes;
59 | uint32_t h0, h1, h2, h3, h4, a, b, c, d, e, temp;
60 | uint32_t w[80];
61 | unsigned char buf[64];
62 |
63 | /* Initialize SHA1 hash state. */
64 | h0 = 0x67452301;
65 | h1 = 0xefcdab89;
66 | h2 = 0x98badcfe;
67 | h3 = 0x10325476;
68 | h4 = 0xc3d2e1f0;
69 |
70 | /* The extra 9 bytes are the pad byte (0x80) and 64-bit bit count that
71 | are appended to the data being hashed. (There will more than likely
72 | also be some zeroes in between the 0x80 and the bit count so that we
73 | operate on a multiple of 64 bytes; 9 bytes, though, is the minimal
74 | amount of extra data.) */
75 | for (i = 0; i < length + 9; i += 64) {
76 |
77 | /* Perform any padding necessary. */
78 | remaining_bytes = length - i;
79 | if (remaining_bytes >= 64) {
80 | _copy_buffer(buf, inbuf + i, 64, 64);
81 | } else if (remaining_bytes >= 0) {
82 | _copy_buffer(buf, inbuf + i, remaining_bytes, 64);
83 | buf[remaining_bytes] = 0x80;
84 | } else {
85 | _copy_buffer(buf, NULL, 0, 64);
86 | }
87 | if (remaining_bytes < 56)
88 | *(uint32_t*)(buf + 60) = SWAP(length * 8);
89 |
90 | /* Build the input array. */
91 | for (j = 0; j < 16; j++)
92 | w[j] = SWAP(*(uint32_t*)(buf + j * 4));
93 | for (j = 16; j < 80; j++)
94 | w[j] = ROL(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
95 |
96 | /* Load hash state. */
97 | a = h0;
98 | b = h1;
99 | c = h2;
100 | d = h3;
101 | e = h4;
102 |
103 | for (j = 0; j < 80; j++) {
104 | if (j < 20)
105 | temp = ((b & c) | ((~b) & d)) + 0x5a827999;
106 | else if (j < 40)
107 | temp = (b ^ c ^ d) + 0x6ed9eba1;
108 | else if (j < 60)
109 | temp = ((b & c) | (b & d) | (c & d)) + 0x8f1bbcdc;
110 | else
111 | temp = (b ^ c ^ d) + 0xca62c1d6;
112 | temp += ROL(a, 5) + e + w[j];
113 |
114 | e = d;
115 | d = c;
116 | c = ROR(b, 2);
117 | b = a;
118 | a = temp;
119 | }
120 |
121 | /* Incorporate the results of the hash operation. */
122 | h0 += a;
123 | h1 += b;
124 | h2 += c;
125 | h3 += d;
126 | h4 += e;
127 | }
128 |
129 | /* Write the hash into the output buffer. */
130 | *(uint32_t*)(outbuf) = SWAP(h0);
131 | *(uint32_t*)(outbuf + 4) = SWAP(h1);
132 | *(uint32_t*)(outbuf + 8) = SWAP(h2);
133 | *(uint32_t*)(outbuf + 12) = SWAP(h3);
134 | *(uint32_t*)(outbuf + 16) = SWAP(h4);
135 | }
136 |
--------------------------------------------------------------------------------
/driver/sha1.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Incredibly minimal implementation of SHA1.
3 | * Totally independent of any other code (even libc) so it can be
4 | * run on bare hardware.
5 | *
6 | * Originally developed as part of the WinKexec project.
7 | * (This SHA1 implementation is the only part of WinKexec that is under the
8 | * license given below; the rest is under GPLv3 or later.)
9 | *
10 | * Copyright (C) 2009 John Stumpo
11 | * All rights reserved.
12 | *
13 | * Redistribution and use in source and binary forms, with or without
14 | * modification, are permitted provided that the following conditions are met:
15 | * * Redistributions of source code must retain the above copyright
16 | * notice, this list of conditions and the following disclaimer.
17 | * * Redistributions in binary form must reproduce the above copyright
18 | * notice, this list of conditions and the following disclaimer in the
19 | * documentation and/or other materials provided with the distribution.
20 | *
21 | * THIS SOFTWARE IS PROVIDED BY JOHN STUMPO ''AS IS'' AND ANY
22 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 | * DISCLAIMED. IN NO EVENT SHALL JOHN STUMPO BE LIABLE FOR ANY
25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 | */
32 |
33 | #ifndef SHA1_H
34 | #define SHA1_H
35 |
36 | /* Only typedefs - thus, we're still completely freestanding. */
37 | #include
38 | #include
39 |
40 | void sha1(void* outbuf, const void* inbuf, size_t length);
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/driver/util.asm:
--------------------------------------------------------------------------------
1 | ; WinKexec: kexec for Windows
2 | ; Copyright (C) 2008-2009 John Stumpo
3 | ;
4 | ; This program is free software: you can redistribute it and/or modify
5 | ; it under the terms of the GNU General Public License as published by
6 | ; the Free Software Foundation, either version 3 of the License, or
7 | ; (at your option) any later version.
8 | ;
9 | ; This program is distributed in the hope that it will be useful,
10 | ; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | ; GNU General Public License for more details.
13 | ;
14 | ; You should have received a copy of the GNU General Public License
15 | ; along with this program. If not, see .
16 |
17 | ; Various utility functions written in assembly for use by the final bit
18 | ; of C code to set things up for the Linux boot.
19 |
20 | section .text
21 | bits 32
22 |
23 | ; Disable interrupts.
24 | global _util_cli
25 | _util_cli:
26 | cli
27 | ret
28 |
29 | ; Repeatedly halt the processor in a never-ending loop.
30 | ; Does not return.
31 | global _util_hlt
32 | _util_hlt:
33 | hlt
34 | jmp short _util_hlt
35 |
36 | ; Figure out whether PAE is enabled.
37 | ; Returns 1 if true or 0 if false.
38 | global _util_pae_enabled
39 | _util_pae_enabled:
40 | mov eax, cr4
41 | and eax, 0x00000020
42 | shr eax, 5
43 | ret
44 |
45 | ; Get cr3, which is the physical address of the page directory.
46 | global _util_get_cr3
47 | _util_get_cr3:
48 | mov eax, cr3
49 | ret
50 |
51 | ; Flush from the TLB the page whose address is passed as arg1.
52 | global _util_invlpg
53 | _util_invlpg:
54 | mov eax, [esp + 4]
55 | invlpg [eax]
56 | ret
57 |
58 | ; Get the current processor number.
59 | ; (Because KeGetCurrentProcessorNumber() epically fails in MinGW.)
60 | global _util_current_processor
61 | _util_current_processor:
62 | movzx eax, byte [fs:0x00000051]
63 | ret
64 |
65 | ; A convenient debug breakpoint.
66 | global _util_int3
67 | _util_int3:
68 | int3
69 | ret
70 |
71 | ; Reload cr3 with the same value it had before.
72 | ; Useful to force a PDPT reload or forget any cached mappings.
73 | global _util_reload_cr3
74 | _util_reload_cr3:
75 | mov eax, cr3
76 | mov cr3, eax
77 | ret
78 |
--------------------------------------------------------------------------------
/driver/util.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KEXEC_DRIVER_UTIL_H
19 | #define KEXEC_DRIVER_UTIL_H
20 |
21 | #include
22 |
23 | void util_cli(void);
24 | void util_hlt(void) KEXEC_NORETURN;
25 |
26 | int util_pae_enabled(void);
27 | uint32_t util_get_cr3(void);
28 | void util_invlpg(uint32_t page_address);
29 | /* Because KeGetCurrentProcessorNumber() epically fails under MinGW. */
30 | uint32_t util_current_processor(void);
31 | void util_int3(void);
32 | void util_reload_cr3(void);
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/guiclient/KexecGui.c:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #define _WIN32_WINNT 0x0500
19 | #define _WIN32_IE 0x0500
20 |
21 | #include
22 | #include
23 |
24 | #include
25 | #include
26 |
27 | #include "resource.h"
28 |
29 | #define OFNBUFSIZE 1024
30 |
31 | static HINSTANCE hInst;
32 | static BOOL ctlButtonLoadsDriver;
33 |
34 |
35 | /* Update the state of the driver-related items in the main dialog. */
36 | static void KxgUpdateDriverState(HWND hDlg)
37 | {
38 | DWORD klen, ilen;
39 | unsigned char buf[256];
40 |
41 | if (KxcIsDriverLoaded()) {
42 | SetDlgItemText(hDlg, KXG_ID_CONTROL_DRIVER, "Unload driver");
43 | if (!KxcDriverOperation(KEXEC_GET_SIZE | KEXEC_KERNEL, NULL, 0, &klen, sizeof(DWORD))) {
44 | KxcReportErrorMsgbox(hDlg);
45 | klen = 0;
46 | }
47 | if (klen == 0)
48 | strcpy(buf, "The kexec driver is active, but no kernel is loaded.");
49 | else {
50 | if (!KxcDriverOperation(KEXEC_GET_SIZE | KEXEC_INITRD, NULL, 0, &ilen, sizeof(DWORD))) {
51 | KxcReportErrorMsgbox(hDlg);
52 | ilen = 0;
53 | }
54 | if (ilen == 0)
55 | sprintf(buf, "Driver active with %lu-byte kernel and no initrd.", klen);
56 | else
57 | sprintf(buf, "Driver active with %lu-byte kernel and %lu-byte initrd.", klen, ilen);
58 | }
59 | SetDlgItemText(hDlg, KXG_ID_STATUS_TEXT, buf);
60 | EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
61 | ctlButtonLoadsDriver = FALSE;
62 | } else {
63 | SetDlgItemText(hDlg, KXG_ID_CONTROL_DRIVER, "Load driver");
64 | SetDlgItemText(hDlg, KXG_ID_STATUS_TEXT, "The kexec driver is not loaded.");
65 | EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
66 | ctlButtonLoadsDriver = TRUE;
67 | }
68 | }
69 |
70 |
71 | /* Apply the settings given in the dialog. */
72 | static void KxgApplySettings(HWND hDlg)
73 | {
74 | unsigned char buf[1024];
75 | PVOID kbuf = NULL;
76 | PVOID ibuf = NULL;
77 | DWORD klen, ilen;
78 |
79 | /* Read the kernel into a buffer. */
80 | if (IsDlgButtonChecked(hDlg, KXG_ID_KERNEL_SWITCH)) {
81 | GetDlgItemText(hDlg, KXG_ID_KERNEL_FILENAME, buf, 1024);
82 | SetDlgItemText(hDlg, KXG_ID_STATUS_TEXT, "Reading kernel... ");
83 | if (!(kbuf = KxcLoadFile(buf, &klen))) {
84 | KxcReportErrorMsgbox(hDlg);
85 | goto end;
86 | }
87 |
88 | #if 0
89 | /* Magic numbers in a Linux kernel image */
90 | if (*(unsigned short*)(kbuf+510) != 0xaa55 ||
91 | strncmp(kbuf+514, "HdrS", 4) != 0)
92 | {
93 | fprintf(stderr, "warning: This does not look like a Linux kernel.\n");
94 | fprintf(stderr, "warning: Loading it anyway.\n");
95 | }
96 | #endif
97 | }
98 |
99 | /* Read the initrd into a buffer. */
100 | if (IsDlgButtonChecked(hDlg, KXG_ID_INITRD_SWITCH)) {
101 | GetDlgItemText(hDlg, KXG_ID_INITRD_FILENAME, buf, 1024);
102 | SetDlgItemText(hDlg, KXG_ID_STATUS_TEXT, "Reading initrd... ");
103 | if (!(ibuf = KxcLoadFile(buf, &ilen))) {
104 | KxcReportErrorMsgbox(hDlg);
105 | goto end;
106 | }
107 | }
108 |
109 | /* Now let kexec.sys know about it.
110 | Do the kernel... */
111 | SetDlgItemText(hDlg, KXG_ID_STATUS_TEXT, "Loading kernel into kexec driver... ");
112 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_KERNEL, kbuf, klen, NULL, 0)) {
113 | KxcReportErrorMsgbox(hDlg);
114 | goto end;
115 | }
116 |
117 | /* ...and the initrd. */
118 | if (ibuf) {
119 | SetDlgItemText(hDlg, KXG_ID_STATUS_TEXT, "Loading initrd into kexec driver... ");
120 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_INITRD, ibuf, ilen, NULL, 0)) {
121 | KxcReportErrorMsgbox(hDlg);
122 | goto end;
123 | }
124 | } else {
125 | SetDlgItemText(hDlg, KXG_ID_STATUS_TEXT, "Setting null initrd... ");
126 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_INITRD, NULL, 0, NULL, 0)) {
127 | KxcReportErrorMsgbox(hDlg);
128 | goto end;
129 | }
130 | }
131 |
132 | /* Set the kernel command line. */
133 | GetDlgItemText(hDlg, KXG_ID_KERNEL_COMMAND_LINE, buf, 1024);
134 | SetDlgItemText(hDlg, KXG_ID_STATUS_TEXT, "Setting kernel command line... ");
135 | if (!KxcDriverOperation(KEXEC_SET | KEXEC_KERNEL_COMMAND_LINE, buf, strlen(buf), NULL, 0)) {
136 | KxcReportErrorMsgbox(hDlg);
137 | goto end;
138 | }
139 |
140 | KxgUpdateDriverState(hDlg);
141 | if (kbuf)
142 | MessageBox(hDlg, "Application successful.\n\n"
143 | "To boot into the newly loaded kernel, reboot Windows as you normally would.",
144 | "WinKexec GUI", MB_ICONINFORMATION | MB_OK);
145 | else
146 | MessageBox(hDlg, "Application successful.", "WinKexec GUI", MB_ICONINFORMATION | MB_OK);
147 |
148 | end:
149 | if (ibuf)
150 | free(ibuf);
151 | if (kbuf)
152 | free(kbuf);
153 | KxgUpdateDriverState(hDlg);
154 |
155 | }
156 |
157 | /* The processing routine for the main dialog. */
158 | static BOOL CALLBACK KxgMainDlgProc(HWND hDlg, UINT msg,
159 | WPARAM wParam, LPARAM lParam)
160 | {
161 | HANDLE bigIcon, smallIcon;
162 | HWND hCtl;
163 | UINT newState;
164 | OPENFILENAME ofn;
165 | unsigned char ofnbuf[OFNBUFSIZE];
166 | DWORD cmdlen;
167 | unsigned char* cmdbuf;
168 |
169 | switch (msg) {
170 | case WM_INITDIALOG:
171 | /* The dialog is being created; set the proper icon. */
172 | bigIcon = LoadImage(hInst, MAKEINTRESOURCE(KXG_ICON),
173 | IMAGE_ICON, GetSystemMetrics(SM_CXICON),
174 | GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR | LR_SHARED);
175 | SendMessage(hDlg, WM_SETICON, ICON_BIG, (LPARAM)bigIcon);
176 |
177 | smallIcon = LoadImage(hInst, MAKEINTRESOURCE(KXG_ICON),
178 | IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
179 | GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR | LR_SHARED);
180 | SendMessage(hDlg, WM_SETICON, ICON_SMALL, (LPARAM)smallIcon);
181 |
182 | /* Set some initial state. */
183 | KxgUpdateDriverState(hDlg);
184 | if (KxcIsDriverLoaded()) {
185 | /* Populate the kernel command line field with the existing kernel command line. */
186 | if (!KxcDriverOperation(KEXEC_GET_SIZE | KEXEC_KERNEL_COMMAND_LINE, NULL, 0, &cmdlen, sizeof(DWORD))) {
187 | KxcReportErrorMsgbox(NULL);
188 | } else {
189 | if (cmdlen > 0) {
190 | if (!(cmdbuf = malloc(cmdlen + 1))) {
191 | MessageBox(NULL, "malloc failure", "KexecGui", MB_ICONERROR | MB_OK);
192 | exit(EXIT_FAILURE);
193 | }
194 | if (!KxcDriverOperation(KEXEC_GET | KEXEC_KERNEL_COMMAND_LINE, NULL, 0, cmdbuf, cmdlen)) {
195 | KxcReportErrorMsgbox(NULL);
196 | } else {
197 | cmdbuf[cmdlen] = '\0';
198 | SetDlgItemText(hDlg, KXG_ID_KERNEL_COMMAND_LINE, cmdbuf);
199 | }
200 | free(cmdbuf);
201 | }
202 | }
203 | }
204 |
205 | break;
206 |
207 | case WM_COMMAND:
208 | hCtl = (HWND)lParam;
209 | switch (LOWORD(wParam)) {
210 | case IDOK:
211 | /* Apply button was pressed. */
212 | KxgApplySettings(hDlg);
213 | break;
214 |
215 | case IDCANCEL:
216 | /* Close button was pressed. */
217 | PostQuitMessage(0);
218 | break;
219 |
220 | case KXG_ID_KERNEL_SWITCH:
221 | /* Kernel checkbox was toggled. */
222 | newState = IsDlgButtonChecked(hDlg, KXG_ID_KERNEL_SWITCH);
223 | EnableWindow(GetDlgItem(hDlg, KXG_ID_KERNEL_FILENAME), newState);
224 | EnableWindow(GetDlgItem(hDlg, KXG_ID_KERNEL_BROWSE), newState);
225 | EnableWindow(GetDlgItem(hDlg, KXG_ID_KERNEL_COMMAND_LINE), newState);
226 | EnableWindow(GetDlgItem(hDlg, KXG_ID_INITRD_SWITCH), newState);
227 | break;
228 |
229 | case KXG_ID_INITRD_SWITCH:
230 | /* Initrd checkbox was toggled. */
231 | newState = IsDlgButtonChecked(hDlg, KXG_ID_INITRD_SWITCH);
232 | EnableWindow(GetDlgItem(hDlg, KXG_ID_INITRD_FILENAME), newState);
233 | EnableWindow(GetDlgItem(hDlg, KXG_ID_INITRD_BROWSE), newState);
234 | break;
235 |
236 | case KXG_ID_KERNEL_BROWSE:
237 | /* Kernel "Browse..." button was pressed. */
238 | ofn.lStructSize = sizeof(OPENFILENAME);
239 | ofn.hwndOwner = hDlg;
240 | ofn.lpstrFilter = "Linux kernels (*.lkrn, *bzImage*, *vmlinu?*, *.bzi)\0*.lkrn;*bzImage*;*vmlinu?*;*.bzi\0All Files\0*.*\0";
241 | ofn.lpstrCustomFilter = NULL;
242 | ofn.nFilterIndex = 1;
243 | ofn.lpstrFile = ofnbuf;
244 | GetDlgItemText(hDlg, KXG_ID_KERNEL_FILENAME, ofnbuf, OFNBUFSIZE);
245 | ofn.nMaxFile = OFNBUFSIZE;
246 | ofn.lpstrFileTitle = NULL;
247 | ofn.lpstrInitialDir = NULL;
248 | ofn.lpstrTitle = "Select Linux kernel";
249 | ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
250 | ofn.lpstrDefExt = NULL;
251 | if (GetOpenFileName(&ofn))
252 | SetDlgItemText(hDlg, KXG_ID_KERNEL_FILENAME, ofnbuf);
253 |
254 | break;
255 |
256 | case KXG_ID_INITRD_BROWSE:
257 | /* Initrd "Browse..." button was pressed. */
258 | ofn.lStructSize = sizeof(OPENFILENAME);
259 | ofn.hwndOwner = hDlg;
260 | ofn.lpstrFilter = "Initrd images (*.img, *.gz)\0*.img;*.gz\0All Files\0*.*\0";
261 | ofn.lpstrCustomFilter = NULL;
262 | ofn.nFilterIndex = 1;
263 | ofn.lpstrFile = ofnbuf;
264 | GetDlgItemText(hDlg, KXG_ID_INITRD_FILENAME, ofnbuf, OFNBUFSIZE);
265 | ofn.nMaxFile = OFNBUFSIZE;
266 | ofn.lpstrFileTitle = NULL;
267 | ofn.lpstrInitialDir = NULL;
268 | ofn.lpstrTitle = "Select initial root disk image";
269 | ofn.Flags = OFN_DONTADDTORECENT | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
270 | ofn.lpstrDefExt = NULL;
271 | if (GetOpenFileName(&ofn))
272 | SetDlgItemText(hDlg, KXG_ID_INITRD_FILENAME, ofnbuf);
273 |
274 | break;
275 |
276 | case KXG_ID_CONTROL_DRIVER:
277 | /* (Un)load driver button was pressed. */
278 | if (ctlButtonLoadsDriver)
279 | KxcLoadDriver();
280 | else
281 | KxcUnloadDriver();
282 |
283 | if (KxcErrorOccurred())
284 | KxcReportErrorMsgbox(hDlg);
285 |
286 | KxgUpdateDriverState(hDlg);
287 |
288 | break;
289 |
290 | case KXG_ID_HELP_ABOUT:
291 | /* "About WinKexec..." option in the Help menu */
292 | KxcAboutWinKexec(hDlg);
293 | break;
294 |
295 | default:
296 | return FALSE;
297 | }
298 | break;
299 |
300 | case WM_DESTROY:
301 | PostQuitMessage(0);
302 | break;
303 |
304 | case WM_CLOSE:
305 | DestroyWindow(hDlg);
306 | break;
307 |
308 | default:
309 | return FALSE;
310 | }
311 | return TRUE;
312 | }
313 |
314 |
315 | /* The entry point. */
316 | int WINAPI WinMain(HINSTANCE in_hInst, HINSTANCE prev KEXEC_UNUSED,
317 | LPSTR cmdline KEXEC_UNUSED, int winstyle KEXEC_UNUSED)
318 | {
319 | INITCOMMONCONTROLSEX initComCtlEx;
320 | HWND hDlg;
321 | MSG msg;
322 | DWORD status;
323 |
324 | KxcInit();
325 | KxcIsDriverLoaded();
326 |
327 | /* Use styled widgets if on XP or later. */
328 | initComCtlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
329 | initComCtlEx.dwICC = ICC_COOL_CLASSES;
330 | if (!InitCommonControlsEx(&initComCtlEx)) {
331 | MessageBox(NULL, "InitCommonControlsEx failed!", "KexecGui", MB_ICONERROR | MB_OK);
332 | exit(EXIT_FAILURE);
333 | }
334 |
335 | /* Set our hInstance aside for a rainy day. */
336 | hInst = in_hInst;
337 |
338 | /* Load the main window. */
339 | hDlg = CreateDialog(hInst, MAKEINTRESOURCE(KXG_MAIN_DLG),
340 | 0, KxgMainDlgProc);
341 | if (!hDlg) {
342 | MessageBox(NULL, "CreateDialog failed!", "KexecGui", MB_ICONERROR | MB_OK);
343 | exit(EXIT_FAILURE);
344 | }
345 |
346 | /* Now for the main loop. */
347 | while ((status = GetMessage(&msg, 0, 0, 0)) > 0) {
348 | if (!IsDialogMessage(hDlg, &msg)) {
349 | TranslateMessage(&msg);
350 | DispatchMessage(&msg);
351 | }
352 | }
353 | return msg.wParam;
354 | }
355 |
--------------------------------------------------------------------------------
/guiclient/Makefile:
--------------------------------------------------------------------------------
1 | # WinKexec: kexec for Windows
2 | # Copyright (C) 2008-2009 John Stumpo
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | include ../common.mk
18 |
19 | CFLAGS += -I../include
20 |
21 | KEXEC_GUI_OBJECTS = KexecGui.o resource.o
22 | KEXEC_GUI_LIBS = ../clientdll/KexecCommon.lib -lkernel32 -lmsvcrt -luser32 -lcomctl32 -lcomdlg32
23 |
24 | __main_target : KexecGui.exe
25 |
26 | KexecGui.exe : $(KEXEC_GUI_OBJECTS)
27 | $(CC) -mwindows $(CFLAGS) -o KexecGui.exe $(KEXEC_GUI_OBJECTS) $(KEXEC_GUI_LIBS)
28 |
29 | clean :
30 | -rm -f KexecGui.exe *.o
31 | .PHONY : clean
32 |
--------------------------------------------------------------------------------
/guiclient/resource.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KEXEC_GUI_RESOURCES_H
19 | #define KEXEC_GUI_RESOURCES_H
20 |
21 | #define KXG_ICON 1
22 | #define KXG_MAIN_DLG 1
23 | #define KXG_MAIN_MENU 1
24 |
25 | #define KXG_ID_KERNEL_SWITCH 20
26 | #define KXG_ID_INITRD_SWITCH 21
27 |
28 | #define KXG_ID_KERNEL_FILENAME 8000
29 | #define KXG_ID_KERNEL_COMMAND_LINE 8001
30 | #define KXG_ID_INITRD_FILENAME 8002
31 |
32 | #define KXG_ID_KERNEL_BROWSE 22
33 | #define KXG_ID_INITRD_BROWSE 23
34 |
35 | #define KXG_ID_CONTROL_DRIVER 24
36 |
37 | #define KXG_ID_STATUS_TEXT 2000
38 |
39 | #define KXG_ID_HELP_ABOUT 3000
40 |
41 | #endif
42 |
--------------------------------------------------------------------------------
/guiclient/resource.rc:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #include
19 | #include
20 |
21 | #include "resource.h"
22 |
23 | #include "../revtag/revtag.h"
24 |
25 | LANGUAGE 9, 1
26 |
27 | VS_VERSION_INFO VERSIONINFO
28 | FILEVERSION RES_VERSION
29 | PRODUCTVERSION RES_VERSION
30 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
31 | FILEOS VOS_NT_WINDOWS32
32 | FILETYPE VFT_APP
33 | FILESUBTYPE VFT2_UNKNOWN
34 | BEGIN
35 | BLOCK "StringFileInfo"
36 | BEGIN
37 | BLOCK "040904B0"
38 | BEGIN
39 | VALUE "CompanyName", "John Stumpo"
40 | VALUE "FileDescription", "Kexec for Windows GUI"
41 | VALUE "FileVersion", VERSION_STR
42 | VALUE "InternalName", "KexecGui.exe"
43 | VALUE "LegalCopyright", "\251 2008-2009 John Stumpo. GNU GPL v3 or later."
44 | VALUE "OriginalFilename", "KexecGui.exe"
45 | VALUE "ProductName", "WinKexec"
46 | VALUE "ProductVersion", VERSION_STR
47 | END
48 | END
49 | BLOCK "VarFileInfo"
50 | BEGIN
51 | VALUE "Translation", 0x409, 1200
52 | END
53 | END
54 |
55 | CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST
56 | BEGIN
57 | "\r\n"
58 | "\r\n"
59 | " \r\n"
61 | " Kexec for Windows GUI\r\n"
62 |
63 | /* This part triggers styled widgets on XP or later. */
64 | " \r\n"
65 | " \r\n"
66 | " \r\n"
69 | " \r\n"
70 | " \r\n"
71 |
72 | /* This part triggers UAC on Vista. */
73 | " \r\n"
74 | " \r\n"
75 | " \r\n"
76 | " \r\n"
77 | " \r\n"
78 | " \r\n"
79 | " \r\n"
80 | "\r\n"
81 | END
82 |
83 | KXG_ICON ICON "../icon/Icon.ico"
84 |
85 | KXG_MAIN_DLG DIALOGEX 0, 0, 232, 100
86 | STYLE WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_CENTER | WS_MINIMIZEBOX | WS_VISIBLE
87 | MENU KXG_MAIN_MENU
88 | CAPTION "WinKexec GUI"
89 | FONT 8, "MS Shell Dlg", 0, 0, 1
90 | BEGIN
91 | DEFPUSHBUTTON "Apply", IDOK, 121, 79, 50, 14
92 | PUSHBUTTON "Close", IDCANCEL, 175, 79, 50, 14
93 |
94 | AUTOCHECKBOX "Kernel:", KXG_ID_KERNEL_SWITCH, 7, 10, 62, 10
95 | LTEXT "Command line:", 1000, 19, 28, 50, 10
96 | AUTOCHECKBOX "Initrd:", KXG_ID_INITRD_SWITCH, 7, 46, 62, 10, WS_DISABLED
97 |
98 | EDITTEXT KXG_ID_KERNEL_FILENAME, 72, 7, 100, 14, WS_DISABLED | ES_AUTOHSCROLL
99 | EDITTEXT KXG_ID_KERNEL_COMMAND_LINE, 72, 25, 153, 14, WS_DISABLED | ES_AUTOHSCROLL
100 | EDITTEXT KXG_ID_INITRD_FILENAME, 72, 43, 100, 14, WS_DISABLED | ES_AUTOHSCROLL
101 |
102 | PUSHBUTTON "Browse...", KXG_ID_KERNEL_BROWSE, 175, 7, 50, 14, WS_DISABLED
103 | PUSHBUTTON "Browse...", KXG_ID_INITRD_BROWSE, 175, 43, 50, 14, WS_DISABLED
104 |
105 | PUSHBUTTON "", KXG_ID_CONTROL_DRIVER, 7, 79, 65, 14
106 |
107 | LTEXT "", KXG_ID_STATUS_TEXT, 7, 67, 218, 10
108 |
109 | END
110 |
111 | KXG_MAIN_MENU MENU
112 | BEGIN
113 | POPUP "&File"
114 | BEGIN
115 | MENUITEM "E&xit\tAlt+F4", IDCANCEL
116 | END
117 |
118 | POPUP "&Help"
119 | BEGIN
120 | MENUITEM "&About WinKexec...", KXG_ID_HELP_ABOUT
121 | END
122 | END
123 |
--------------------------------------------------------------------------------
/icon/Icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/icon/Icon.ico
--------------------------------------------------------------------------------
/icon/IconFull.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/icon/IconFull.xcf
--------------------------------------------------------------------------------
/icon/Icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/icon/Icon_16x16.png
--------------------------------------------------------------------------------
/icon/Icon_16x16.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/icon/Icon_16x16.xcf
--------------------------------------------------------------------------------
/icon/Icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/icon/Icon_32x32.png
--------------------------------------------------------------------------------
/icon/Icon_32x32.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/icon/Icon_32x32.xcf
--------------------------------------------------------------------------------
/icon/Icon_48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/icon/Icon_48x48.png
--------------------------------------------------------------------------------
/icon/Icon_48x48.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/icon/Icon_48x48.xcf
--------------------------------------------------------------------------------
/include/KexecCommon.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008-2009 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KEXECCOMMON_H
19 | #define KEXECCOMMON_H
20 |
21 | #include
22 | #include
23 |
24 | #include
25 |
26 | #ifdef IN_KEXEC_COMMON
27 | # define KEXECCOMMON_SPEC KEXEC_DLLEXPORT
28 | #else
29 | # define KEXECCOMMON_SPEC KEXEC_DLLIMPORT
30 | #endif
31 |
32 | KEXECCOMMON_SPEC BOOL KxcErrorOccurred(void);
33 | KEXECCOMMON_SPEC const char* KxcGetErrorMessage(void);
34 | KEXECCOMMON_SPEC void KxcReportErrorStderr(void);
35 | KEXECCOMMON_SPEC void KxcReportErrorMsgbox(HWND parent);
36 | KEXECCOMMON_SPEC void KxcAboutWinKexec(HWND parent);
37 | KEXECCOMMON_SPEC PVOID KxcLoadFile(const char* filename, DWORD* length);
38 | KEXECCOMMON_SPEC BOOL KxcDriverOperation(DWORD opcode, LPVOID ibuf, DWORD ibuflen, LPVOID obuf, DWORD obuflen);
39 | KEXECCOMMON_SPEC BOOL KxcIsDriverLoaded(void);
40 | KEXECCOMMON_SPEC BOOL KxcLoadDriver(void);
41 | KEXECCOMMON_SPEC BOOL KxcUnloadDriver(void);
42 | KEXECCOMMON_SPEC void KxcInit(void);
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/include/kexec.h:
--------------------------------------------------------------------------------
1 | /* WinKexec: kexec for Windows
2 | * Copyright (C) 2008 John Stumpo
3 | *
4 | * This program is free software: you can redistribute it and/or modify
5 | * it under the terms of the GNU General Public License as published by
6 | * the Free Software Foundation, either version 3 of the License, or
7 | * (at your option) any later version.
8 | *
9 | * This program is distributed in the hope that it will be useful,
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | * GNU General Public License for more details.
13 | *
14 | * You should have received a copy of the GNU General Public License
15 | * along with this program. If not, see .
16 | */
17 |
18 | #ifndef KEXEC_H
19 | #define KEXEC_H
20 |
21 | #ifdef DRIVER
22 | #include
23 | #else
24 | #include
25 | #include
26 | #endif
27 |
28 | /* Buffers to operate on */
29 | #define KEXEC_KERNEL CTL_CODE(0, 0x000, 0, 0)
30 | #define KEXEC_INITRD CTL_CODE(0, 0x004, 0, 0)
31 | #define KEXEC_KERNEL_COMMAND_LINE CTL_CODE(0, 0x008, 0, 0)
32 |
33 | /* Operations */
34 | #define KEXEC_SET CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_WRITE_DATA)
35 | #define KEXEC_GET_SIZE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_READ_DATA)
36 | #define KEXEC_GET CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_READ_DATA)
37 |
38 | /* Conveniently mask off either part of the ioctl code */
39 | #define KEXEC_BUFFER_MASK CTL_CODE(0, 0x00c, 0, 0)
40 | #define KEXEC_OPERATION_MASK (~KEXEC_BUFFER_MASK)
41 |
42 | /* Convenience macros */
43 | #ifdef __GNUC__
44 | # define KEXEC_DLLIMPORT __attribute__((__dllimport__))
45 | # define KEXEC_DLLEXPORT __attribute__((__dllexport__))
46 | # define KEXEC_UNUSED __attribute__((__unused__))
47 | # define KEXEC_PACKED __attribute__((packed))
48 | # define KEXEC_NORETURN __attribute__((noreturn))
49 | #else
50 | # define KEXEC_DLLIMPORT __declspec(dllimport)
51 | # define KEXEC_DLLEXPORT __declspec(dllexport)
52 | # define KEXEC_UNUSED
53 | # define KEXEC_PACKED
54 | # define KEXEC_NORETURN __declspec(noreturn)
55 | #endif
56 |
57 | #endif
58 |
--------------------------------------------------------------------------------
/revtag/Makefile:
--------------------------------------------------------------------------------
1 | # WinKexec: kexec for Windows
2 | # Copyright (C) 2008-2009 John Stumpo
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | include ../common.mk
18 |
19 | __main_target : revtag_headers
20 |
21 | revtag_headers :
22 | $(PYTHON) revtag.py --make-headers .. .
23 | .PHONY : revtag_headers
24 |
25 | clean :
26 | -rm -f revtag.h revtag.nsh
27 | .PHONY : clean
28 |
--------------------------------------------------------------------------------
/revtag/revtag.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # WinKexec: kexec for Windows
3 | # Copyright (C) 2008-2010 John Stumpo
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import sys
19 | import os
20 | import re
21 |
22 | VERSION = '1.0 development'
23 | RES_VERSION = '1.0.0.93' # distinguish from svn, where the last number
24 | # was the revision number, which went up to 92
25 |
26 | # List of macros to define in the generated header files
27 | macro_list = []
28 |
29 | # Generate a header file and return the contents.
30 | def make_header(prefix):
31 | innards = ''
32 | for key, value in macro_list:
33 | innards += '%sdefine %s %s\n' % (prefix, key, value)
34 | return '''%sifndef REVTAG_REVISION_HEADER
35 | %sdefine REVTAG_REVISION_HEADER
36 |
37 | %s
38 | %sendif
39 | ''' % (prefix, prefix, innards, prefix)
40 |
41 | def usage():
42 | sys.stderr.write('''usage: %s [operation] [path1] [path2]
43 |
44 | operation: --make-headers or --tag-file
45 | --make-headers: write C and NSIS header files containing revision number
46 | into folder named by path2
47 | --tag-file: substitute revision number into file named by path2
48 | and write results to stdout
49 |
50 | path1: path to get the revision number from
51 | path2: path to actually operate on
52 | ''' % sys.argv[0])
53 | sys.exit(1)
54 |
55 | def notify(msg):
56 | sys.stderr.write('%s: %s\n' % (sys.argv[0], msg))
57 |
58 | if len(sys.argv) != 4:
59 | usage()
60 |
61 | def get_revnum():
62 | try:
63 | # HEAD is in the form "ref: refs/heads/master\n"
64 | headref = open(os.path.join(sys.argv[2], '.git', 'HEAD')).read()[5:].strip()
65 | # The ref is in the form "sha1-hash\n"
66 | headhash = open(os.path.join(sys.argv[2], '.git', *headref.split('/'))).read().strip()
67 | shortref = re.sub('^refs/(heads/)?', '', headref)
68 | gitinfo = ' (git %s %s)' % (shortref, headhash[:7])
69 | except IOError:
70 | gitinfo = ''
71 |
72 | macro_list.append(('RES_VERSION', RES_VERSION.replace('.', ', ')))
73 | macro_list.append(('RES_VERSION_STR', '"%s"' % RES_VERSION))
74 | macro_list.append(('VERSION_STR', '"%s%s"' % (VERSION, gitinfo)))
75 |
76 | if sys.argv[1] == '--make-headers':
77 | get_revnum()
78 | os.chdir(sys.argv[3])
79 | revtag_h = make_header('#')
80 | revtag_nsh = make_header('!')
81 | try:
82 | old_revtag_h = open('revtag.h', 'r').read()
83 | except:
84 | old_revtag_h = None
85 | try:
86 | old_revtag_nsh = open('revtag.nsh', 'r').read()
87 | except:
88 | old_revtag_nsh = None
89 | if revtag_h == old_revtag_h:
90 | notify('revtag.h is up to date')
91 | else:
92 | notify('updating revtag.h')
93 | open('revtag.h', 'w').write(revtag_h)
94 | if revtag_nsh == old_revtag_nsh:
95 | notify('revtag.nsh is up to date')
96 | else:
97 | notify('updating revtag.nsh')
98 | open('revtag.nsh', 'w').write(revtag_nsh)
99 | elif sys.argv[1] == '--tag-file':
100 | get_revnum()
101 | fdata = open(sys.argv[3], 'r').read()
102 | for key, value in macro_list:
103 | fdata = fdata.replace('@%s@' % key, value)
104 | sys.stdout.write(fdata)
105 | else:
106 | usage()
107 |
--------------------------------------------------------------------------------
/setup/EnvVarUpdate.nsh:
--------------------------------------------------------------------------------
1 | ; EnvVarUpdate.nsh
2 | ; Cut-and-pasted verbatim from http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries#Function_Code
3 |
4 | /**
5 | * EnvVarUpdate.nsh
6 | * : Environmental Variables: append, prepend, and remove entries
7 | *
8 | * WARNING: If you use StrFunc.nsh header then include it before this file
9 | * with all required definitions. This is to avoid conflicts
10 | *
11 | * Usage:
12 | * ${EnvVarUpdate} "ResultVar" "EnvVarName" "Action" "RegLoc" "PathString"
13 | *
14 | * Credits:
15 | * Version 1.0
16 | * * Cal Turney (turnec2)
17 | * * Amir Szekely (KiCHiK) and e-circ for developing the forerunners of this
18 | * function: AddToPath, un.RemoveFromPath, AddToEnvVar, un.RemoveFromEnvVar,
19 | * WriteEnvStr, and un.DeleteEnvStr
20 | * * Diego Pedroso (deguix) for StrTok
21 | * * Kevin English (kenglish_hi) for StrContains
22 | * * Hendri Adriaens (Smile2Me), Diego Pedroso (deguix), and Dan Fuhry
23 | * (dandaman32) for StrReplace
24 | *
25 | * Version 1.1 (compatibility with StrFunc.nsh)
26 | * * techtonik
27 | *
28 | * http://nsis.sourceforge.net/Environmental_Variables:_append%2C_prepend%2C_and_remove_entries
29 | *
30 | */
31 |
32 |
33 | !ifndef ENVVARUPDATE_FUNCTION
34 | !define ENVVARUPDATE_FUNCTION
35 | !verbose push
36 | !verbose 3
37 | !include "LogicLib.nsh"
38 | !include "WinMessages.NSH"
39 | !include "StrFunc.nsh"
40 |
41 | ; ---- Fix for conflict if StrFunc.nsh is already includes in main file -----------------------
42 | !macro _IncludeStrFunction StrFuncName
43 | !ifndef ${StrFuncName}_INCLUDED
44 | ${${StrFuncName}}
45 | !endif
46 | !ifndef Un${StrFuncName}_INCLUDED
47 | ${Un${StrFuncName}}
48 | !endif
49 | !define un.${StrFuncName} "${Un${StrFuncName}}"
50 | !macroend
51 |
52 | !insertmacro _IncludeStrFunction StrTok
53 | !insertmacro _IncludeStrFunction StrStr
54 | !insertmacro _IncludeStrFunction StrRep
55 |
56 | ; ---------------------------------- Macro Definitions ----------------------------------------
57 | !macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
58 | Push "${EnvVarName}"
59 | Push "${Action}"
60 | Push "${RegLoc}"
61 | Push "${PathString}"
62 | Call EnvVarUpdate
63 | Pop "${ResultVar}"
64 | !macroend
65 | !define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"'
66 |
67 | !macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString
68 | Push "${EnvVarName}"
69 | Push "${Action}"
70 | Push "${RegLoc}"
71 | Push "${PathString}"
72 | Call un.EnvVarUpdate
73 | Pop "${ResultVar}"
74 | !macroend
75 | !define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"'
76 | ; ---------------------------------- Macro Definitions end-------------------------------------
77 |
78 | ;----------------------------------- EnvVarUpdate start----------------------------------------
79 | !define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"'
80 | !define hkcu_current_user 'HKCU "Environment"'
81 |
82 | !macro EnvVarUpdate UN
83 |
84 | Function ${UN}EnvVarUpdate
85 |
86 | Push $0
87 | Exch 4
88 | Exch $1
89 | Exch 3
90 | Exch $2
91 | Exch 2
92 | Exch $3
93 | Exch
94 | Exch $4
95 | Push $5
96 | Push $6
97 | Push $7
98 | Push $8
99 | Push $9
100 | Push $R0
101 |
102 | /* After this point:
103 | -------------------------
104 | $0 = ResultVar (returned)
105 | $1 = EnvVarName (input)
106 | $2 = Action (input)
107 | $3 = RegLoc (input)
108 | $4 = PathString (input)
109 | $5 = Orig EnvVar (read from registry)
110 | $6 = Len of $0 (temp)
111 | $7 = tempstr1 (temp)
112 | $8 = Entry counter (temp)
113 | $9 = tempstr2 (temp)
114 | $R0 = tempChar (temp) */
115 |
116 | ; Step 1: Read contents of EnvVarName from RegLoc
117 | ;
118 | ; Check for empty EnvVarName
119 | ${If} $1 == ""
120 | SetErrors
121 | DetailPrint "ERROR: EnvVarName is blank"
122 | Goto EnvVarUpdate_Restore_Vars
123 | ${EndIf}
124 |
125 | ; Check for valid Action
126 | ${If} $2 != "A"
127 | ${AndIf} $2 != "P"
128 | ${AndIf} $2 != "R"
129 | SetErrors
130 | DetailPrint "ERROR: Invalid Action - must be A, P, or R"
131 | Goto EnvVarUpdate_Restore_Vars
132 | ${EndIf}
133 |
134 | ${If} $3 == HKLM
135 | ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5
136 | ${ElseIf} $3 == HKCU
137 | ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5
138 | ${Else}
139 | SetErrors
140 | DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"'
141 | Goto EnvVarUpdate_Restore_Vars
142 | ${EndIf}
143 |
144 | ; Check for empty PathString
145 | ${If} $4 == ""
146 | SetErrors
147 | DetailPrint "ERROR: PathString is blank"
148 | Goto EnvVarUpdate_Restore_Vars
149 | ${EndIf}
150 |
151 | ; Make sure we've got some work to do
152 | ${If} $5 == ""
153 | ${AndIf} $2 == "R"
154 | SetErrors
155 | DetailPrint "$1 is empty - Nothing to remove"
156 | Goto EnvVarUpdate_Restore_Vars
157 | ${EndIf}
158 |
159 | ; Step 2: Scrub EnvVar
160 | ;
161 | StrCpy $0 $5 ; Copy the contents to $0
162 | ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or
163 | ; after the last one are not removed here but instead in Step 3)
164 | ${If} $0 != "" ; If EnvVar is not empty ...
165 | ${Do}
166 | ${${UN}StrStr} $7 $0 " ;"
167 | ${If} $7 == ""
168 | ${ExitDo}
169 | ${EndIf}
170 | ${${UN}StrRep} $0 $0 " ;" ";" ; Remove ';'
171 | ${Loop}
172 | ${Do}
173 | ${${UN}StrStr} $7 $0 "; "
174 | ${If} $7 == ""
175 | ${ExitDo}
176 | ${EndIf}
177 | ${${UN}StrRep} $0 $0 "; " ";" ; Remove ';'
178 | ${Loop}
179 | ${Do}
180 | ${${UN}StrStr} $7 $0 ";;"
181 | ${If} $7 == ""
182 | ${ExitDo}
183 | ${EndIf}
184 | ${${UN}StrRep} $0 $0 ";;" ";"
185 | ${Loop}
186 |
187 | ; Remove a leading or trailing semicolon from EnvVar
188 | StrCpy $7 $0 1 0
189 | ${If} $7 == ";"
190 | StrCpy $0 $0 "" 1 ; Change ';' to ''
191 | ${EndIf}
192 | StrLen $6 $0
193 | IntOp $6 $6 - 1
194 | StrCpy $7 $0 1 $6
195 | ${If} $7 == ";"
196 | StrCpy $0 $0 $6 ; Change ';' to ''
197 | ${EndIf}
198 | ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug
199 | ${EndIf}
200 |
201 | /* Step 3. Remove all instances of the target path/string (even if "A" or "P")
202 | $6 = bool flag (1 = found and removed PathString)
203 | $7 = a string (e.g. path) delimited by semicolon(s)
204 | $8 = entry counter starting at 0
205 | $9 = copy of $0
206 | $R0 = tempChar */
207 |
208 | ${If} $5 != "" ; If EnvVar is not empty ...
209 | StrCpy $9 $0
210 | StrCpy $0 ""
211 | StrCpy $8 0
212 | StrCpy $6 0
213 |
214 | ${Do}
215 | ${${UN}StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter
216 |
217 | ${If} $7 == "" ; If we've run out of entries,
218 | ${ExitDo} ; were done
219 | ${EndIf} ;
220 |
221 | ; Remove leading and trailing spaces from this entry (critical step for Action=Remove)
222 | ${Do}
223 | StrCpy $R0 $7 1
224 | ${If} $R0 != " "
225 | ${ExitDo}
226 | ${EndIf}
227 | StrCpy $7 $7 "" 1 ; Remove leading space
228 | ${Loop}
229 | ${Do}
230 | StrCpy $R0 $7 1 -1
231 | ${If} $R0 != " "
232 | ${ExitDo}
233 | ${EndIf}
234 | StrCpy $7 $7 -1 ; Remove trailing space
235 | ${Loop}
236 | ${If} $7 == $4 ; If string matches, remove it by not appending it
237 | StrCpy $6 1 ; Set 'found' flag
238 | ${ElseIf} $7 != $4 ; If string does NOT match
239 | ${AndIf} $0 == "" ; and the 1st string being added to $0,
240 | StrCpy $0 $7 ; copy it to $0 without a prepended semicolon
241 | ${ElseIf} $7 != $4 ; If string does NOT match
242 | ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0,
243 | StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon
244 | ${EndIf} ;
245 |
246 | IntOp $8 $8 + 1 ; Bump counter
247 | ${Loop} ; Check for duplicates until we run out of paths
248 | ${EndIf}
249 |
250 | ; Step 4: Perform the requested Action
251 | ;
252 | ${If} $2 != "R" ; If Append or Prepend
253 | ${If} $6 == 1 ; And if we found the target
254 | DetailPrint "Target is already present in $1. It will be removed and"
255 | ${EndIf}
256 | ${If} $0 == "" ; If EnvVar is (now) empty
257 | StrCpy $0 $4 ; just copy PathString to EnvVar
258 | ${If} $6 == 0 ; If found flag is either 0
259 | ${OrIf} $6 == "" ; or blank (if EnvVarName is empty)
260 | DetailPrint "$1 was empty and has been updated with the target"
261 | ${EndIf}
262 | ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty),
263 | StrCpy $0 $0;$4 ; append PathString
264 | ${If} $6 == 1
265 | DetailPrint "appended to $1"
266 | ${Else}
267 | DetailPrint "Target was appended to $1"
268 | ${EndIf}
269 | ${Else} ; If Prepend (and EnvVar is not empty),
270 | StrCpy $0 $4;$0 ; prepend PathString
271 | ${If} $6 == 1
272 | DetailPrint "prepended to $1"
273 | ${Else}
274 | DetailPrint "Target was prepended to $1"
275 | ${EndIf}
276 | ${EndIf}
277 | ${Else} ; If Action = Remove
278 | ${If} $6 == 1 ; and we found the target
279 | DetailPrint "Target was found and removed from $1"
280 | ${Else}
281 | DetailPrint "Target was NOT found in $1 (nothing to remove)"
282 | ${EndIf}
283 | ${If} $0 == ""
284 | DetailPrint "$1 is now empty"
285 | ${EndIf}
286 | ${EndIf}
287 |
288 | ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change
289 | ;
290 | ClearErrors
291 | ${If} $3 == HKLM
292 | WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section
293 | ${ElseIf} $3 == HKCU
294 | WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section
295 | ${EndIf}
296 |
297 | IfErrors 0 +4
298 | MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3"
299 | DetailPrint "Could not write updated $1 to $3"
300 | Goto EnvVarUpdate_Restore_Vars
301 |
302 | ; "Export" our change
303 | SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000
304 |
305 | EnvVarUpdate_Restore_Vars:
306 | ;
307 | ; Restore the user's variables and return ResultVar
308 | Pop $R0
309 | Pop $9
310 | Pop $8
311 | Pop $7
312 | Pop $6
313 | Pop $5
314 | Pop $4
315 | Pop $3
316 | Pop $2
317 | Pop $1
318 | Push $0 ; Push my $0 (ResultVar)
319 | Exch
320 | Pop $0 ; Restore his $0
321 |
322 | FunctionEnd
323 |
324 | !macroend ; EnvVarUpdate UN
325 | !insertmacro EnvVarUpdate ""
326 | !insertmacro EnvVarUpdate "un."
327 | ;----------------------------------- EnvVarUpdate end----------------------------------------
328 |
329 | !verbose pop
330 | !endif
--------------------------------------------------------------------------------
/setup/KexecDriver.nsi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/setup/KexecDriver.nsi
--------------------------------------------------------------------------------
/setup/KexecSetup.nsi:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sha0/winkexec/e21633c2958c5ae8b5452d595dcff37a97fe5f26/setup/KexecSetup.nsi
--------------------------------------------------------------------------------
/setup/Makefile:
--------------------------------------------------------------------------------
1 | # WinKexec: kexec for Windows
2 | # Copyright (C) 2008-2009 John Stumpo
3 | #
4 | # This program is free software: you can redistribute it and/or modify
5 | # it under the terms of the GNU General Public License as published by
6 | # the Free Software Foundation, either version 3 of the License, or
7 | # (at your option) any later version.
8 | #
9 | # This program is distributed in the hope that it will be useful,
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | # GNU General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU General Public License
15 | # along with this program. If not, see .
16 |
17 | include ../common.mk
18 |
19 | MAKENSISFLAGS = -V2
20 |
21 | __main_target : KexecSetup.exe KexecDriver.exe
22 |
23 | KexecSetup.exe : KexecDriver.exe
24 | $(MAKENSIS) $(MAKENSISFLAGS) KexecSetup.nsi
25 |
26 | KexecDriver.exe :
27 | $(MAKENSIS) $(MAKENSISFLAGS) KexecDriver.nsi
28 |
29 | clean :
30 | -rm -f KexecSetup.exe KexecDriver.exe
31 | .PHONY : clean
32 |
--------------------------------------------------------------------------------