├── .editorconfig ├── .gitignore ├── .gitmodules ├── K6INIT.C ├── MAKEFILE ├── README.MD └── screenshots ├── k6init_auto.png ├── k6init_bars.png ├── k6init_multi.png └── k6init_status.png /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # DOS-style newlines + extra newline 5 | [*] 6 | end_of_line = crlf 7 | insert_final_newline = true 8 | charset = latin1 9 | indent_size = 4 10 | indent_style = space 11 | trim_trailing_whitespace = true 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | 3 | bin/ 4 | BIN/ 5 | 6 | *.OBJ 7 | *.obj 8 | *.LIB 9 | *.lib 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib866d"] 2 | path = lib866d 3 | url = https://github.com/oerg866/lib866d 4 | -------------------------------------------------------------------------------- /K6INIT.C: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "vesabios.h" 7 | #include "vgacon.h" 8 | #include "util.h" 9 | #include "args.h" 10 | #include "sys.h" 11 | #include "pci.h" 12 | #include "cpu_k6.h" 13 | 14 | #define __LIB866D_TAG__ "K6INIT" 15 | #include "debug.h" 16 | 17 | /* This structure holds all the arguments passed to the program. */ 18 | static struct { 19 | bool autoSetup; 20 | bool printBARs; 21 | /* MTRR Config */ 22 | struct { bool setup; 23 | bool clear; 24 | size_t count; 25 | cpu_K6_MemoryTypeRangeRegs toSet; } mtrr; 26 | /* Write Ordering Config */ 27 | struct { bool setup; 28 | u8 mode; } wOrder; 29 | /* Write Allocate Config */ 30 | struct { bool setup; 31 | bool hole; 32 | u32 size; } wAlloc; 33 | /* Multiplier Config */ 34 | struct { bool setup; 35 | u8 integer; 36 | u8 decimal; } multi; 37 | /* L1 Cache Config */ 38 | struct { bool setup; 39 | bool enable; } l1Cache; 40 | /* L2 Cache Config */ 41 | struct { bool setup; 42 | bool enable; } l2Cache; 43 | /* Data Prefetch Config */ 44 | struct { bool setup; 45 | bool enable; } prefetch; 46 | 47 | } s_params; 48 | 49 | typedef enum { 50 | K6_2_CXT = 0, 51 | K6_III, 52 | K6_PLUS, 53 | UNSUPPORTED_CPU 54 | } k6init_SupportedCPU; 55 | 56 | /* This structure holds all the detected system info we may need for this program. */ 57 | static struct { 58 | sys_CPUIDVersionInfo cpuidInfo; 59 | sys_CPUManufacturer cpuManufacturer; 60 | char cpuidString[13]; 61 | k6init_SupportedCPU thisCPU; 62 | cpu_K6_MemoryTypeRangeRegs mtrrs; 63 | cpu_K6_WriteAllocateConfig whcr; 64 | u32 memSize; 65 | bool memHole; 66 | bool vesaBIOSPresent; 67 | vesa_BiosInfo vesaBiosInfo; 68 | bool L1CacheEnabled; 69 | bool L2CacheEnabled; 70 | bool criticalError; 71 | } s_sysInfo; 72 | 73 | static char s_multiToParse[4] = {0,}; 74 | static u32 s_MTRRCfgQueue[4]; 75 | static const char k6init_versionString[] = "K6INIT Version 1.1 - (C) 2021-2024 Eric Voirin (oerg866)"; 76 | 77 | #define retPrintErrorIf(condition, message, value) if (condition) { vgacon_printError(message "\n", value); return false; } 78 | 79 | static bool k6init_addMTRRToConfig(u32 offset, u32 sizeKB, bool writeCombine, bool uncacheable) { 80 | retPrintErrorIf(s_params.mtrr.clear == true, "Cannot clear MTRRs and set them up at the same time!", 0); 81 | retPrintErrorIf(s_params.mtrr.count >= 2, "You are trying to configure too many MTRRs, maximum is 2!", 0); 82 | retPrintErrorIf(sizeKB > 0x400000UL, "Requested MTRR size of %lu KB too big!", sizeKB); 83 | retPrintErrorIf((offset % 131072UL) != 0UL, "MTRR offset %lu isn't aligned on a 128KB boundary!", offset); 84 | retPrintErrorIf(sizeKB < 128UL, "Requested MTRR size of %lu KB is too small (< 128KB)!", sizeKB); 85 | 86 | s_params.mtrr.toSet.configs[s_params.mtrr.count].offset = offset; 87 | s_params.mtrr.toSet.configs[s_params.mtrr.count].sizeKB = sizeKB; 88 | s_params.mtrr.toSet.configs[s_params.mtrr.count].writeCombine = writeCombine; 89 | s_params.mtrr.toSet.configs[s_params.mtrr.count].uncacheable = uncacheable; 90 | s_params.mtrr.toSet.configs[s_params.mtrr.count].isValid = true; 91 | 92 | DBG("k6init_addMTRRToConfig: 0x%08lx | %lu KB | %s | %s\n", offset, sizeKB, writeCombine ? "WC" : " ", uncacheable ? "UC" : " "); 93 | 94 | s_params.mtrr.count++; 95 | s_params.mtrr.setup = true; 96 | 97 | return true; 98 | } 99 | 100 | static bool k6init_argClearMTRRs(const void *arg) { 101 | UNUSED_ARG(arg); 102 | retPrintErrorIf(s_params.mtrr.setup == true, "Cannot clear MTRRs and set them up at the same time!", 0); 103 | 104 | memset(&s_params.mtrr.toSet, 0, sizeof(cpu_K6_MemoryTypeRangeRegs)); 105 | s_params.mtrr.count = 2; 106 | s_params.mtrr.setup = true; 107 | return true; 108 | } 109 | 110 | static bool k6init_argAddMTRR(const void *arg) { 111 | u32 *toParse = (u32 *)arg; 112 | bool formatOK = (toParse[2] <= 1 && toParse[3] <= 1); /* WC/UC flags must be valid bools */ 113 | 114 | retPrintErrorIf(formatOK == false, "MTRR Config Argument Format error.", 0); 115 | return k6init_addMTRRToConfig(toParse[0], toParse[1], (bool) toParse[2], (bool) toParse[3]); 116 | } 117 | 118 | static bool k6init_isKnownMTRRAddress(u32 address) { 119 | if (s_params.mtrr.setup == false) return false; 120 | if (address == s_params.mtrr.toSet.configs[0].offset) return true; 121 | if (address == s_params.mtrr.toSet.configs[1].offset) return true; 122 | return false; 123 | } 124 | 125 | /* Finds LFB addresses and stuff. */ 126 | bool k6init_findAndAddLFBsToMTRRConfig(void) { 127 | vesa_ModeInfo currentMode; 128 | bool vesaBiosValid = vesa_isValidVesaBios(&s_sysInfo.vesaBiosInfo); 129 | u32 vramSizeKB = vesa_getVRAMSize(&s_sysInfo.vesaBiosInfo) / 1024UL; 130 | size_t lfbsFound = 0; 131 | size_t i; 132 | 133 | retPrintErrorIf(vesaBiosValid == false, "No VESA BIOS found, cannot scan for LFBs!", 0); 134 | 135 | vgacon_print("Scanning %u VESA modes for Linear Frame Buffers...\n", (u16) vesa_getModeCount(&s_sysInfo.vesaBiosInfo)); 136 | 137 | for (i = 0; i < vesa_getModeCount(&s_sysInfo.vesaBiosInfo); i++) { 138 | retPrintErrorIf(false == vesa_getModeInfoByIndex(&s_sysInfo.vesaBiosInfo, ¤tMode, i), 139 | "No VESA BIOS found, cannot scan for LFBs!", 0); 140 | 141 | if (currentMode.attributes.hasLFB) { 142 | /* Check if the address is already known */ 143 | if (k6init_isKnownMTRRAddress(currentMode.lfbAddress)) { 144 | lfbsFound++; 145 | continue; 146 | } 147 | 148 | vgacon_print("Found Linear Frame Buffer at: 0x%08lx\n", currentMode.lfbAddress); 149 | L866_ASSERTM(lfbsFound < 2, "More than two unique LFB addresses found! Please configure manually!"); 150 | 151 | if (false == k6init_addMTRRToConfig(currentMode.lfbAddress, vramSizeKB, true, false)) { 152 | return false; 153 | } 154 | 155 | lfbsFound++; 156 | } 157 | } 158 | 159 | retPrintErrorIf(lfbsFound == 0, "There is a VESA BIOS but no LFB modes were found!", 0); 160 | return true; 161 | } 162 | 163 | bool k6init_findAndAddPCIFBsToMTRRConfig(void) { 164 | pci_Device *curDevice = NULL; 165 | pci_DeviceInfo curDeviceInfo; 166 | size_t pciFbsFound = 0; 167 | u32 i; 168 | 169 | retPrintErrorIf(pci_test() == false, "FATAL: Unable to access PCI bus!", 0); 170 | 171 | while (NULL != (curDevice = pci_getNextDevice(curDevice))) { 172 | /* If this isn't a VGA card, continue searching */ 173 | if (pci_getClass(*curDevice) != CLASS_DISPLAY || pci_getSubClass(*curDevice) != 0x00) 174 | continue; 175 | 176 | retPrintErrorIf(pci_populateDeviceInfo(&curDeviceInfo, *curDevice) == false, "Failed to read PCI device info!", 0); 177 | 178 | vgacon_print("Found Graphics Card, Vendor 0x%04x, Device 0x%04x\n", curDeviceInfo.vendor, curDeviceInfo.device); 179 | 180 | for (i = 0; i < PCI_BARS_MAX; i++) { 181 | if (curDeviceInfo.bars[i].type != PCI_BAR_MEMORY) continue; /* Must be memory BAR */ 182 | if (curDeviceInfo.bars[i].size < 1048576UL) continue; /* Must be at least 1MB */ 183 | 184 | /* Check if address is already known */ 185 | if (k6init_isKnownMTRRAddress(curDeviceInfo.bars[i].address)) { 186 | pciFbsFound++; 187 | continue; 188 | } 189 | 190 | vgacon_print("Found PCI/AGP frame buffer at: 0x%08lx\n", curDeviceInfo.bars[i].address); 191 | 192 | if (false == k6init_addMTRRToConfig(curDeviceInfo.bars[i].address, curDeviceInfo.bars[i].size / 1024UL, true, false)) { 193 | return false; 194 | } 195 | 196 | pciFbsFound++; 197 | } 198 | } 199 | 200 | if (curDevice != NULL) 201 | free(curDevice); 202 | 203 | retPrintErrorIf(pciFbsFound == 0, "No PCI/AGP Frame Buffers were found!", 0); 204 | 205 | return true; 206 | } 207 | 208 | static bool k6init_argAddLFBMTRR(const void *arg) { 209 | UNUSED_ARG(arg); 210 | return k6init_findAndAddLFBsToMTRRConfig(); 211 | } 212 | 213 | static bool k6init_argAddPCIMTRR(const void *arg) { 214 | UNUSED_ARG(arg); 215 | return k6init_findAndAddPCIFBsToMTRRConfig(); 216 | } 217 | 218 | static bool k6init_argAddVGAMTRR(const void *arg) { 219 | UNUSED_ARG(arg); 220 | return k6init_addMTRRToConfig(0xA0000, 128, true, false); 221 | } 222 | 223 | static bool k6init_argForceWAHole(const void *arg) { 224 | UNUSED_ARG(arg); 225 | retPrintErrorIf(s_params.wAlloc.setup == false, "Can't force 15M Hole without setting Write Allocate!", 0); 226 | return true; 227 | } 228 | 229 | static bool k6init_argWriteOrder(const void *arg) { 230 | retPrintErrorIf(s_params.wOrder.mode >= (u8) __CPU_K6_WRITEORDER_MODE_COUNT__, 231 | "Value %u for Write Order Mode out of range!\n", s_params.wOrder.mode); 232 | UNUSED_ARG(arg); 233 | return s_params.wOrder.setup = true; 234 | } 235 | 236 | static bool k6init_argWriteAllocate(const void *arg) { 237 | UNUSED_ARG(arg); 238 | return s_params.wAlloc.setup = true; 239 | } 240 | 241 | static bool k6init_argAddMulti(const void *arg) { 242 | bool formatOK = (isdigit(s_multiToParse[0])) 243 | && (s_multiToParse[1] == '.' && s_multiToParse[3] == 0x00) 244 | && (s_multiToParse[2] == '5' || s_multiToParse[2] == '0'); 245 | 246 | retPrintErrorIf(formatOK == false, "Multiplier argument ('%s') format error!", s_multiToParse); 247 | UNUSED_ARG(arg); 248 | 249 | s_params.multi.integer = (u8) (s_multiToParse[0] - '0'); 250 | s_params.multi.decimal = (u8) (s_multiToParse[2] - '0'); 251 | s_params.multi.setup = true; 252 | 253 | return true; 254 | } 255 | 256 | static bool k6init_argAddL1(const void *arg) { 257 | UNUSED_ARG(arg); 258 | return s_params.l1Cache.setup = true; 259 | } 260 | 261 | static bool k6init_argAddL2(const void *arg) { 262 | UNUSED_ARG(arg); 263 | return s_params.l2Cache.setup = true; 264 | } 265 | 266 | static bool k6init_argAddPrefetch(const void *arg) { 267 | UNUSED_ARG(arg); 268 | return s_params.prefetch.setup = true; 269 | } 270 | 271 | k6init_SupportedCPU k6init_getSupportedCPUFromCPUID(sys_CPUIDVersionInfo info) { 272 | if (info.basic.family == 5 && info.basic.model == 8 && info.basic.stepping == 0x0c) 273 | return K6_2_CXT; 274 | if (info.basic.family == 5 && info.basic.model == 9) 275 | return K6_III; 276 | if (info.basic.family == 5 && info.basic.model == 0x0d) 277 | return K6_PLUS; 278 | 279 | return UNSUPPORTED_CPU; 280 | }; 281 | 282 | static const char *k6init_getK6CPUString(k6init_SupportedCPU cpu) { 283 | if (cpu == K6_2_CXT) return "AMD K6-2 CXT"; 284 | if (cpu == K6_III) return "AMD K6-III"; 285 | if (cpu == K6_PLUS) return "AMD K6-2+/III+"; 286 | return ""; 287 | } 288 | 289 | static void k6init_populateSysInfo(void) { 290 | memset (&s_sysInfo, 0, sizeof(s_sysInfo)); 291 | 292 | /* Get CPU info */ 293 | sys_getCPUIDString(s_sysInfo.cpuidString); 294 | s_sysInfo.cpuidInfo = sys_getCPUIDVersionInfo(); 295 | s_sysInfo.thisCPU = k6init_getSupportedCPUFromCPUID(s_sysInfo.cpuidInfo); 296 | s_sysInfo.cpuManufacturer = sys_getCPUManufacturer(NULL); 297 | 298 | if (s_sysInfo.thisCPU != UNSUPPORTED_CPU) { 299 | s_sysInfo.criticalError |= !cpu_K6_getMemoryTypeRanges(&s_sysInfo.mtrrs); 300 | s_sysInfo.criticalError |= !cpu_K6_getWriteAllocateRange(&s_sysInfo.whcr); 301 | s_sysInfo.L1CacheEnabled = cpu_K6_getL1CacheStatus(); 302 | s_sysInfo.L2CacheEnabled = cpu_K6_getL2CacheStatus(); 303 | } 304 | 305 | /* Get memory info */ 306 | s_sysInfo.memSize = sys_getMemorySize(&s_sysInfo.memHole); 307 | 308 | /* Get VGA BIOS info */ 309 | s_sysInfo.vesaBIOSPresent = vesa_getBiosInfo(&s_sysInfo.vesaBiosInfo); 310 | } 311 | 312 | static void k6init_printCompactMTRRConfigs(const char *optionalTag, bool newLine) { 313 | size_t i; 314 | cpu_K6_getMemoryTypeRanges(&s_sysInfo.mtrrs); /* Update known MTRRs */ 315 | 316 | if (optionalTag != NULL) 317 | vgacon_print("%s", optionalTag); 318 | 319 | for (i = 0; i < 2; i++) { 320 | if (s_sysInfo.mtrrs.configs[i].isValid == true) { 321 | printf("<%u: %lu KB @ %08lx> ", i, 322 | s_sysInfo.mtrrs.configs[i].sizeKB, 323 | s_sysInfo.mtrrs.configs[i].offset); 324 | } else { 325 | printf("<%u: unconfigured> ", (u16) i); 326 | } 327 | } 328 | 329 | printf("%s", newLine ? "\n" : ""); 330 | } 331 | 332 | static void k6init_printAppLogoSysInfo(u8 logoColor) { 333 | #define LOGO_HEADER_WIDTH 12 334 | #define LOGO_HEADER_HEIGHT 6 335 | static const u8 k6initLogoData[LOGO_HEADER_WIDTH * LOGO_HEADER_HEIGHT] = { 336 | 0x20, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0xDC, 0x20, 0x20, 337 | 0x20, 0x20, 0xDF, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0x20, 0x20, 338 | 0x20, 0x20, 0x20, 0xDC, 0xDF, 0xDF, 0xDF, 0xDB, 0xDB, 0xDB, 0x20, 0x20, 339 | 0x20, 0xDC, 0xDB, 0xDB, 0x20, 0x20, 0x20, 0xDB, 0xDB, 0xDB, 0x20, 0x20, 340 | 0x20, 0xDB, 0xDB, 0xDB, 0xDC, 0xDC, 0xDC, 0xDB, 0xDB, 0xDB, 0x20, 0x20, 341 | 0x20, 0xDB, 0xDB, 0xDB, 0xDB, 0xDF, 0x20, 0x20, 0xDF, 0xDB, 0x20, 0x20 342 | }; 343 | util_ApplicationLogo logo = { (const char *)k6initLogoData, LOGO_HEADER_WIDTH, LOGO_HEADER_HEIGHT, 0, VGACON_COLOR_BLACK }; 344 | 345 | /* Turbo C won't let me do this assignment in the initialization*/ 346 | logo.fgColor = logoColor; 347 | 348 | /* Print the title / version header */ 349 | util_printWithApplicationLogo(&logo, "%s\n", k6init_versionString); 350 | 351 | /* Print the line with the little twig going down after 5 characters */ 352 | util_printWithApplicationLogo(&logo, ""); 353 | vgacon_fillCharacter('\xC4', 5); 354 | vgacon_fillCharacter('\xC2', 1); 355 | vgacon_fillCharacter('\xC4', 60); 356 | putchar('\n'); 357 | 358 | /* If our CPU is unsupported, print info about it, else the clearname */ 359 | if (s_sysInfo.thisCPU == UNSUPPORTED_CPU) { 360 | util_printWithApplicationLogo(&logo, "CPU \xB3[%s] Type %u Family %u Model %u Stepping %u \n", 361 | s_sysInfo.cpuidString, 362 | s_sysInfo.cpuidInfo.basic.type, 363 | s_sysInfo.cpuidInfo.basic.family, 364 | s_sysInfo.cpuidInfo.basic.model, 365 | s_sysInfo.cpuidInfo.basic.stepping); 366 | } else { 367 | util_printWithApplicationLogo(&logo, "CPU \xB3["); 368 | vgacon_printColorString(k6init_getK6CPUString(s_sysInfo.thisCPU), VGACON_COLOR_LGREN, VGACON_COLOR_BLACK, false); 369 | printf("] L1 Cache: %s", s_sysInfo.L1CacheEnabled ? "ON" : "OFF"); 370 | 371 | if (s_sysInfo.thisCPU == K6_III || s_sysInfo.thisCPU == K6_PLUS) 372 | printf(", L2 Cache: %s", s_sysInfo.L2CacheEnabled ? "ON" : "OFF"); 373 | 374 | printf("\n"); 375 | } 376 | 377 | /* Print RAM info, should be reliable across all platforms we run on... */ 378 | util_printWithApplicationLogo(&logo, "RAM \xB3"); 379 | if (s_sysInfo.memSize > 0) { 380 | printf("%lu KB, 15MB Hole: %s\n", 381 | s_sysInfo.memSize / 1024UL, 382 | s_sysInfo.memHole ? "Yes" : "No"); 383 | } else { 384 | vgacon_printColorString("? (Detection failed!)", VGACON_COLOR_YELLO, VGACON_COLOR_BLACK, true); 385 | printf("\n"); 386 | } 387 | 388 | /* If we found a valid VESA BIOS, print some info about it */ 389 | if (vesa_isValidVesaBios(&s_sysInfo.vesaBiosInfo)) { 390 | util_printWithApplicationLogo(&logo, "VBIOS\xB3[%Fs], VESA %x.%x, %u modes, %lu MB\n", 391 | s_sysInfo.vesaBiosInfo.oemStringPtr ? s_sysInfo.vesaBiosInfo.oemStringPtr : "Unknown", 392 | s_sysInfo.vesaBiosInfo.version.major, 393 | s_sysInfo.vesaBiosInfo.version.minor, 394 | (u16) vesa_getModeCount(&s_sysInfo.vesaBiosInfo), 395 | vesa_getVRAMSize(&s_sysInfo.vesaBiosInfo) >> 20UL); /* /1024/1024 -> size in megabytes */ 396 | } else { 397 | util_printWithApplicationLogo(&logo, "VBIOS\xB3\n"); 398 | } 399 | 400 | /* If the CPU is supported, print MTRR configs, else make clear that it isn't */ 401 | if (s_sysInfo.thisCPU != UNSUPPORTED_CPU) { 402 | util_printWithApplicationLogo(&logo, "MTRR \xB3"); 403 | k6init_printCompactMTRRConfigs(NULL, true); 404 | } else { 405 | util_printWithApplicationLogo(&logo, "MTRR \xB3"); 406 | vgacon_printColorString("< Unsupported CPU detected! >", VGACON_COLOR_LRED, VGACON_COLOR_BLACK, true); 407 | putchar('\n'); 408 | } 409 | 410 | putchar('\n'); 411 | } 412 | 413 | typedef bool (*action)(void); /* Function pointer to action to execute if condition is true */ 414 | static bool k6init_doIfSetupAndPrint(bool condition, action function, const char *fmt, ...) { 415 | if (condition) { 416 | va_list args; 417 | bool success = function(); 418 | 419 | if (success) vgacon_printOK(""); /* To get the header of the line printed */ 420 | else vgacon_printError(""); 421 | 422 | va_start(args, fmt); 423 | vprintf(fmt, args); 424 | printf("\n"); 425 | va_end(args); 426 | 427 | return success; 428 | } 429 | return true; 430 | } 431 | 432 | static bool k6init_doMTRRCfg(void) { 433 | bool success = cpu_K6_setMemoryTypeRanges(&s_params.mtrr.toSet); 434 | k6init_printCompactMTRRConfigs("New MTRR setup: ", true); 435 | return success; 436 | } 437 | 438 | static bool k6init_doWriteAllocCfg(void) { 439 | return cpu_K6_setWriteAllocateRangeValues(s_params.wAlloc.size, s_params.wAlloc.hole); 440 | } 441 | 442 | static bool k6init_doWriteOrderCfg(void) { 443 | return cpu_K6_setWriteOrderMode((cpu_K6_WriteOrderMode) s_params.wOrder.mode); 444 | } 445 | 446 | static bool k6init_doMultiCfg(void) { 447 | cpu_K6_SetMulError errCode; 448 | retPrintErrorIf(s_sysInfo.thisCPU != K6_PLUS, "Multiplier configuration only supported on K6-2+/III+. Skipping...", 0); 449 | errCode = cpu_K6_setMultiplier(s_params.multi.integer, s_params.multi.decimal); 450 | retPrintErrorIf(errCode == SETMUL_BADMUL, "The given multiplier value is invalid and not supported!", 0); 451 | retPrintErrorIf(errCode == SETMUL_ERROR, "There was a system error while setting the multiplier!", 0); 452 | return true; 453 | } 454 | 455 | static bool k6init_doL1Cfg(void) { 456 | return cpu_K6_setL1Cache(s_params.l1Cache.enable); 457 | } 458 | 459 | static bool k6init_doL2Cfg(void) { 460 | bool cpuHasL2 = (s_sysInfo.thisCPU == K6_III || s_sysInfo.thisCPU == K6_PLUS); 461 | retPrintErrorIf(cpuHasL2 == false, "This CPU does not have on-die L2 cache. Skipping...", 0); 462 | return cpu_K6_setL2Cache(s_params.l2Cache.enable); 463 | } 464 | 465 | static bool k6init_doPrefetchCfg(void) { 466 | return cpu_K6_setDataPrefetch(s_params.prefetch.enable); 467 | } 468 | 469 | bool k6init_doPrintBARs(void) { 470 | pci_Device *curDevice = NULL; 471 | pci_DeviceInfo curDeviceInfo; 472 | u32 i; 473 | 474 | retPrintErrorIf(pci_test() == false, "FATAL: Unable to access PCI bus!", 0); 475 | 476 | while (NULL != (curDevice = pci_getNextDevice(curDevice))) { 477 | if (pci_populateDeviceInfo(&curDeviceInfo, *curDevice) == false) { 478 | vgacon_printWarning("Failed to obtain PCI device info...\n"); 479 | continue; 480 | } 481 | 482 | vgacon_printOK("[Device @ %u:%u:%u] ", curDevice->bus, curDevice->slot, curDevice->func); 483 | printf("Vendor 0x%04x Device 0x%04x Class %02x Subclass %02x:\n", 484 | curDeviceInfo.vendor, curDeviceInfo.device, curDeviceInfo.classCode, curDeviceInfo.subClass); 485 | for (i = 0; i < PCI_BARS_MAX; i++) { 486 | if (curDeviceInfo.bars[i].address > 0UL) 487 | vgacon_print(" --> [BAR %lu] @ 0x%08lx (%s) Size %lu KB\n", 488 | i, 489 | curDeviceInfo.bars[i].address, 490 | (curDeviceInfo.bars[i].type == PCI_BAR_MEMORY) ? "Memory" : "I/O", 491 | curDeviceInfo.bars[i].size / 1024UL); 492 | } 493 | } 494 | return true; 495 | } 496 | 497 | static bool k6init_autoSetup(void) { 498 | bool cpuHasL2 = (s_sysInfo.thisCPU == K6_III || s_sysInfo.thisCPU == K6_PLUS); 499 | 500 | s_params.wAlloc.setup = (s_sysInfo.memSize > 0); 501 | s_params.wAlloc.size = s_sysInfo.memSize / 1024UL; 502 | s_params.wAlloc.hole = s_sysInfo.memHole; 503 | 504 | s_params.wOrder.setup = true; 505 | s_params.wOrder.mode = CPU_K6_WRITEORDER_ALL_EXCEPT_UC_WC; 506 | 507 | s_params.l1Cache.setup = true; 508 | s_params.l1Cache.enable = true; 509 | 510 | s_params.l2Cache.setup = cpuHasL2; 511 | s_params.l2Cache.enable = true; 512 | 513 | s_params.prefetch.setup = true; 514 | s_params.prefetch.enable = true; 515 | 516 | retPrintErrorIf(k6init_findAndAddPCIFBsToMTRRConfig() == false, "PCI/AGP FB detection failed! Skipping...", 0); 517 | retPrintErrorIf(k6init_findAndAddLFBsToMTRRConfig() == false, "LFB detection failed! Skipping...", 0); 518 | retPrintErrorIf(s_params.wAlloc.setup == false, "Memory detection failed! Skipping Write Allocate.", 0); 519 | return true; 520 | } 521 | 522 | static const char k6init_appDescription[] = 523 | "http://github.com/oerg866/k6init\n" 524 | "\n" 525 | "K6INIT is a driver for MS-DOS that lets you configure special features of\n" 526 | "AMD K6-2/2+/III/III+ processors, similar to FASTVID on Pentium systems.\n" 527 | "\n" 528 | "It works on Chomper Extended (CXT) K6-2 chips or later.\n" 529 | "In contrast to other tools, K6INIT can be loaded from CONFIG.SYS, so it works\n" 530 | "even with an extended memory manager (such as EMM386) installed.\n" 531 | "\n" 532 | "If called with the /auto parameter, it does the following:\n" 533 | "- Finds linear frame buffer memory and sets up write combining for it\n" 534 | "- Enables Write Allocate for the entire system memory range\n" 535 | "- Enables Write Ordering except for uncacheable / write-combined regions\n" 536 | "\n" 537 | "This can be altered and overridden with many command line parameters.\n" 538 | "\n" 539 | "K6INIT was built using:\n" 540 | "LIB866D DOS Real-Mode Software Development Library\n" 541 | "http://github.com/oerg866/lib866d\n"; 542 | 543 | static const args_arg k6init_args[] = { 544 | ARGS_HEADER(k6init_versionString, k6init_appDescription), 545 | ARGS_USAGE("?", "Prints parameter list"), 546 | 547 | { "status", NULL, "Display current program status.", ARG_FLAG, NULL, NULL }, 548 | 549 | { "auto", NULL, "Fully automated setup (See above.)", ARG_FLAG, &s_params.autoSetup, NULL }, 550 | 551 | { "mtrr", "offset,size,wc,uc","Enable Write Combining for given range", ARG_ARRAY(ARG_U32, 4), s_MTRRCfgQueue, k6init_argAddMTRR }, 552 | ARGS_EXPLAIN("offset: linear offset (e.g. 0xE0000000)"), 553 | ARGS_EXPLAIN("size: length in KILOBYTES (e.g. 8192)"), 554 | ARGS_EXPLAIN("wc: '1': Region is write-combine"), 555 | ARGS_EXPLAIN("uc: '1': Region is uncacheable"), 556 | ARGS_EXPLAIN("NOTE - /mtrr can be be used twice."), 557 | ARGS_EXPLAIN("NOTE - Will discard any MTRRs configured before"), 558 | ARGS_EXPLAIN("running this program."), 559 | 560 | { "lfb", NULL, "Find and enable Write Combine for Linear Frame Buffer",ARG_FLAG, NULL, k6init_argAddLFBMTRR }, 561 | 562 | { "pci", NULL, "Find and enable Write Combine for Frame Buffers", ARG_FLAG, NULL, k6init_argAddPCIMTRR }, 563 | ARGS_EXPLAIN("exposed by PCI/AGP cards (experimental)"), 564 | 565 | { "vga", NULL, "Enables Write Combine for the VGA memory region", ARG_FLAG, NULL, k6init_argAddVGAMTRR }, 566 | ARGS_EXPLAIN("(A0000-BFFFF). WARNING: Potentially unsafe."), 567 | ARGS_EXPLAIN("You MUST NOT use this memory region for UMBs."), 568 | ARGS_EXPLAIN("This parameter is equivalent to /wc:0xA0000,128,1,0"), 569 | 570 | { "nomtrr", NULL, "Disables Memory Type Range Registers completely", ARG_FLAG, NULL, k6init_argClearMTRRs }, 571 | ARGS_EXPLAIN("Clears any MTRRs, including Write-Combine and"), 572 | ARGS_EXPLAIN("Uncacheable regions."), 573 | 574 | { "wa", "size", "Configure Write Allocate", ARG_U32, &s_params.wAlloc.size, k6init_argWriteAllocate }, 575 | ARGS_EXPLAIN("size: Memory size in KB"), 576 | ARGS_EXPLAIN("Set this to 0 to disable Write Allocate completely."), 577 | 578 | { "wahole", NULL, "Force 15-16M Memory Hole Skipping for Write Allocate", ARG_FLAG, &s_params.wAlloc.hole, k6init_argForceWAHole }, 579 | ARGS_EXPLAIN("K6INIT detects the memory hole automatically,"), 580 | ARGS_EXPLAIN("but you can use this parameter to force it."), 581 | 582 | { "wo", "mode", "Configure Write Order Mode", ARG_U8, &s_params.wOrder.mode, k6init_argWriteOrder }, 583 | ARGS_EXPLAIN("mode is a single digit to indicate the mode:"), 584 | ARGS_EXPLAIN("0 - All Memory Regions (Slow)"), 585 | ARGS_EXPLAIN("1 - All except Uncacheable/Write-Combined (Fast)"), 586 | ARGS_EXPLAIN("2 - No Memory Regions (Fastest)"), 587 | 588 | { "multi", "x.y", "Configure CPU Frequency Multiplier", ARG_STRING(3), s_multiToParse, k6init_argAddMulti }, 589 | ARGS_EXPLAIN("x: integral part of multiplier"), 590 | ARGS_EXPLAIN("y: fractional part of multiplier"), 591 | ARGS_EXPLAIN("IMPORTANT: Requires K6-2+ or K6-III+ CPU!"), 592 | ARGS_EXPLAIN("Example: /multi:5.5"), 593 | 594 | { "l1", "1/0", "Enable/Disable Level 1 cache", ARG_BOOL, &s_params.l1Cache.enable, k6init_argAddL1 }, 595 | { "l2", "1/0", "Enable/Disable Level 2 cache", ARG_BOOL, &s_params.l2Cache.enable, k6init_argAddL2 }, 596 | ARGS_EXPLAIN("NOTE: Only K6-2+ and K6-III+ have on-die L2 Cache!"), 597 | { "prefetch", "1/0", "Enable/Disable Data Prefetch", ARG_BOOL, &s_params.prefetch.enable, k6init_argAddPrefetch }, 598 | 599 | { "listbars", NULL, "List all PCI/AGP device Base Address Regions (BARs)", ARG_FLAG, &s_params.printBARs, NULL }, 600 | }; 601 | 602 | int main(int argc, char *argv[]) { 603 | const char *writeOrderModeStrings[] = { "0, All Memory Regions", 604 | "1, All except Uncacheable/Write-Combined", 605 | "2, No Memory Regions" }; 606 | args_ParseError argErr; 607 | u8 logoColor = VGACON_COLOR_GREEN; 608 | bool ok = true; 609 | 610 | 611 | /* Privileged instructions cause GPFs on WINDOWS, so we exit. */ 612 | if (sys_getWindowsMode() != OS_PURE_DOS) { 613 | vgacon_printError("K6INIT cannot run on Windows.\n"); 614 | return -1; 615 | } 616 | 617 | k6init_populateSysInfo(); 618 | 619 | memset(&s_params, 0, sizeof(s_params)); 620 | argErr = args_parseAllArgs(argc, (const char **) argv, k6init_args, ARRAY_SIZE(k6init_args)); 621 | 622 | if (argErr == ARGS_USAGE_PRINTED) { return 0; } 623 | 624 | if (s_sysInfo.criticalError == true) { logoColor = VGACON_COLOR_RED; } 625 | else if (s_sysInfo.thisCPU == UNSUPPORTED_CPU) { logoColor = VGACON_COLOR_LRED; } 626 | else if (argErr == ARGS_NO_ARGUMENTS) { logoColor = VGACON_COLOR_YELLO; } 627 | else if (argErr != ARGS_SUCCESS) { logoColor = VGACON_COLOR_BROWN; } 628 | 629 | k6init_printAppLogoSysInfo(logoColor); 630 | 631 | if (s_sysInfo.thisCPU == UNSUPPORTED_CPU) { 632 | putchar(' '); 633 | vgacon_printColorString("Please run this program on an AMD-K6-2 CXT/K6-2+/K6-III/K6-III+!", VGACON_COLOR_LRED, VGACON_COLOR_BLACK, true); 634 | printf("\n"); 635 | return -1; 636 | } else if (argErr == ARGS_NO_ARGUMENTS) { 637 | vgacon_printWarning("No arguments given. Use /help for more information.\n"); 638 | return 1; 639 | } else if (argErr != ARGS_SUCCESS) { 640 | vgacon_printError("User input error, quitting...\n"); 641 | return (int) argErr; 642 | } 643 | 644 | /* Do actual execution of requested actions */ 645 | ok &= k6init_doIfSetupAndPrint(s_params.printBARs, k6init_doPrintBARs, "Print PCI/AGP device BARs"); 646 | ok &= k6init_doIfSetupAndPrint(s_params.autoSetup, k6init_autoSetup, "Preparing automatic configuration"); 647 | ok &= k6init_doIfSetupAndPrint(s_params.mtrr.setup, k6init_doMTRRCfg, "Set MTRR Config"); 648 | ok &= k6init_doIfSetupAndPrint(s_params.wAlloc.setup, k6init_doWriteAllocCfg, "Set Write Allocate Config (%lu KB)", 649 | s_params.wAlloc.size); 650 | ok &= k6init_doIfSetupAndPrint(s_params.wOrder.setup, k6init_doWriteOrderCfg, "Set Write Order Mode (%s)", 651 | writeOrderModeStrings[(u16)s_params.wOrder.mode]); 652 | ok &= k6init_doIfSetupAndPrint(s_params.multi.setup, k6init_doMultiCfg, "Set Frequency Multiplier (%sx)", 653 | s_multiToParse); 654 | ok &= k6init_doIfSetupAndPrint(s_params.l1Cache.setup, k6init_doL1Cfg, "Set L1 Cache (%s)", 655 | s_params.l1Cache.enable ? "On" : "Off"); 656 | ok &= k6init_doIfSetupAndPrint(s_params.l2Cache.setup, k6init_doL2Cfg, "Set L2 Cache (%s)", 657 | s_params.l2Cache.enable ? "On" : "Off"); 658 | ok &= k6init_doIfSetupAndPrint(s_params.prefetch.setup, k6init_doPrefetchCfg, "Set Data Prefetch (%s)", 659 | s_params.prefetch.enable ? "On" : "Off"); 660 | if (!ok) 661 | vgacon_printWarning("Summary: Some actions failed!\n"); 662 | 663 | return (ok == true) ? 0 : -1; 664 | } 665 | -------------------------------------------------------------------------------- /MAKEFILE: -------------------------------------------------------------------------------- 1 | # Microsoft C/C++ 7.00 Makefile for K6INIT 2 | 3 | CC = cl 4 | LINK = link 5 | CFLAGS = /c /Ox /WX /nologo /ILIB866D 6 | DEBUG = 0 7 | 8 | !IF $(DEBUG) 9 | CFLAGS = /DDEBUG $(CFLAGS) 10 | !ENDIF 11 | 12 | 13 | TARGETS : K6INIT.EXE 14 | 15 | clean: 16 | del *.obj 17 | del *.exe 18 | 19 | OBJ = LIB866D\*.OBJ K6INIT.OBJ 20 | 21 | # Link with DRIVER.ASM, CRTDRVR.LIB and CRTKEEPC.LIB 22 | 23 | K6INIT.EXE : clean $(OBJ) 24 | $(LINK) driver+crtdrvr.lib+crtkeepc.lib+ARGS+CPU_K6+UTIL+VESABIOS+VGACON+SYS+PCI+K6INIT,K6INIT.EXE; 25 | 26 | .c.obj: 27 | $(CC) $(CFLAGS) $< 28 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # K6INIT 2 | 3 | (C) 2021 - 2024, Eric Voirin (oerg866) 4 | 5 | ![image](screenshots/k6init_status.png) 6 | ![image](screenshots/k6init_auto.png) 7 | ![image](screenshots/k6init_multi.png) 8 | ![image](screenshots/k6init_bars.png) 9 | 10 | --- 11 | 12 | **K6INIT** is a driver for MS-DOS that lets you configure special features of AMD K6-2/2+/3/3+ processors, replacing tools like `k6dos.sys` and `setk6.exe`, and is similar to FASTVID on Pentium systems. 13 | 14 | While **K6INIT** can run completely autonomously, it supports manual, detailed control over **Memory Type Range Registers** (including Write-Combine and Cachability modes), **Write Allocate**, **Write Ordering**, **CPU Cache** and **Frequency Multiplier**. 15 | 16 | In contrast to other tools, **K6INIT** can be loaded from `CONFIG.SYS`, so it works 17 | even with an extended memory manager (such as `EMM386`) installed. 18 | 19 | If called with the `/auto` parameter, **K6INIT** does the following: 20 | 21 | - *Write Ordering mode* to **1 (All except UC/WC)** 22 | - *Write Allocate* for **all system memory** (auto detected) 23 | - *Write Combining* for **Linear Frame Buffer(s) exposed by PCI/AGP graphics cards and VESA BIOS** 24 | (auto detected) 25 | - *L1 Cache* to **Enabled** 26 | - *L2 Cache* to **Enabled** (supported CPUs only!) 27 | - *Data Prefetch* to **Enabled** 28 | 29 | This can be altered and overridden with many command line parameters. 30 | 31 | **K6INIT** runs on Chomper Extended (CXT) K6-2 chips or later. 32 | 33 | **K6INIT** was built using the [LIB866D DOS Real-Mode Software Development Library](https://github.com/oerg866/lib866d) 34 | 35 | ## Features 36 | 37 | - [x] Detect CPU type automatically 38 | - [x] Detect total available system memory (Using E820 and E801 methods) 39 | - [x] Detect 15-16M Memory hole automatically 40 | - [x] Give precise control over **Memory Type Range Registers (MTRRs)** including **Write-Combine** and **Uncacheable** modes. 41 | - [x] Set MTRR to enable Write combining for PCI/AGP BAR Frame Buffers automatically 42 | - [x] Set MTRR to enable Write combining for Linear Frame Buffers (LFBs) automatically (requires graphics card with VESA BIOS extensions) 43 | - [x] Set Write allocate for system memory 44 | - [x] Set Write Order mode 45 | - [x] Set Frequency Multiplier (K6-2+/III+ only) 46 | - [X] Enable/Disable L1 Cache 47 | - [X] Enable/Disable L2 Cache (K6-2+/K6-III/K6-III+ only) 48 | - [x] Enable/Disable Data Prefetch 49 | - [x] List all PCI/AGP device Base Address Regions (BARs) 50 | 51 | ## Supported Processors 52 | 53 | | CPU Type | Family | Model | Stepping | 54 | |-------------------------|--------|-------|----------| 55 | | AMD K6-2 (CXT Core) | 5 | 8 | C | 56 | | AMD K6-III | 5 | 9 | *Any* | 57 | | AMD K6-2+ / AMD K6-III+ | 5 | D | *Any* | 58 | 59 | ## System Requirements 60 | 61 | * Supported AMD K6 family CPU (see above) 62 | * Microsoft MS-DOS 5.0 (or compatible) or higher 63 | * [X] Microsoft Windows 95/98 support 64 | * [X] FreeDOS support 65 | * Other systems such as DR-DOS untested, but should work. 66 | 67 | # Running the Driver 68 | 69 | Usage (config.sys): 70 | `DEVICE=K6INIT.EXE ` 71 | 72 | Usage (command line): 73 | `K6INIT.EXE ` 74 | 75 | All parameters are case-inensitive. Parameters other than `/auto` should only be used by knowledgeable users. 76 | 77 | ## Command Line Parameters 78 | 79 | K6INIT offers several command-line options to configure and manage memory settings, CPU features, and other system parameters. Below is a detailed explanation of each parameter. 80 | 81 | ### `/?` 82 | **Description:** Prints this list of parameters. 83 | 84 | --- 85 | ### `/status` 86 | **Description:** Displays the current program status. 87 | 88 | --- 89 | ### `/auto` 90 | **Description:** Fully automated setup. 91 | 92 | --- 93 | ### `/mtrr:offset,size,wc,uc` 94 | **Description:** Enables Write Combining for a specific memory range. 95 | **Parameters:** 96 | - `offset`: Linear offset (e.g., `0xE0000000`) 97 | - `size`: Length in kilobytes (e.g., `8192`) 98 | - `wc`: Write-combine flag (`1` to enable, `0` to disable) 99 | - `uc`: Uncacheable flag (`1` to enable, `0` to disable) 100 | 101 | **Notes:** 102 | - The `/mtrr` option can be used twice. 103 | - Discards any MTRRs configured before running the program. 104 | 105 | --- 106 | ### `/lfb` 107 | **Description:** Automatically finds and enables Write Combining for the Linear Frame Buffers (LFB). 108 | 109 | --- 110 | ### `/pci` 111 | **Description:** Automatically finds and enables Write Combining for Frame Buffers exposed by PCI / AGP graphics cards (experimental). 112 | 113 | --- 114 | ### `/vga` 115 | **Description:** Enables Write Combining for the VGA memory region (`A0000-BFFFF`). 116 | 117 | **Notes:** 118 | - **Warning:** This option is potentially unsafe. Do not use this memory region for Upper Memory Blocks (UMBs). 119 | - Equivalent to: `/wc:0xA0000,128,1,0` 120 | 121 | --- 122 | ### `/nomtrr` 123 | **Description:** Disables Memory Type Range Registers (MTRRs) entirely. 124 | 125 | **Notes:** 126 | - Clears any existing MTRRs, including Write-Combined and Uncacheable regions. 127 | 128 | --- 129 | ### `/wa:size` 130 | **Description:** Configures Write Allocate (WA) settings. 131 | 132 | **Arguments:** 133 | - `size`: Memory size in kilobytes. 134 | 135 | **Notes:** 136 | - Set this to `0` to disable Write Allocate. 137 | 138 | --- 139 | ### `/wahole` 140 | **Description:** Forces 15-16 MB memory hole skipping for Write Allocate. 141 | 142 | **Notes:** 143 | - K6INIT detects the memory hole automatically, but this option can be used to force it. 144 | 145 | --- 146 | ### `/wo:mode` 147 | **Description:** Configures the Write Order Mode. 148 | 149 | **Arguments:** 150 | - `mode`: A single digit representing the desired mode. 151 | - `0`: All memory regions (Slow) 152 | - `1`: All except uncacheable or write-combined regions (Fast) 153 | - `2`: No memory regions (Fastest) 154 | 155 | --- 156 | ### `/multi:x.y` 157 | **Description:** Configures the CPU frequency multiplier. 158 | 159 | **Arguments:** 160 | - `x`: Integral part of the multiplier. 161 | - `y`: Fractional part of the multiplier. 162 | 163 | **Notes:** 164 | - Requires a K6-2+ or K6-III+ CPU. 165 | - Example usage: `/multi:5.5` 166 | 167 | --- 168 | ### `/l1:1/0` 169 | **Description:** Enables (`1`) or disables (`0`) the Level 1 cache. 170 | 171 | --- 172 | ### `/l2:1/0` 173 | **Description:** Enables (`1`) or disables (`0`) the Level 2 cache. 174 | 175 | **Notes:** 176 | - Only K6-2+ and K6-III+ CPUs have an on-die L2 cache. 177 | 178 | --- 179 | ### `/prefetch:1/0` 180 | **Description:** Enables (`1`) or disables (`0`) Data Prefetching (DPE) 181 | 182 | --- 183 | ### `/listbars` 184 | **Description:** Lists all Base Address Regions (BARs) exposed by PCI/AGP devices in the system. 185 | 186 | --- 187 | 188 | 189 | # Building **K6INIT** 190 | 191 | ## Required Build Environment 192 | 193 | * MS-DOS 6.xx or 7.xx or Windows 95/98 194 | * Microsoft C / C++ Compiler Version 7.00 195 | * latest patch set required 196 | * Also works with Microsoft Visual C++ 1.52. This is not recommended because it is not really meant for pure DOS development. 197 | 198 | In this case you need a 32-Bit DOS Extender such as HX-DOS. The DOSXNT that is included doesn't play nice with my machine sadly. 199 | * `LIB` and `INCLUDE` directories from the **DOS Internals** disk bundled with *Geoff Chappell's* excellent book of the same name 200 | Can be acquired here: https://www.pcjs.org/software/pcx86/sw/books/dos_internals/ 201 | 202 | I have requested permission from *Geoff Chappell* to bundle these files with the **K6INIT** repository, but have not yet received a response. 203 | * Updates for the above libraries from *Geoff Chappell's* website: https://www.geoffchappell.com/notes/dos/internals/crtdrvr/update.htm?ta=8.714286804199219&tx=6 204 | * DPMI host (not necessary on Windows) 205 | * I use HXDPMI32 ([part of HXDOS by Japheth](https://www.japheth.de/HX.html)). 206 | 207 | *Note: Previous versions required the Microsoft Macro Assembler to build. As LIB866D includes macros that allow the usage of unsupported opcodes in inline assembly, this is no longer the case.* 208 | 209 | ## Building 210 | 211 | ``` 212 | cd \k6init 213 | nmake 214 | ``` 215 | 216 | That's all. 217 | 218 | ### Debug build 219 | 220 | To make a build with a lot of verbose debug output, build it with `DEBUG=1`: 221 | 222 | ``` 223 | nmake DEBUG=1 224 | ``` 225 | 226 | ### Borland and Watcom Compiler support 227 | 228 | While **Borland C/C++ 3.x**, **Borland Turbo C/C++ 3.0** and **OpenWatcom v2** are technically supported, the resulting executable will not be loadable in `CONFIG.SYS`. Use the following commands to compile them: 229 | 230 | #### Borland Turbo C/C++: 231 | 232 | `tcc -wall -g1 -Ilib866d -ek6init.exe lib866d\*.c k6init.c` 233 | 234 | #### Borland C/C++: 235 | `bcc -wall -g1 -Ilib866d -ek6init.exe lib866d\*.c k6init.c` 236 | 237 | #### OpenWatcom: 238 | `wcl -wcd111 -w9 -bt=dos -Ilib866d lib866d\*.c k6init.c` 239 | 240 | ## Build environment issues 241 | 242 | I developed this on an AMD K6-II CXT 500MHz. DOS is not the most stable and easy to configure environment in the world and there are a few quirks to address. 243 | 244 | ### Weird errors when building 245 | 246 | **USE HIMEM.SYS THAT COMES WITH MICROSOFT C/C++ 7.00!** 247 | 248 | You'll get weird errors otherwise. It's something to do with XMS size. I can get this to compile with JemmEx when limiting its reported size to 32MiB. 249 | 250 | QEMM '97 also works, but after a while I got really strange behavior. I cannot open K6init.h (and only that file) properly via network share anymore. 251 | 252 | ### Linker doesn't run when DPMI host is running 253 | 254 | I couldn't really fix this, so I took the linker (`LINK.EXE` and `CVPACK.EXE`) from Microsoft Visual C++ 1.52. **NOTE:** The linker from VC1.52 requires a 32-Bit DOS Extender. 255 | VC1.52 includes one in the form of `DOSXNT.EXE` 256 | 257 | ### CodeView doesn't run when DPMI host is running 258 | 259 | No idea. I don't use the debugger (yet) so at the moment it is not a big deal for me but it would be cool to fix this...? 260 | 261 | ### Why don't you just use 386-MAX as suggested by Microsoft? 262 | 263 | Because when I load it, it reboots my computer. %-) 264 | 265 | # License 266 | 267 | [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 (CC BY-NC-SA 4.0)](https://creativecommons.org/licenses/by-nc/4.0/deed.en) 268 | -------------------------------------------------------------------------------- /screenshots/k6init_auto.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oerg866/k6init/6ec2a5b626b0b9842cafe426c9d227d9dec0ec12/screenshots/k6init_auto.png -------------------------------------------------------------------------------- /screenshots/k6init_bars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oerg866/k6init/6ec2a5b626b0b9842cafe426c9d227d9dec0ec12/screenshots/k6init_bars.png -------------------------------------------------------------------------------- /screenshots/k6init_multi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oerg866/k6init/6ec2a5b626b0b9842cafe426c9d227d9dec0ec12/screenshots/k6init_multi.png -------------------------------------------------------------------------------- /screenshots/k6init_status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oerg866/k6init/6ec2a5b626b0b9842cafe426c9d227d9dec0ec12/screenshots/k6init_status.png --------------------------------------------------------------------------------