├── .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 | --------------------------------------------------------------------------------