├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── busybox-config ├── doslinux.asm ├── init ├── init.c ├── kbd.c ├── kbd.h ├── panic.c ├── panic.h ├── term.c ├── term.h ├── vm86.c └── vm86.h ├── linux-config-doslinux ├── mtoolsrc └── script ├── build-busybox ├── build-linux └── build-prereq /.gitignore: -------------------------------------------------------------------------------- 1 | dosemu-* 2 | busybox-* 3 | linux-* 4 | 5 | *.o 6 | *.img 7 | *.tgz 8 | *.com 9 | 10 | init/init 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DOS Subsystem for Linux 2 | Copyright (C) 2020 Hailey Somerville 3 | 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU Affero 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 Affero General Public License for more details. 13 | 14 | You should have received a copy of the GNU Affero General Public License 15 | along with this program. If not, see . 16 | 17 | - 18 | 19 | GNU AFFERO GENERAL PUBLIC LICENSE 20 | Version 3, 19 November 2007 21 | 22 | Copyright (C) 2007 Free Software Foundation, Inc. 23 | Everyone is permitted to copy and distribute verbatim copies 24 | of this license document, but changing it is not allowed. 25 | 26 | Preamble 27 | 28 | The GNU Affero General Public License is a free, copyleft license for 29 | software and other kinds of works, specifically designed to ensure 30 | cooperation with the community in the case of network server software. 31 | 32 | The licenses for most software and other practical works are designed 33 | to take away your freedom to share and change the works. By contrast, 34 | our General Public Licenses are intended to guarantee your freedom to 35 | share and change all versions of a program--to make sure it remains free 36 | software for all its users. 37 | 38 | When we speak of free software, we are referring to freedom, not 39 | price. Our General Public Licenses are designed to make sure that you 40 | have the freedom to distribute copies of free software (and charge for 41 | them if you wish), that you receive source code or can get it if you 42 | want it, that you can change the software or use pieces of it in new 43 | free programs, and that you know you can do these things. 44 | 45 | Developers that use our General Public Licenses protect your rights 46 | with two steps: (1) assert copyright on the software, and (2) offer 47 | you this License which gives you legal permission to copy, distribute 48 | and/or modify the software. 49 | 50 | A secondary benefit of defending all users' freedom is that 51 | improvements made in alternate versions of the program, if they 52 | receive widespread use, become available for other developers to 53 | incorporate. Many developers of free software are heartened and 54 | encouraged by the resulting cooperation. However, in the case of 55 | software used on network servers, this result may fail to come about. 56 | The GNU General Public License permits making a modified version and 57 | letting the public access it on a server without ever releasing its 58 | source code to the public. 59 | 60 | The GNU Affero General Public License is designed specifically to 61 | ensure that, in such cases, the modified source code becomes available 62 | to the community. It requires the operator of a network server to 63 | provide the source code of the modified version running there to the 64 | users of that server. Therefore, public use of a modified version, on 65 | a publicly accessible server, gives the public access to the source 66 | code of the modified version. 67 | 68 | An older license, called the Affero General Public License and 69 | published by Affero, was designed to accomplish similar goals. This is 70 | a different license, not a version of the Affero GPL, but Affero has 71 | released a new version of the Affero GPL which permits relicensing under 72 | this license. 73 | 74 | The precise terms and conditions for copying, distribution and 75 | modification follow. 76 | 77 | TERMS AND CONDITIONS 78 | 79 | 0. Definitions. 80 | 81 | "This License" refers to version 3 of the GNU Affero General Public License. 82 | 83 | "Copyright" also means copyright-like laws that apply to other kinds of 84 | works, such as semiconductor masks. 85 | 86 | "The Program" refers to any copyrightable work licensed under this 87 | License. Each licensee is addressed as "you". "Licensees" and 88 | "recipients" may be individuals or organizations. 89 | 90 | To "modify" a work means to copy from or adapt all or part of the work 91 | in a fashion requiring copyright permission, other than the making of an 92 | exact copy. The resulting work is called a "modified version" of the 93 | earlier work or a work "based on" the earlier work. 94 | 95 | A "covered work" means either the unmodified Program or a work based 96 | on the Program. 97 | 98 | To "propagate" a work means to do anything with it that, without 99 | permission, would make you directly or secondarily liable for 100 | infringement under applicable copyright law, except executing it on a 101 | computer or modifying a private copy. Propagation includes copying, 102 | distribution (with or without modification), making available to the 103 | public, and in some countries other activities as well. 104 | 105 | To "convey" a work means any kind of propagation that enables other 106 | parties to make or receive copies. Mere interaction with a user through 107 | a computer network, with no transfer of a copy, is not conveying. 108 | 109 | An interactive user interface displays "Appropriate Legal Notices" 110 | to the extent that it includes a convenient and prominently visible 111 | feature that (1) displays an appropriate copyright notice, and (2) 112 | tells the user that there is no warranty for the work (except to the 113 | extent that warranties are provided), that licensees may convey the 114 | work under this License, and how to view a copy of this License. If 115 | the interface presents a list of user commands or options, such as a 116 | menu, a prominent item in the list meets this criterion. 117 | 118 | 1. Source Code. 119 | 120 | The "source code" for a work means the preferred form of the work 121 | for making modifications to it. "Object code" means any non-source 122 | form of a work. 123 | 124 | A "Standard Interface" means an interface that either is an official 125 | standard defined by a recognized standards body, or, in the case of 126 | interfaces specified for a particular programming language, one that 127 | is widely used among developers working in that language. 128 | 129 | The "System Libraries" of an executable work include anything, other 130 | than the work as a whole, that (a) is included in the normal form of 131 | packaging a Major Component, but which is not part of that Major 132 | Component, and (b) serves only to enable use of the work with that 133 | Major Component, or to implement a Standard Interface for which an 134 | implementation is available to the public in source code form. A 135 | "Major Component", in this context, means a major essential component 136 | (kernel, window system, and so on) of the specific operating system 137 | (if any) on which the executable work runs, or a compiler used to 138 | produce the work, or an object code interpreter used to run it. 139 | 140 | The "Corresponding Source" for a work in object code form means all 141 | the source code needed to generate, install, and (for an executable 142 | work) run the object code and to modify the work, including scripts to 143 | control those activities. However, it does not include the work's 144 | System Libraries, or general-purpose tools or generally available free 145 | programs which are used unmodified in performing those activities but 146 | which are not part of the work. For example, Corresponding Source 147 | includes interface definition files associated with source files for 148 | the work, and the source code for shared libraries and dynamically 149 | linked subprograms that the work is specifically designed to require, 150 | such as by intimate data communication or control flow between those 151 | subprograms and other parts of the work. 152 | 153 | The Corresponding Source need not include anything that users 154 | can regenerate automatically from other parts of the Corresponding 155 | Source. 156 | 157 | The Corresponding Source for a work in source code form is that 158 | same work. 159 | 160 | 2. Basic Permissions. 161 | 162 | All rights granted under this License are granted for the term of 163 | copyright on the Program, and are irrevocable provided the stated 164 | conditions are met. This License explicitly affirms your unlimited 165 | permission to run the unmodified Program. The output from running a 166 | covered work is covered by this License only if the output, given its 167 | content, constitutes a covered work. This License acknowledges your 168 | rights of fair use or other equivalent, as provided by copyright law. 169 | 170 | You may make, run and propagate covered works that you do not 171 | convey, without conditions so long as your license otherwise remains 172 | in force. You may convey covered works to others for the sole purpose 173 | of having them make modifications exclusively for you, or provide you 174 | with facilities for running those works, provided that you comply with 175 | the terms of this License in conveying all material for which you do 176 | not control copyright. Those thus making or running the covered works 177 | for you must do so exclusively on your behalf, under your direction 178 | and control, on terms that prohibit them from making any copies of 179 | your copyrighted material outside their relationship with you. 180 | 181 | Conveying under any other circumstances is permitted solely under 182 | the conditions stated below. Sublicensing is not allowed; section 10 183 | makes it unnecessary. 184 | 185 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 186 | 187 | No covered work shall be deemed part of an effective technological 188 | measure under any applicable law fulfilling obligations under article 189 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 190 | similar laws prohibiting or restricting circumvention of such 191 | measures. 192 | 193 | When you convey a covered work, you waive any legal power to forbid 194 | circumvention of technological measures to the extent such circumvention 195 | is effected by exercising rights under this License with respect to 196 | the covered work, and you disclaim any intention to limit operation or 197 | modification of the work as a means of enforcing, against the work's 198 | users, your or third parties' legal rights to forbid circumvention of 199 | technological measures. 200 | 201 | 4. Conveying Verbatim Copies. 202 | 203 | You may convey verbatim copies of the Program's source code as you 204 | receive it, in any medium, provided that you conspicuously and 205 | appropriately publish on each copy an appropriate copyright notice; 206 | keep intact all notices stating that this License and any 207 | non-permissive terms added in accord with section 7 apply to the code; 208 | keep intact all notices of the absence of any warranty; and give all 209 | recipients a copy of this License along with the Program. 210 | 211 | You may charge any price or no price for each copy that you convey, 212 | and you may offer support or warranty protection for a fee. 213 | 214 | 5. Conveying Modified Source Versions. 215 | 216 | You may convey a work based on the Program, or the modifications to 217 | produce it from the Program, in the form of source code under the 218 | terms of section 4, provided that you also meet all of these conditions: 219 | 220 | a) The work must carry prominent notices stating that you modified 221 | it, and giving a relevant date. 222 | 223 | b) The work must carry prominent notices stating that it is 224 | released under this License and any conditions added under section 225 | 7. This requirement modifies the requirement in section 4 to 226 | "keep intact all notices". 227 | 228 | c) You must license the entire work, as a whole, under this 229 | License to anyone who comes into possession of a copy. This 230 | License will therefore apply, along with any applicable section 7 231 | additional terms, to the whole of the work, and all its parts, 232 | regardless of how they are packaged. This License gives no 233 | permission to license the work in any other way, but it does not 234 | invalidate such permission if you have separately received it. 235 | 236 | d) If the work has interactive user interfaces, each must display 237 | Appropriate Legal Notices; however, if the Program has interactive 238 | interfaces that do not display Appropriate Legal Notices, your 239 | work need not make them do so. 240 | 241 | A compilation of a covered work with other separate and independent 242 | works, which are not by their nature extensions of the covered work, 243 | and which are not combined with it such as to form a larger program, 244 | in or on a volume of a storage or distribution medium, is called an 245 | "aggregate" if the compilation and its resulting copyright are not 246 | used to limit the access or legal rights of the compilation's users 247 | beyond what the individual works permit. Inclusion of a covered work 248 | in an aggregate does not cause this License to apply to the other 249 | parts of the aggregate. 250 | 251 | 6. Conveying Non-Source Forms. 252 | 253 | You may convey a covered work in object code form under the terms 254 | of sections 4 and 5, provided that you also convey the 255 | machine-readable Corresponding Source under the terms of this License, 256 | in one of these ways: 257 | 258 | a) Convey the object code in, or embodied in, a physical product 259 | (including a physical distribution medium), accompanied by the 260 | Corresponding Source fixed on a durable physical medium 261 | customarily used for software interchange. 262 | 263 | b) Convey the object code in, or embodied in, a physical product 264 | (including a physical distribution medium), accompanied by a 265 | written offer, valid for at least three years and valid for as 266 | long as you offer spare parts or customer support for that product 267 | model, to give anyone who possesses the object code either (1) a 268 | copy of the Corresponding Source for all the software in the 269 | product that is covered by this License, on a durable physical 270 | medium customarily used for software interchange, for a price no 271 | more than your reasonable cost of physically performing this 272 | conveying of source, or (2) access to copy the 273 | Corresponding Source from a network server at no charge. 274 | 275 | c) Convey individual copies of the object code with a copy of the 276 | written offer to provide the Corresponding Source. This 277 | alternative is allowed only occasionally and noncommercially, and 278 | only if you received the object code with such an offer, in accord 279 | with subsection 6b. 280 | 281 | d) Convey the object code by offering access from a designated 282 | place (gratis or for a charge), and offer equivalent access to the 283 | Corresponding Source in the same way through the same place at no 284 | further charge. You need not require recipients to copy the 285 | Corresponding Source along with the object code. If the place to 286 | copy the object code is a network server, the Corresponding Source 287 | may be on a different server (operated by you or a third party) 288 | that supports equivalent copying facilities, provided you maintain 289 | clear directions next to the object code saying where to find the 290 | Corresponding Source. Regardless of what server hosts the 291 | Corresponding Source, you remain obligated to ensure that it is 292 | available for as long as needed to satisfy these requirements. 293 | 294 | e) Convey the object code using peer-to-peer transmission, provided 295 | you inform other peers where the object code and Corresponding 296 | Source of the work are being offered to the general public at no 297 | charge under subsection 6d. 298 | 299 | A separable portion of the object code, whose source code is excluded 300 | from the Corresponding Source as a System Library, need not be 301 | included in conveying the object code work. 302 | 303 | A "User Product" is either (1) a "consumer product", which means any 304 | tangible personal property which is normally used for personal, family, 305 | or household purposes, or (2) anything designed or sold for incorporation 306 | into a dwelling. In determining whether a product is a consumer product, 307 | doubtful cases shall be resolved in favor of coverage. For a particular 308 | product received by a particular user, "normally used" refers to a 309 | typical or common use of that class of product, regardless of the status 310 | of the particular user or of the way in which the particular user 311 | actually uses, or expects or is expected to use, the product. A product 312 | is a consumer product regardless of whether the product has substantial 313 | commercial, industrial or non-consumer uses, unless such uses represent 314 | the only significant mode of use of the product. 315 | 316 | "Installation Information" for a User Product means any methods, 317 | procedures, authorization keys, or other information required to install 318 | and execute modified versions of a covered work in that User Product from 319 | a modified version of its Corresponding Source. The information must 320 | suffice to ensure that the continued functioning of the modified object 321 | code is in no case prevented or interfered with solely because 322 | modification has been made. 323 | 324 | If you convey an object code work under this section in, or with, or 325 | specifically for use in, a User Product, and the conveying occurs as 326 | part of a transaction in which the right of possession and use of the 327 | User Product is transferred to the recipient in perpetuity or for a 328 | fixed term (regardless of how the transaction is characterized), the 329 | Corresponding Source conveyed under this section must be accompanied 330 | by the Installation Information. But this requirement does not apply 331 | if neither you nor any third party retains the ability to install 332 | modified object code on the User Product (for example, the work has 333 | been installed in ROM). 334 | 335 | The requirement to provide Installation Information does not include a 336 | requirement to continue to provide support service, warranty, or updates 337 | for a work that has been modified or installed by the recipient, or for 338 | the User Product in which it has been modified or installed. Access to a 339 | network may be denied when the modification itself materially and 340 | adversely affects the operation of the network or violates the rules and 341 | protocols for communication across the network. 342 | 343 | Corresponding Source conveyed, and Installation Information provided, 344 | in accord with this section must be in a format that is publicly 345 | documented (and with an implementation available to the public in 346 | source code form), and must require no special password or key for 347 | unpacking, reading or copying. 348 | 349 | 7. Additional Terms. 350 | 351 | "Additional permissions" are terms that supplement the terms of this 352 | License by making exceptions from one or more of its conditions. 353 | Additional permissions that are applicable to the entire Program shall 354 | be treated as though they were included in this License, to the extent 355 | that they are valid under applicable law. If additional permissions 356 | apply only to part of the Program, that part may be used separately 357 | under those permissions, but the entire Program remains governed by 358 | this License without regard to the additional permissions. 359 | 360 | When you convey a copy of a covered work, you may at your option 361 | remove any additional permissions from that copy, or from any part of 362 | it. (Additional permissions may be written to require their own 363 | removal in certain cases when you modify the work.) You may place 364 | additional permissions on material, added by you to a covered work, 365 | for which you have or can give appropriate copyright permission. 366 | 367 | Notwithstanding any other provision of this License, for material you 368 | add to a covered work, you may (if authorized by the copyright holders of 369 | that material) supplement the terms of this License with terms: 370 | 371 | a) Disclaiming warranty or limiting liability differently from the 372 | terms of sections 15 and 16 of this License; or 373 | 374 | b) Requiring preservation of specified reasonable legal notices or 375 | author attributions in that material or in the Appropriate Legal 376 | Notices displayed by works containing it; or 377 | 378 | c) Prohibiting misrepresentation of the origin of that material, or 379 | requiring that modified versions of such material be marked in 380 | reasonable ways as different from the original version; or 381 | 382 | d) Limiting the use for publicity purposes of names of licensors or 383 | authors of the material; or 384 | 385 | e) Declining to grant rights under trademark law for use of some 386 | trade names, trademarks, or service marks; or 387 | 388 | f) Requiring indemnification of licensors and authors of that 389 | material by anyone who conveys the material (or modified versions of 390 | it) with contractual assumptions of liability to the recipient, for 391 | any liability that these contractual assumptions directly impose on 392 | those licensors and authors. 393 | 394 | All other non-permissive additional terms are considered "further 395 | restrictions" within the meaning of section 10. If the Program as you 396 | received it, or any part of it, contains a notice stating that it is 397 | governed by this License along with a term that is a further 398 | restriction, you may remove that term. If a license document contains 399 | a further restriction but permits relicensing or conveying under this 400 | License, you may add to a covered work material governed by the terms 401 | of that license document, provided that the further restriction does 402 | not survive such relicensing or conveying. 403 | 404 | If you add terms to a covered work in accord with this section, you 405 | must place, in the relevant source files, a statement of the 406 | additional terms that apply to those files, or a notice indicating 407 | where to find the applicable terms. 408 | 409 | Additional terms, permissive or non-permissive, may be stated in the 410 | form of a separately written license, or stated as exceptions; 411 | the above requirements apply either way. 412 | 413 | 8. Termination. 414 | 415 | You may not propagate or modify a covered work except as expressly 416 | provided under this License. Any attempt otherwise to propagate or 417 | modify it is void, and will automatically terminate your rights under 418 | this License (including any patent licenses granted under the third 419 | paragraph of section 11). 420 | 421 | However, if you cease all violation of this License, then your 422 | license from a particular copyright holder is reinstated (a) 423 | provisionally, unless and until the copyright holder explicitly and 424 | finally terminates your license, and (b) permanently, if the copyright 425 | holder fails to notify you of the violation by some reasonable means 426 | prior to 60 days after the cessation. 427 | 428 | Moreover, your license from a particular copyright holder is 429 | reinstated permanently if the copyright holder notifies you of the 430 | violation by some reasonable means, this is the first time you have 431 | received notice of violation of this License (for any work) from that 432 | copyright holder, and you cure the violation prior to 30 days after 433 | your receipt of the notice. 434 | 435 | Termination of your rights under this section does not terminate the 436 | licenses of parties who have received copies or rights from you under 437 | this License. If your rights have been terminated and not permanently 438 | reinstated, you do not qualify to receive new licenses for the same 439 | material under section 10. 440 | 441 | 9. Acceptance Not Required for Having Copies. 442 | 443 | You are not required to accept this License in order to receive or 444 | run a copy of the Program. Ancillary propagation of a covered work 445 | occurring solely as a consequence of using peer-to-peer transmission 446 | to receive a copy likewise does not require acceptance. However, 447 | nothing other than this License grants you permission to propagate or 448 | modify any covered work. These actions infringe copyright if you do 449 | not accept this License. Therefore, by modifying or propagating a 450 | covered work, you indicate your acceptance of this License to do so. 451 | 452 | 10. Automatic Licensing of Downstream Recipients. 453 | 454 | Each time you convey a covered work, the recipient automatically 455 | receives a license from the original licensors, to run, modify and 456 | propagate that work, subject to this License. You are not responsible 457 | for enforcing compliance by third parties with this License. 458 | 459 | An "entity transaction" is a transaction transferring control of an 460 | organization, or substantially all assets of one, or subdividing an 461 | organization, or merging organizations. If propagation of a covered 462 | work results from an entity transaction, each party to that 463 | transaction who receives a copy of the work also receives whatever 464 | licenses to the work the party's predecessor in interest had or could 465 | give under the previous paragraph, plus a right to possession of the 466 | Corresponding Source of the work from the predecessor in interest, if 467 | the predecessor has it or can get it with reasonable efforts. 468 | 469 | You may not impose any further restrictions on the exercise of the 470 | rights granted or affirmed under this License. For example, you may 471 | not impose a license fee, royalty, or other charge for exercise of 472 | rights granted under this License, and you may not initiate litigation 473 | (including a cross-claim or counterclaim in a lawsuit) alleging that 474 | any patent claim is infringed by making, using, selling, offering for 475 | sale, or importing the Program or any portion of it. 476 | 477 | 11. Patents. 478 | 479 | A "contributor" is a copyright holder who authorizes use under this 480 | License of the Program or a work on which the Program is based. The 481 | work thus licensed is called the contributor's "contributor version". 482 | 483 | A contributor's "essential patent claims" are all patent claims 484 | owned or controlled by the contributor, whether already acquired or 485 | hereafter acquired, that would be infringed by some manner, permitted 486 | by this License, of making, using, or selling its contributor version, 487 | but do not include claims that would be infringed only as a 488 | consequence of further modification of the contributor version. For 489 | purposes of this definition, "control" includes the right to grant 490 | patent sublicenses in a manner consistent with the requirements of 491 | this License. 492 | 493 | Each contributor grants you a non-exclusive, worldwide, royalty-free 494 | patent license under the contributor's essential patent claims, to 495 | make, use, sell, offer for sale, import and otherwise run, modify and 496 | propagate the contents of its contributor version. 497 | 498 | In the following three paragraphs, a "patent license" is any express 499 | agreement or commitment, however denominated, not to enforce a patent 500 | (such as an express permission to practice a patent or covenant not to 501 | sue for patent infringement). To "grant" such a patent license to a 502 | party means to make such an agreement or commitment not to enforce a 503 | patent against the party. 504 | 505 | If you convey a covered work, knowingly relying on a patent license, 506 | and the Corresponding Source of the work is not available for anyone 507 | to copy, free of charge and under the terms of this License, through a 508 | publicly available network server or other readily accessible means, 509 | then you must either (1) cause the Corresponding Source to be so 510 | available, or (2) arrange to deprive yourself of the benefit of the 511 | patent license for this particular work, or (3) arrange, in a manner 512 | consistent with the requirements of this License, to extend the patent 513 | license to downstream recipients. "Knowingly relying" means you have 514 | actual knowledge that, but for the patent license, your conveying the 515 | covered work in a country, or your recipient's use of the covered work 516 | in a country, would infringe one or more identifiable patents in that 517 | country that you have reason to believe are valid. 518 | 519 | If, pursuant to or in connection with a single transaction or 520 | arrangement, you convey, or propagate by procuring conveyance of, a 521 | covered work, and grant a patent license to some of the parties 522 | receiving the covered work authorizing them to use, propagate, modify 523 | or convey a specific copy of the covered work, then the patent license 524 | you grant is automatically extended to all recipients of the covered 525 | work and works based on it. 526 | 527 | A patent license is "discriminatory" if it does not include within 528 | the scope of its coverage, prohibits the exercise of, or is 529 | conditioned on the non-exercise of one or more of the rights that are 530 | specifically granted under this License. You may not convey a covered 531 | work if you are a party to an arrangement with a third party that is 532 | in the business of distributing software, under which you make payment 533 | to the third party based on the extent of your activity of conveying 534 | the work, and under which the third party grants, to any of the 535 | parties who would receive the covered work from you, a discriminatory 536 | patent license (a) in connection with copies of the covered work 537 | conveyed by you (or copies made from those copies), or (b) primarily 538 | for and in connection with specific products or compilations that 539 | contain the covered work, unless you entered into that arrangement, 540 | or that patent license was granted, prior to 28 March 2007. 541 | 542 | Nothing in this License shall be construed as excluding or limiting 543 | any implied license or other defenses to infringement that may 544 | otherwise be available to you under applicable patent law. 545 | 546 | 12. No Surrender of Others' Freedom. 547 | 548 | If conditions are imposed on you (whether by court order, agreement or 549 | otherwise) that contradict the conditions of this License, they do not 550 | excuse you from the conditions of this License. If you cannot convey a 551 | covered work so as to satisfy simultaneously your obligations under this 552 | License and any other pertinent obligations, then as a consequence you may 553 | not convey it at all. For example, if you agree to terms that obligate you 554 | to collect a royalty for further conveying from those to whom you convey 555 | the Program, the only way you could satisfy both those terms and this 556 | License would be to refrain entirely from conveying the Program. 557 | 558 | 13. Remote Network Interaction; Use with the GNU General Public License. 559 | 560 | Notwithstanding any other provision of this License, if you modify the 561 | Program, your modified version must prominently offer all users 562 | interacting with it remotely through a computer network (if your version 563 | supports such interaction) an opportunity to receive the Corresponding 564 | Source of your version by providing access to the Corresponding Source 565 | from a network server at no charge, through some standard or customary 566 | means of facilitating copying of software. This Corresponding Source 567 | shall include the Corresponding Source for any work covered by version 3 568 | of the GNU General Public License that is incorporated pursuant to the 569 | following paragraph. 570 | 571 | Notwithstanding any other provision of this License, you have 572 | permission to link or combine any covered work with a work licensed 573 | under version 3 of the GNU General Public License into a single 574 | combined work, and to convey the resulting work. The terms of this 575 | License will continue to apply to the part which is the covered work, 576 | but the work with which it is combined will remain governed by version 577 | 3 of the GNU General Public License. 578 | 579 | 14. Revised Versions of this License. 580 | 581 | The Free Software Foundation may publish revised and/or new versions of 582 | the GNU Affero General Public License from time to time. Such new versions 583 | will be similar in spirit to the present version, but may differ in detail to 584 | address new problems or concerns. 585 | 586 | Each version is given a distinguishing version number. If the 587 | Program specifies that a certain numbered version of the GNU Affero General 588 | Public License "or any later version" applies to it, you have the 589 | option of following the terms and conditions either of that numbered 590 | version or of any later version published by the Free Software 591 | Foundation. If the Program does not specify a version number of the 592 | GNU Affero General Public License, you may choose any version ever published 593 | by the Free Software Foundation. 594 | 595 | If the Program specifies that a proxy can decide which future 596 | versions of the GNU Affero General Public License can be used, that proxy's 597 | public statement of acceptance of a version permanently authorizes you 598 | to choose that version for the Program. 599 | 600 | Later license versions may give you additional or different 601 | permissions. However, no additional obligations are imposed on any 602 | author or copyright holder as a result of your choosing to follow a 603 | later version. 604 | 605 | 15. Disclaimer of Warranty. 606 | 607 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 608 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 609 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 610 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 611 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 612 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 613 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 614 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 615 | 616 | 16. Limitation of Liability. 617 | 618 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 619 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 620 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 621 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 622 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 623 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 624 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 625 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 626 | SUCH DAMAGES. 627 | 628 | 17. Interpretation of Sections 15 and 16. 629 | 630 | If the disclaimer of warranty and limitation of liability provided 631 | above cannot be given local legal effect according to their terms, 632 | reviewing courts shall apply local law that most closely approximates 633 | an absolute waiver of all civil liability in connection with the 634 | Program, unless a warranty or assumption of liability accompanies a 635 | copy of the Program in return for a fee. 636 | 637 | END OF TERMS AND CONDITIONS 638 | 639 | How to Apply These Terms to Your New Programs 640 | 641 | If you develop a new program, and you want it to be of the greatest 642 | possible use to the public, the best way to achieve this is to make it 643 | free software which everyone can redistribute and change under these terms. 644 | 645 | To do so, attach the following notices to the program. It is safest 646 | to attach them to the start of each source file to most effectively 647 | state the exclusion of warranty; and each file should have at least 648 | the "copyright" line and a pointer to where the full notice is found. 649 | 650 | 651 | Copyright (C) 652 | 653 | This program is free software: you can redistribute it and/or modify 654 | it under the terms of the GNU Affero General Public License as published by 655 | the Free Software Foundation, either version 3 of the License, or 656 | (at your option) any later version. 657 | 658 | This program is distributed in the hope that it will be useful, 659 | but WITHOUT ANY WARRANTY; without even the implied warranty of 660 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 661 | GNU Affero General Public License for more details. 662 | 663 | You should have received a copy of the GNU Affero General Public License 664 | along with this program. If not, see . 665 | 666 | Also add information on how to contact you by electronic and paper mail. 667 | 668 | If your software can interact with users remotely through a computer 669 | network, you should also make sure that it provides a way for users to 670 | get its source. For example, if your program is a web application, its 671 | interface could display a "Source" link that leads users to an archive 672 | of the code. There are many ways you could offer source, and different 673 | solutions will be better for different programs; see section 13 for the 674 | specific requirements. 675 | 676 | You should also get your employer (if you work as a programmer) or school, 677 | if any, to sign a "copyright disclaimer" for the program, if necessary. 678 | For more information on this, and how to apply and follow the GNU AGPL, see 679 | . 680 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = i386-linux-musl-gcc 2 | CFLAGS = -m32 -static -Os -Wall -Wextra 3 | NASM = nasm 4 | STRIP = i386-linux-musl-strip 5 | 6 | HDD_BASE = hdd.base.img 7 | LINUX_BZIMAGE = linux-5.8.9/arch/x86/boot/bzImage 8 | BUSYBOX_BIN = busybox-1.32.0/busybox_unstripped 9 | 10 | .PHONY: all 11 | all: hdd.img 12 | 13 | .PHONY: clean 14 | clean: 15 | rm -f hdd.img doslinux.com init/init init/*.o 16 | 17 | hdd.img: $(HDD_BASE) doslinux.com init/init $(LINUX_IMAGE) $(BUSYBOX_BIN) 18 | cp $(HDD_BASE) hdd.img 19 | MTOOLSRC=mtoolsrc mmd C:/doslinux 20 | MTOOLSRC=mtoolsrc mcopy doslinux.com C:/doslinux/dsl.com 21 | MTOOLSRC=mtoolsrc mcopy init/init C:/doslinux/init 22 | MTOOLSRC=mtoolsrc mcopy $(LINUX_BZIMAGE) C:/doslinux/bzimage 23 | MTOOLSRC=mtoolsrc mcopy $(BUSYBOX_BIN) C:/doslinux/busybox 24 | MTOOLSRC=mtoolsrc mmd C:/doslinux/rootfs 25 | 26 | doslinux.com: doslinux.asm 27 | $(NASM) -o $@ -f bin $< 28 | 29 | init/init: init/init.o init/vm86.o init/panic.o init/kbd.o init/term.o 30 | $(CC) $(CFLAGS) -o $@ $^ 31 | 32 | init/%.o: init/%.c init/*.h 33 | $(CC) $(CFLAGS) -o $@ -c $< 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DOS Subsystem for Linux 2 | 3 | A WSL alternative for users who prefer an MS-DOS environment. DOS Subsystem for Linux integrates a real Linux environment into MS-DOS systems, allowing users to make use of both DOS and Linux applications from the DOS command prompt. 4 | 5 | ![](https://user-images.githubusercontent.com/179065/178898715-7e30135c-7afd-4f37-83cc-cf49a4d46d79.gif) 6 | 7 | ## Building 8 | 9 | * You will need a cross toolchain targeting `i386-linux-musl` on `PATH`. 10 | 11 | https://github.com/richfelker/musl-cross-make is a tool that can build one for you with minimal hassle. Set `TARGET` to `i386-linux-musl`. 12 | 13 | * Build the prequisites (Linux and Busybox) by running `J=xxx script/build-prereq`, replacing `xxx` with the desired build parallelism. 14 | 15 | * You will need a hard drive image `hdd.base.img` with an installed copy of MS-DOS on the first partition. 16 | 17 | * Run `make` 18 | 19 | This will produce a new hard drive image `hdd.img` with DOS Subsystem for Linux installed. Invoke `C:\doslinux\dsl ` to run Linux commands. `C:\doslinux` can also be placed on your DOS `PATH` for greater convenience. 20 | -------------------------------------------------------------------------------- /busybox-config: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated make config: don't edit 3 | # Busybox version: 1.32.0 4 | # Mon Sep 21 00:48:37 2020 5 | # 6 | CONFIG_HAVE_DOT_CONFIG=y 7 | 8 | # 9 | # Settings 10 | # 11 | # CONFIG_DESKTOP is not set 12 | # CONFIG_EXTRA_COMPAT is not set 13 | # CONFIG_FEDORA_COMPAT is not set 14 | CONFIG_INCLUDE_SUSv2=y 15 | CONFIG_LONG_OPTS=y 16 | CONFIG_SHOW_USAGE=y 17 | CONFIG_FEATURE_VERBOSE_USAGE=y 18 | CONFIG_FEATURE_COMPRESS_USAGE=y 19 | CONFIG_LFS=y 20 | # CONFIG_PAM is not set 21 | CONFIG_FEATURE_DEVPTS=y 22 | CONFIG_FEATURE_UTMP=y 23 | CONFIG_FEATURE_WTMP=y 24 | CONFIG_FEATURE_PIDFILE=y 25 | CONFIG_PID_FILE_PATH="/var/run" 26 | CONFIG_BUSYBOX=y 27 | CONFIG_FEATURE_SHOW_SCRIPT=y 28 | CONFIG_FEATURE_INSTALLER=y 29 | # CONFIG_INSTALL_NO_USR is not set 30 | CONFIG_FEATURE_SUID=y 31 | CONFIG_FEATURE_SUID_CONFIG=y 32 | CONFIG_FEATURE_SUID_CONFIG_QUIET=y 33 | # CONFIG_FEATURE_PREFER_APPLETS is not set 34 | CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" 35 | # CONFIG_SELINUX is not set 36 | # CONFIG_FEATURE_CLEAN_UP is not set 37 | CONFIG_FEATURE_SYSLOG_INFO=y 38 | CONFIG_FEATURE_SYSLOG=y 39 | CONFIG_PLATFORM_LINUX=y 40 | 41 | # 42 | # Build Options 43 | # 44 | CONFIG_STATIC=y 45 | # CONFIG_PIE is not set 46 | # CONFIG_NOMMU is not set 47 | # CONFIG_BUILD_LIBBUSYBOX is not set 48 | # CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set 49 | # CONFIG_FEATURE_INDIVIDUAL is not set 50 | # CONFIG_FEATURE_SHARED_BUSYBOX is not set 51 | CONFIG_CROSS_COMPILER_PREFIX="i386-linux-musl-" 52 | CONFIG_SYSROOT="" 53 | CONFIG_EXTRA_CFLAGS="" 54 | CONFIG_EXTRA_LDFLAGS="" 55 | CONFIG_EXTRA_LDLIBS="" 56 | # CONFIG_USE_PORTABLE_CODE is not set 57 | CONFIG_STACK_OPTIMIZATION_386=y 58 | 59 | # 60 | # Installation Options ("make install" behavior) 61 | # 62 | CONFIG_INSTALL_APPLET_SYMLINKS=y 63 | # CONFIG_INSTALL_APPLET_HARDLINKS is not set 64 | # CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set 65 | # CONFIG_INSTALL_APPLET_DONT is not set 66 | # CONFIG_INSTALL_SH_APPLET_SYMLINK is not set 67 | # CONFIG_INSTALL_SH_APPLET_HARDLINK is not set 68 | # CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set 69 | CONFIG_PREFIX="./_install" 70 | 71 | # 72 | # Debugging Options 73 | # 74 | # CONFIG_DEBUG is not set 75 | # CONFIG_DEBUG_PESSIMIZE is not set 76 | # CONFIG_DEBUG_SANITIZE is not set 77 | # CONFIG_UNIT_TEST is not set 78 | # CONFIG_WERROR is not set 79 | # CONFIG_WARN_SIMPLE_MSG is not set 80 | CONFIG_NO_DEBUG_LIB=y 81 | # CONFIG_DMALLOC is not set 82 | # CONFIG_EFENCE is not set 83 | 84 | # 85 | # Library Tuning 86 | # 87 | # CONFIG_FEATURE_USE_BSS_TAIL is not set 88 | CONFIG_FLOAT_DURATION=y 89 | CONFIG_FEATURE_RTMINMAX=y 90 | CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS=y 91 | CONFIG_FEATURE_BUFFERS_USE_MALLOC=y 92 | # CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set 93 | # CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set 94 | CONFIG_PASSWORD_MINLEN=6 95 | CONFIG_MD5_SMALL=1 96 | CONFIG_SHA3_SMALL=1 97 | # CONFIG_FEATURE_FAST_TOP is not set 98 | # CONFIG_FEATURE_ETC_NETWORKS is not set 99 | # CONFIG_FEATURE_ETC_SERVICES is not set 100 | CONFIG_FEATURE_EDITING=y 101 | CONFIG_FEATURE_EDITING_MAX_LEN=1024 102 | # CONFIG_FEATURE_EDITING_VI is not set 103 | CONFIG_FEATURE_EDITING_HISTORY=255 104 | CONFIG_FEATURE_EDITING_SAVEHISTORY=y 105 | # CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set 106 | CONFIG_FEATURE_REVERSE_SEARCH=y 107 | CONFIG_FEATURE_TAB_COMPLETION=y 108 | CONFIG_FEATURE_USERNAME_COMPLETION=y 109 | CONFIG_FEATURE_EDITING_FANCY_PROMPT=y 110 | CONFIG_FEATURE_EDITING_WINCH=y 111 | # CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set 112 | # CONFIG_LOCALE_SUPPORT is not set 113 | CONFIG_UNICODE_SUPPORT=y 114 | # CONFIG_UNICODE_USING_LOCALE is not set 115 | # CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set 116 | CONFIG_SUBST_WCHAR=63 117 | CONFIG_LAST_SUPPORTED_WCHAR=767 118 | # CONFIG_UNICODE_COMBINING_WCHARS is not set 119 | # CONFIG_UNICODE_WIDE_WCHARS is not set 120 | # CONFIG_UNICODE_BIDI_SUPPORT is not set 121 | # CONFIG_UNICODE_NEUTRAL_TABLE is not set 122 | # CONFIG_UNICODE_PRESERVE_BROKEN is not set 123 | CONFIG_FEATURE_NON_POSIX_CP=y 124 | # CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set 125 | CONFIG_FEATURE_USE_SENDFILE=y 126 | CONFIG_FEATURE_COPYBUF_KB=4 127 | CONFIG_FEATURE_SKIP_ROOTFS=y 128 | CONFIG_MONOTONIC_SYSCALL=y 129 | CONFIG_IOCTL_HEX2STR_ERROR=y 130 | CONFIG_FEATURE_HWIB=y 131 | 132 | # 133 | # Applets 134 | # 135 | 136 | # 137 | # Archival Utilities 138 | # 139 | CONFIG_FEATURE_SEAMLESS_XZ=y 140 | CONFIG_FEATURE_SEAMLESS_LZMA=y 141 | CONFIG_FEATURE_SEAMLESS_BZ2=y 142 | CONFIG_FEATURE_SEAMLESS_GZ=y 143 | # CONFIG_FEATURE_SEAMLESS_Z is not set 144 | # CONFIG_AR is not set 145 | # CONFIG_FEATURE_AR_LONG_FILENAMES is not set 146 | # CONFIG_FEATURE_AR_CREATE is not set 147 | # CONFIG_UNCOMPRESS is not set 148 | CONFIG_GUNZIP=y 149 | CONFIG_ZCAT=y 150 | CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y 151 | CONFIG_BUNZIP2=y 152 | CONFIG_BZCAT=y 153 | CONFIG_UNLZMA=y 154 | CONFIG_LZCAT=y 155 | CONFIG_LZMA=y 156 | CONFIG_UNXZ=y 157 | CONFIG_XZCAT=y 158 | CONFIG_XZ=y 159 | CONFIG_BZIP2=y 160 | CONFIG_BZIP2_SMALL=8 161 | CONFIG_FEATURE_BZIP2_DECOMPRESS=y 162 | CONFIG_CPIO=y 163 | CONFIG_FEATURE_CPIO_O=y 164 | CONFIG_FEATURE_CPIO_P=y 165 | CONFIG_DPKG=y 166 | CONFIG_DPKG_DEB=y 167 | CONFIG_GZIP=y 168 | CONFIG_FEATURE_GZIP_LONG_OPTIONS=y 169 | CONFIG_GZIP_FAST=0 170 | # CONFIG_FEATURE_GZIP_LEVELS is not set 171 | CONFIG_FEATURE_GZIP_DECOMPRESS=y 172 | CONFIG_LZOP=y 173 | # CONFIG_UNLZOP is not set 174 | # CONFIG_LZOPCAT is not set 175 | # CONFIG_LZOP_COMPR_HIGH is not set 176 | CONFIG_RPM=y 177 | CONFIG_RPM2CPIO=y 178 | CONFIG_TAR=y 179 | CONFIG_FEATURE_TAR_LONG_OPTIONS=y 180 | CONFIG_FEATURE_TAR_CREATE=y 181 | CONFIG_FEATURE_TAR_AUTODETECT=y 182 | CONFIG_FEATURE_TAR_FROM=y 183 | CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y 184 | CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y 185 | CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y 186 | CONFIG_FEATURE_TAR_TO_COMMAND=y 187 | CONFIG_FEATURE_TAR_UNAME_GNAME=y 188 | CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y 189 | # CONFIG_FEATURE_TAR_SELINUX is not set 190 | CONFIG_UNZIP=y 191 | CONFIG_FEATURE_UNZIP_CDF=y 192 | # CONFIG_FEATURE_UNZIP_BZIP2 is not set 193 | # CONFIG_FEATURE_UNZIP_LZMA is not set 194 | # CONFIG_FEATURE_UNZIP_XZ is not set 195 | # CONFIG_FEATURE_LZMA_FAST is not set 196 | 197 | # 198 | # Coreutils 199 | # 200 | CONFIG_BASENAME=y 201 | CONFIG_CAT=y 202 | CONFIG_FEATURE_CATN=y 203 | CONFIG_FEATURE_CATV=y 204 | CONFIG_CHGRP=y 205 | CONFIG_CHMOD=y 206 | CONFIG_CHOWN=y 207 | CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y 208 | CONFIG_CHROOT=y 209 | CONFIG_CKSUM=y 210 | CONFIG_COMM=y 211 | CONFIG_CP=y 212 | CONFIG_FEATURE_CP_LONG_OPTIONS=y 213 | CONFIG_FEATURE_CP_REFLINK=y 214 | CONFIG_CUT=y 215 | CONFIG_DATE=y 216 | CONFIG_FEATURE_DATE_ISOFMT=y 217 | # CONFIG_FEATURE_DATE_NANO is not set 218 | CONFIG_FEATURE_DATE_COMPAT=y 219 | CONFIG_DD=y 220 | CONFIG_FEATURE_DD_SIGNAL_HANDLING=y 221 | CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y 222 | CONFIG_FEATURE_DD_IBS_OBS=y 223 | CONFIG_FEATURE_DD_STATUS=y 224 | CONFIG_DF=y 225 | CONFIG_FEATURE_DF_FANCY=y 226 | CONFIG_DIRNAME=y 227 | CONFIG_DOS2UNIX=y 228 | CONFIG_UNIX2DOS=y 229 | CONFIG_DU=y 230 | CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y 231 | CONFIG_ECHO=y 232 | CONFIG_FEATURE_FANCY_ECHO=y 233 | CONFIG_ENV=y 234 | CONFIG_EXPAND=y 235 | CONFIG_UNEXPAND=y 236 | CONFIG_EXPR=y 237 | CONFIG_EXPR_MATH_SUPPORT_64=y 238 | CONFIG_FACTOR=y 239 | CONFIG_FALSE=y 240 | CONFIG_FOLD=y 241 | CONFIG_HEAD=y 242 | CONFIG_FEATURE_FANCY_HEAD=y 243 | CONFIG_HOSTID=y 244 | CONFIG_ID=y 245 | CONFIG_GROUPS=y 246 | CONFIG_INSTALL=y 247 | CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y 248 | CONFIG_LINK=y 249 | CONFIG_LN=y 250 | CONFIG_LOGNAME=y 251 | CONFIG_LS=y 252 | CONFIG_FEATURE_LS_FILETYPES=y 253 | CONFIG_FEATURE_LS_FOLLOWLINKS=y 254 | CONFIG_FEATURE_LS_RECURSIVE=y 255 | CONFIG_FEATURE_LS_WIDTH=y 256 | CONFIG_FEATURE_LS_SORTFILES=y 257 | CONFIG_FEATURE_LS_TIMESTAMPS=y 258 | CONFIG_FEATURE_LS_USERNAME=y 259 | CONFIG_FEATURE_LS_COLOR=y 260 | CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y 261 | CONFIG_MD5SUM=y 262 | CONFIG_SHA1SUM=y 263 | CONFIG_SHA256SUM=y 264 | CONFIG_SHA512SUM=y 265 | CONFIG_SHA3SUM=y 266 | 267 | # 268 | # Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum 269 | # 270 | CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y 271 | CONFIG_MKDIR=y 272 | CONFIG_MKFIFO=y 273 | CONFIG_MKNOD=y 274 | CONFIG_MKTEMP=y 275 | CONFIG_MV=y 276 | CONFIG_NICE=y 277 | CONFIG_NL=y 278 | CONFIG_NOHUP=y 279 | CONFIG_NPROC=y 280 | CONFIG_OD=y 281 | CONFIG_PASTE=y 282 | CONFIG_PRINTENV=y 283 | CONFIG_PRINTF=y 284 | CONFIG_PWD=y 285 | CONFIG_READLINK=y 286 | CONFIG_FEATURE_READLINK_FOLLOW=y 287 | CONFIG_REALPATH=y 288 | CONFIG_RM=y 289 | CONFIG_RMDIR=y 290 | CONFIG_SEQ=y 291 | CONFIG_SHRED=y 292 | CONFIG_SHUF=y 293 | CONFIG_SLEEP=y 294 | CONFIG_FEATURE_FANCY_SLEEP=y 295 | CONFIG_SORT=y 296 | CONFIG_FEATURE_SORT_BIG=y 297 | # CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set 298 | CONFIG_SPLIT=y 299 | CONFIG_FEATURE_SPLIT_FANCY=y 300 | CONFIG_STAT=y 301 | CONFIG_FEATURE_STAT_FORMAT=y 302 | CONFIG_FEATURE_STAT_FILESYSTEM=y 303 | CONFIG_STTY=y 304 | CONFIG_SUM=y 305 | CONFIG_SYNC=y 306 | CONFIG_FEATURE_SYNC_FANCY=y 307 | CONFIG_FSYNC=y 308 | CONFIG_TAC=y 309 | CONFIG_TAIL=y 310 | CONFIG_FEATURE_FANCY_TAIL=y 311 | CONFIG_TEE=y 312 | CONFIG_FEATURE_TEE_USE_BLOCK_IO=y 313 | CONFIG_TEST=y 314 | CONFIG_TEST1=y 315 | CONFIG_TEST2=y 316 | CONFIG_FEATURE_TEST_64=y 317 | CONFIG_TIMEOUT=y 318 | CONFIG_TOUCH=y 319 | CONFIG_FEATURE_TOUCH_NODEREF=y 320 | CONFIG_FEATURE_TOUCH_SUSV3=y 321 | CONFIG_TR=y 322 | CONFIG_FEATURE_TR_CLASSES=y 323 | CONFIG_FEATURE_TR_EQUIV=y 324 | CONFIG_TRUE=y 325 | CONFIG_TRUNCATE=y 326 | CONFIG_TTY=y 327 | CONFIG_UNAME=y 328 | CONFIG_UNAME_OSNAME="GNU/Linux" 329 | CONFIG_BB_ARCH=y 330 | CONFIG_UNIQ=y 331 | CONFIG_UNLINK=y 332 | CONFIG_USLEEP=y 333 | CONFIG_UUDECODE=y 334 | CONFIG_BASE64=y 335 | CONFIG_UUENCODE=y 336 | CONFIG_WC=y 337 | CONFIG_FEATURE_WC_LARGE=y 338 | CONFIG_WHOAMI=y 339 | CONFIG_WHO=y 340 | CONFIG_W=y 341 | CONFIG_USERS=y 342 | CONFIG_YES=y 343 | 344 | # 345 | # Common options 346 | # 347 | CONFIG_FEATURE_VERBOSE=y 348 | 349 | # 350 | # Common options for cp and mv 351 | # 352 | CONFIG_FEATURE_PRESERVE_HARDLINKS=y 353 | 354 | # 355 | # Common options for df, du, ls 356 | # 357 | CONFIG_FEATURE_HUMAN_READABLE=y 358 | 359 | # 360 | # Console Utilities 361 | # 362 | CONFIG_CHVT=y 363 | CONFIG_CLEAR=y 364 | CONFIG_DEALLOCVT=y 365 | CONFIG_DUMPKMAP=y 366 | CONFIG_FGCONSOLE=y 367 | CONFIG_KBD_MODE=y 368 | CONFIG_LOADFONT=y 369 | CONFIG_SETFONT=y 370 | CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y 371 | CONFIG_DEFAULT_SETFONT_DIR="" 372 | 373 | # 374 | # Common options for loadfont and setfont 375 | # 376 | CONFIG_FEATURE_LOADFONT_PSF2=y 377 | CONFIG_FEATURE_LOADFONT_RAW=y 378 | CONFIG_LOADKMAP=y 379 | CONFIG_OPENVT=y 380 | CONFIG_RESET=y 381 | CONFIG_RESIZE=y 382 | CONFIG_FEATURE_RESIZE_PRINT=y 383 | CONFIG_SETCONSOLE=y 384 | CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y 385 | CONFIG_SETKEYCODES=y 386 | CONFIG_SETLOGCONS=y 387 | CONFIG_SHOWKEY=y 388 | 389 | # 390 | # Debian Utilities 391 | # 392 | CONFIG_PIPE_PROGRESS=y 393 | CONFIG_RUN_PARTS=y 394 | CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y 395 | CONFIG_FEATURE_RUN_PARTS_FANCY=y 396 | CONFIG_START_STOP_DAEMON=y 397 | CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y 398 | CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y 399 | CONFIG_WHICH=y 400 | 401 | # 402 | # klibc-utils 403 | # 404 | # CONFIG_MINIPS is not set 405 | CONFIG_NUKE=y 406 | CONFIG_RESUME=y 407 | CONFIG_RUN_INIT=y 408 | 409 | # 410 | # Editors 411 | # 412 | CONFIG_AWK=y 413 | CONFIG_FEATURE_AWK_LIBM=y 414 | CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y 415 | CONFIG_CMP=y 416 | CONFIG_DIFF=y 417 | CONFIG_FEATURE_DIFF_LONG_OPTIONS=y 418 | CONFIG_FEATURE_DIFF_DIR=y 419 | CONFIG_ED=y 420 | CONFIG_PATCH=y 421 | CONFIG_SED=y 422 | CONFIG_VI=y 423 | CONFIG_FEATURE_VI_MAX_LEN=4096 424 | # CONFIG_FEATURE_VI_8BIT is not set 425 | CONFIG_FEATURE_VI_COLON=y 426 | CONFIG_FEATURE_VI_YANKMARK=y 427 | CONFIG_FEATURE_VI_SEARCH=y 428 | # CONFIG_FEATURE_VI_REGEX_SEARCH is not set 429 | CONFIG_FEATURE_VI_USE_SIGNALS=y 430 | CONFIG_FEATURE_VI_DOT_CMD=y 431 | CONFIG_FEATURE_VI_READONLY=y 432 | CONFIG_FEATURE_VI_SETOPTS=y 433 | CONFIG_FEATURE_VI_SET=y 434 | CONFIG_FEATURE_VI_WIN_RESIZE=y 435 | CONFIG_FEATURE_VI_ASK_TERMINAL=y 436 | CONFIG_FEATURE_VI_UNDO=y 437 | CONFIG_FEATURE_VI_UNDO_QUEUE=y 438 | CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 439 | CONFIG_FEATURE_ALLOW_EXEC=y 440 | 441 | # 442 | # Finding Utilities 443 | # 444 | CONFIG_FIND=y 445 | CONFIG_FEATURE_FIND_PRINT0=y 446 | CONFIG_FEATURE_FIND_MTIME=y 447 | CONFIG_FEATURE_FIND_MMIN=y 448 | CONFIG_FEATURE_FIND_PERM=y 449 | CONFIG_FEATURE_FIND_TYPE=y 450 | CONFIG_FEATURE_FIND_EXECUTABLE=y 451 | CONFIG_FEATURE_FIND_XDEV=y 452 | CONFIG_FEATURE_FIND_MAXDEPTH=y 453 | CONFIG_FEATURE_FIND_NEWER=y 454 | CONFIG_FEATURE_FIND_INUM=y 455 | CONFIG_FEATURE_FIND_EXEC=y 456 | CONFIG_FEATURE_FIND_EXEC_PLUS=y 457 | CONFIG_FEATURE_FIND_USER=y 458 | CONFIG_FEATURE_FIND_GROUP=y 459 | CONFIG_FEATURE_FIND_NOT=y 460 | CONFIG_FEATURE_FIND_DEPTH=y 461 | CONFIG_FEATURE_FIND_PAREN=y 462 | CONFIG_FEATURE_FIND_SIZE=y 463 | CONFIG_FEATURE_FIND_PRUNE=y 464 | CONFIG_FEATURE_FIND_QUIT=y 465 | CONFIG_FEATURE_FIND_DELETE=y 466 | CONFIG_FEATURE_FIND_EMPTY=y 467 | CONFIG_FEATURE_FIND_PATH=y 468 | CONFIG_FEATURE_FIND_REGEX=y 469 | # CONFIG_FEATURE_FIND_CONTEXT is not set 470 | CONFIG_FEATURE_FIND_LINKS=y 471 | CONFIG_GREP=y 472 | CONFIG_EGREP=y 473 | CONFIG_FGREP=y 474 | CONFIG_FEATURE_GREP_CONTEXT=y 475 | CONFIG_XARGS=y 476 | CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y 477 | CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y 478 | CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y 479 | CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y 480 | CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y 481 | CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y 482 | CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y 483 | 484 | # 485 | # Init Utilities 486 | # 487 | CONFIG_BOOTCHARTD=y 488 | CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y 489 | CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y 490 | CONFIG_HALT=y 491 | CONFIG_POWEROFF=y 492 | CONFIG_REBOOT=y 493 | CONFIG_FEATURE_WAIT_FOR_INIT=y 494 | # CONFIG_FEATURE_CALL_TELINIT is not set 495 | CONFIG_TELINIT_PATH="" 496 | CONFIG_INIT=y 497 | CONFIG_LINUXRC=y 498 | CONFIG_FEATURE_USE_INITTAB=y 499 | # CONFIG_FEATURE_KILL_REMOVED is not set 500 | CONFIG_FEATURE_KILL_DELAY=0 501 | CONFIG_FEATURE_INIT_SCTTY=y 502 | CONFIG_FEATURE_INIT_SYSLOG=y 503 | CONFIG_FEATURE_INIT_QUIET=y 504 | # CONFIG_FEATURE_INIT_COREDUMPS is not set 505 | CONFIG_INIT_TERMINAL_TYPE="linux" 506 | CONFIG_FEATURE_INIT_MODIFY_CMDLINE=y 507 | 508 | # 509 | # Login/Password Management Utilities 510 | # 511 | CONFIG_FEATURE_SHADOWPASSWDS=y 512 | CONFIG_USE_BB_PWD_GRP=y 513 | CONFIG_USE_BB_SHADOW=y 514 | CONFIG_USE_BB_CRYPT=y 515 | CONFIG_USE_BB_CRYPT_SHA=y 516 | CONFIG_ADDGROUP=y 517 | CONFIG_FEATURE_ADDUSER_TO_GROUP=y 518 | CONFIG_ADD_SHELL=y 519 | CONFIG_REMOVE_SHELL=y 520 | CONFIG_ADDUSER=y 521 | # CONFIG_FEATURE_CHECK_NAMES is not set 522 | CONFIG_LAST_ID=60000 523 | CONFIG_FIRST_SYSTEM_ID=100 524 | CONFIG_LAST_SYSTEM_ID=999 525 | CONFIG_CHPASSWD=y 526 | CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="des" 527 | CONFIG_CRYPTPW=y 528 | CONFIG_MKPASSWD=y 529 | CONFIG_DELUSER=y 530 | CONFIG_DELGROUP=y 531 | CONFIG_FEATURE_DEL_USER_FROM_GROUP=y 532 | CONFIG_GETTY=y 533 | CONFIG_LOGIN=y 534 | # CONFIG_LOGIN_SESSION_AS_CHILD is not set 535 | CONFIG_LOGIN_SCRIPTS=y 536 | CONFIG_FEATURE_NOLOGIN=y 537 | CONFIG_FEATURE_SECURETTY=y 538 | CONFIG_PASSWD=y 539 | CONFIG_FEATURE_PASSWD_WEAK_CHECK=y 540 | CONFIG_SU=y 541 | CONFIG_FEATURE_SU_SYSLOG=y 542 | CONFIG_FEATURE_SU_CHECKS_SHELLS=y 543 | # CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set 544 | CONFIG_SULOGIN=y 545 | CONFIG_VLOCK=y 546 | 547 | # 548 | # Linux Ext2 FS Progs 549 | # 550 | CONFIG_CHATTR=y 551 | CONFIG_FSCK=y 552 | CONFIG_LSATTR=y 553 | # CONFIG_TUNE2FS is not set 554 | 555 | # 556 | # Linux Module Utilities 557 | # 558 | CONFIG_MODPROBE_SMALL=y 559 | CONFIG_DEPMOD=y 560 | CONFIG_INSMOD=y 561 | CONFIG_LSMOD=y 562 | # CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set 563 | CONFIG_MODINFO=y 564 | CONFIG_MODPROBE=y 565 | # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set 566 | CONFIG_RMMOD=y 567 | 568 | # 569 | # Options common to multiple modutils 570 | # 571 | CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS=y 572 | CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y 573 | # CONFIG_FEATURE_2_4_MODULES is not set 574 | # CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set 575 | # CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set 576 | # CONFIG_FEATURE_INSMOD_LOADINKMEM is not set 577 | # CONFIG_FEATURE_INSMOD_LOAD_MAP is not set 578 | # CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set 579 | # CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set 580 | # CONFIG_FEATURE_INSMOD_TRY_MMAP is not set 581 | # CONFIG_FEATURE_MODUTILS_ALIAS is not set 582 | # CONFIG_FEATURE_MODUTILS_SYMBOLS is not set 583 | CONFIG_DEFAULT_MODULES_DIR="/lib/modules" 584 | CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" 585 | 586 | # 587 | # Linux System Utilities 588 | # 589 | CONFIG_ACPID=y 590 | CONFIG_FEATURE_ACPID_COMPAT=y 591 | CONFIG_BLKDISCARD=y 592 | CONFIG_BLKID=y 593 | CONFIG_FEATURE_BLKID_TYPE=y 594 | CONFIG_BLOCKDEV=y 595 | CONFIG_CAL=y 596 | CONFIG_CHRT=y 597 | CONFIG_DMESG=y 598 | CONFIG_FEATURE_DMESG_PRETTY=y 599 | CONFIG_EJECT=y 600 | CONFIG_FEATURE_EJECT_SCSI=y 601 | CONFIG_FALLOCATE=y 602 | CONFIG_FATATTR=y 603 | CONFIG_FBSET=y 604 | CONFIG_FEATURE_FBSET_FANCY=y 605 | CONFIG_FEATURE_FBSET_READMODE=y 606 | CONFIG_FDFORMAT=y 607 | CONFIG_FDISK=y 608 | # CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set 609 | CONFIG_FEATURE_FDISK_WRITABLE=y 610 | # CONFIG_FEATURE_AIX_LABEL is not set 611 | # CONFIG_FEATURE_SGI_LABEL is not set 612 | # CONFIG_FEATURE_SUN_LABEL is not set 613 | # CONFIG_FEATURE_OSF_LABEL is not set 614 | # CONFIG_FEATURE_GPT_LABEL is not set 615 | CONFIG_FEATURE_FDISK_ADVANCED=y 616 | CONFIG_FINDFS=y 617 | CONFIG_FLOCK=y 618 | CONFIG_FDFLUSH=y 619 | CONFIG_FREERAMDISK=y 620 | CONFIG_FSCK_MINIX=y 621 | CONFIG_FSFREEZE=y 622 | CONFIG_FSTRIM=y 623 | CONFIG_GETOPT=y 624 | CONFIG_FEATURE_GETOPT_LONG=y 625 | CONFIG_HEXDUMP=y 626 | CONFIG_FEATURE_HEXDUMP_REVERSE=y 627 | CONFIG_HD=y 628 | CONFIG_XXD=y 629 | CONFIG_HWCLOCK=y 630 | # CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set 631 | CONFIG_IONICE=y 632 | CONFIG_IPCRM=y 633 | CONFIG_IPCS=y 634 | CONFIG_LAST=y 635 | CONFIG_FEATURE_LAST_FANCY=y 636 | CONFIG_LOSETUP=y 637 | CONFIG_LSPCI=y 638 | CONFIG_LSUSB=y 639 | CONFIG_MDEV=y 640 | CONFIG_FEATURE_MDEV_CONF=y 641 | CONFIG_FEATURE_MDEV_RENAME=y 642 | CONFIG_FEATURE_MDEV_RENAME_REGEXP=y 643 | CONFIG_FEATURE_MDEV_EXEC=y 644 | CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y 645 | CONFIG_FEATURE_MDEV_DAEMON=y 646 | CONFIG_MESG=y 647 | CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y 648 | CONFIG_MKE2FS=y 649 | CONFIG_MKFS_EXT2=y 650 | CONFIG_MKFS_MINIX=y 651 | CONFIG_FEATURE_MINIX2=y 652 | # CONFIG_MKFS_REISER is not set 653 | CONFIG_MKDOSFS=y 654 | CONFIG_MKFS_VFAT=y 655 | CONFIG_MKSWAP=y 656 | CONFIG_FEATURE_MKSWAP_UUID=y 657 | CONFIG_MORE=y 658 | CONFIG_MOUNT=y 659 | CONFIG_FEATURE_MOUNT_FAKE=y 660 | CONFIG_FEATURE_MOUNT_VERBOSE=y 661 | # CONFIG_FEATURE_MOUNT_HELPERS is not set 662 | CONFIG_FEATURE_MOUNT_LABEL=y 663 | # CONFIG_FEATURE_MOUNT_NFS is not set 664 | CONFIG_FEATURE_MOUNT_CIFS=y 665 | CONFIG_FEATURE_MOUNT_FLAGS=y 666 | CONFIG_FEATURE_MOUNT_FSTAB=y 667 | CONFIG_FEATURE_MOUNT_OTHERTAB=y 668 | CONFIG_MOUNTPOINT=y 669 | CONFIG_NOLOGIN=y 670 | # CONFIG_NOLOGIN_DEPENDENCIES is not set 671 | CONFIG_NSENTER=y 672 | CONFIG_PIVOT_ROOT=y 673 | CONFIG_RDATE=y 674 | CONFIG_RDEV=y 675 | CONFIG_READPROFILE=y 676 | CONFIG_RENICE=y 677 | CONFIG_REV=y 678 | CONFIG_RTCWAKE=y 679 | CONFIG_SCRIPT=y 680 | CONFIG_SCRIPTREPLAY=y 681 | CONFIG_SETARCH=y 682 | CONFIG_LINUX32=y 683 | CONFIG_LINUX64=y 684 | CONFIG_SETPRIV=y 685 | CONFIG_FEATURE_SETPRIV_DUMP=y 686 | CONFIG_FEATURE_SETPRIV_CAPABILITIES=y 687 | CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES=y 688 | CONFIG_SETSID=y 689 | CONFIG_SWAPON=y 690 | CONFIG_FEATURE_SWAPON_DISCARD=y 691 | CONFIG_FEATURE_SWAPON_PRI=y 692 | CONFIG_SWAPOFF=y 693 | CONFIG_FEATURE_SWAPONOFF_LABEL=y 694 | CONFIG_SWITCH_ROOT=y 695 | CONFIG_TASKSET=y 696 | CONFIG_FEATURE_TASKSET_FANCY=y 697 | CONFIG_FEATURE_TASKSET_CPULIST=y 698 | CONFIG_UEVENT=y 699 | CONFIG_UMOUNT=y 700 | CONFIG_FEATURE_UMOUNT_ALL=y 701 | CONFIG_UNSHARE=y 702 | CONFIG_WALL=y 703 | 704 | # 705 | # Common options for mount/umount 706 | # 707 | CONFIG_FEATURE_MOUNT_LOOP=y 708 | CONFIG_FEATURE_MOUNT_LOOP_CREATE=y 709 | # CONFIG_FEATURE_MTAB_SUPPORT is not set 710 | CONFIG_VOLUMEID=y 711 | 712 | # 713 | # Filesystem/Volume identification 714 | # 715 | CONFIG_FEATURE_VOLUMEID_BCACHE=y 716 | CONFIG_FEATURE_VOLUMEID_BTRFS=y 717 | CONFIG_FEATURE_VOLUMEID_CRAMFS=y 718 | CONFIG_FEATURE_VOLUMEID_EXFAT=y 719 | CONFIG_FEATURE_VOLUMEID_EXT=y 720 | CONFIG_FEATURE_VOLUMEID_F2FS=y 721 | CONFIG_FEATURE_VOLUMEID_FAT=y 722 | CONFIG_FEATURE_VOLUMEID_HFS=y 723 | CONFIG_FEATURE_VOLUMEID_ISO9660=y 724 | CONFIG_FEATURE_VOLUMEID_JFS=y 725 | CONFIG_FEATURE_VOLUMEID_LFS=y 726 | CONFIG_FEATURE_VOLUMEID_LINUXRAID=y 727 | CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y 728 | CONFIG_FEATURE_VOLUMEID_LUKS=y 729 | CONFIG_FEATURE_VOLUMEID_MINIX=y 730 | CONFIG_FEATURE_VOLUMEID_NILFS=y 731 | CONFIG_FEATURE_VOLUMEID_NTFS=y 732 | CONFIG_FEATURE_VOLUMEID_OCFS2=y 733 | CONFIG_FEATURE_VOLUMEID_REISERFS=y 734 | CONFIG_FEATURE_VOLUMEID_ROMFS=y 735 | CONFIG_FEATURE_VOLUMEID_SQUASHFS=y 736 | CONFIG_FEATURE_VOLUMEID_SYSV=y 737 | CONFIG_FEATURE_VOLUMEID_UBIFS=y 738 | CONFIG_FEATURE_VOLUMEID_UDF=y 739 | CONFIG_FEATURE_VOLUMEID_XFS=y 740 | 741 | # 742 | # Miscellaneous Utilities 743 | # 744 | CONFIG_ADJTIMEX=y 745 | # CONFIG_BBCONFIG is not set 746 | # CONFIG_FEATURE_COMPRESS_BBCONFIG is not set 747 | CONFIG_BC=y 748 | CONFIG_DC=y 749 | CONFIG_FEATURE_DC_BIG=y 750 | # CONFIG_FEATURE_DC_LIBM is not set 751 | CONFIG_FEATURE_BC_INTERACTIVE=y 752 | CONFIG_FEATURE_BC_LONG_OPTIONS=y 753 | CONFIG_BEEP=y 754 | CONFIG_FEATURE_BEEP_FREQ=4000 755 | CONFIG_FEATURE_BEEP_LENGTH_MS=30 756 | CONFIG_CHAT=y 757 | CONFIG_FEATURE_CHAT_NOFAIL=y 758 | # CONFIG_FEATURE_CHAT_TTY_HIFI is not set 759 | CONFIG_FEATURE_CHAT_IMPLICIT_CR=y 760 | CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y 761 | CONFIG_FEATURE_CHAT_SEND_ESCAPES=y 762 | CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y 763 | CONFIG_FEATURE_CHAT_CLR_ABORT=y 764 | CONFIG_CONSPY=y 765 | CONFIG_CROND=y 766 | CONFIG_FEATURE_CROND_D=y 767 | CONFIG_FEATURE_CROND_CALL_SENDMAIL=y 768 | CONFIG_FEATURE_CROND_SPECIAL_TIMES=y 769 | CONFIG_FEATURE_CROND_DIR="/var/spool/cron" 770 | CONFIG_CRONTAB=y 771 | # CONFIG_DEVFSD is not set 772 | # CONFIG_DEVFSD_MODLOAD is not set 773 | # CONFIG_DEVFSD_FG_NP is not set 774 | # CONFIG_DEVFSD_VERBOSE is not set 775 | # CONFIG_FEATURE_DEVFS is not set 776 | CONFIG_DEVMEM=y 777 | CONFIG_FBSPLASH=y 778 | # CONFIG_FLASHCP is not set 779 | # CONFIG_FLASH_ERASEALL is not set 780 | # CONFIG_FLASH_LOCK is not set 781 | # CONFIG_FLASH_UNLOCK is not set 782 | CONFIG_HDPARM=y 783 | CONFIG_FEATURE_HDPARM_GET_IDENTITY=y 784 | CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y 785 | CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y 786 | CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y 787 | CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y 788 | CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y 789 | CONFIG_HEXEDIT=y 790 | CONFIG_I2CGET=y 791 | CONFIG_I2CSET=y 792 | CONFIG_I2CDUMP=y 793 | CONFIG_I2CDETECT=y 794 | CONFIG_I2CTRANSFER=y 795 | # CONFIG_INOTIFYD is not set 796 | CONFIG_LESS=y 797 | CONFIG_FEATURE_LESS_MAXLINES=9999999 798 | CONFIG_FEATURE_LESS_BRACKETS=y 799 | CONFIG_FEATURE_LESS_FLAGS=y 800 | CONFIG_FEATURE_LESS_TRUNCATE=y 801 | CONFIG_FEATURE_LESS_MARKS=y 802 | CONFIG_FEATURE_LESS_REGEXP=y 803 | CONFIG_FEATURE_LESS_WINCH=y 804 | CONFIG_FEATURE_LESS_ASK_TERMINAL=y 805 | CONFIG_FEATURE_LESS_DASHCMD=y 806 | CONFIG_FEATURE_LESS_LINENUMS=y 807 | CONFIG_FEATURE_LESS_RAW=y 808 | CONFIG_FEATURE_LESS_ENV=y 809 | CONFIG_LSSCSI=y 810 | CONFIG_MAKEDEVS=y 811 | # CONFIG_FEATURE_MAKEDEVS_LEAF is not set 812 | CONFIG_FEATURE_MAKEDEVS_TABLE=y 813 | CONFIG_MAN=y 814 | CONFIG_MICROCOM=y 815 | CONFIG_MIM=y 816 | CONFIG_MT=y 817 | CONFIG_NANDWRITE=y 818 | CONFIG_NANDDUMP=y 819 | CONFIG_PARTPROBE=y 820 | CONFIG_RAIDAUTORUN=y 821 | CONFIG_READAHEAD=y 822 | # CONFIG_RFKILL is not set 823 | CONFIG_RUNLEVEL=y 824 | CONFIG_RX=y 825 | CONFIG_SETFATTR=y 826 | CONFIG_SETSERIAL=y 827 | CONFIG_STRINGS=y 828 | CONFIG_TIME=y 829 | CONFIG_TS=y 830 | CONFIG_TTYSIZE=y 831 | CONFIG_UBIRENAME=y 832 | CONFIG_UBIATTACH=y 833 | CONFIG_UBIDETACH=y 834 | CONFIG_UBIMKVOL=y 835 | CONFIG_UBIRMVOL=y 836 | CONFIG_UBIRSVOL=y 837 | CONFIG_UBIUPDATEVOL=y 838 | CONFIG_VOLNAME=y 839 | CONFIG_WATCHDOG=y 840 | 841 | # 842 | # Networking Utilities 843 | # 844 | CONFIG_FEATURE_IPV6=y 845 | # CONFIG_FEATURE_UNIX_LOCAL is not set 846 | CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y 847 | # CONFIG_VERBOSE_RESOLUTION_ERRORS is not set 848 | # CONFIG_FEATURE_TLS_SHA1 is not set 849 | CONFIG_ARP=y 850 | CONFIG_ARPING=y 851 | CONFIG_BRCTL=y 852 | CONFIG_FEATURE_BRCTL_FANCY=y 853 | CONFIG_FEATURE_BRCTL_SHOW=y 854 | CONFIG_DNSD=y 855 | CONFIG_ETHER_WAKE=y 856 | CONFIG_FTPD=y 857 | CONFIG_FEATURE_FTPD_WRITE=y 858 | CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y 859 | CONFIG_FEATURE_FTPD_AUTHENTICATION=y 860 | CONFIG_FTPGET=y 861 | CONFIG_FTPPUT=y 862 | CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y 863 | CONFIG_HOSTNAME=y 864 | CONFIG_DNSDOMAINNAME=y 865 | CONFIG_HTTPD=y 866 | CONFIG_FEATURE_HTTPD_RANGES=y 867 | CONFIG_FEATURE_HTTPD_SETUID=y 868 | CONFIG_FEATURE_HTTPD_BASIC_AUTH=y 869 | CONFIG_FEATURE_HTTPD_AUTH_MD5=y 870 | CONFIG_FEATURE_HTTPD_CGI=y 871 | CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y 872 | CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y 873 | CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y 874 | CONFIG_FEATURE_HTTPD_ERROR_PAGES=y 875 | CONFIG_FEATURE_HTTPD_PROXY=y 876 | CONFIG_FEATURE_HTTPD_GZIP=y 877 | CONFIG_IFCONFIG=y 878 | CONFIG_FEATURE_IFCONFIG_STATUS=y 879 | CONFIG_FEATURE_IFCONFIG_SLIP=y 880 | CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y 881 | CONFIG_FEATURE_IFCONFIG_HW=y 882 | CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y 883 | CONFIG_IFENSLAVE=y 884 | CONFIG_IFPLUGD=y 885 | CONFIG_IFUP=y 886 | CONFIG_IFDOWN=y 887 | CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" 888 | CONFIG_FEATURE_IFUPDOWN_IP=y 889 | CONFIG_FEATURE_IFUPDOWN_IPV4=y 890 | CONFIG_FEATURE_IFUPDOWN_IPV6=y 891 | CONFIG_FEATURE_IFUPDOWN_MAPPING=y 892 | # CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set 893 | CONFIG_INETD=y 894 | CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y 895 | CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y 896 | CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y 897 | CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y 898 | CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y 899 | # CONFIG_FEATURE_INETD_RPC is not set 900 | CONFIG_IP=y 901 | CONFIG_IPADDR=y 902 | CONFIG_IPLINK=y 903 | CONFIG_IPROUTE=y 904 | CONFIG_IPTUNNEL=y 905 | CONFIG_IPRULE=y 906 | CONFIG_IPNEIGH=y 907 | CONFIG_FEATURE_IP_ADDRESS=y 908 | CONFIG_FEATURE_IP_LINK=y 909 | CONFIG_FEATURE_IP_ROUTE=y 910 | CONFIG_FEATURE_IP_ROUTE_DIR="/etc/iproute2" 911 | CONFIG_FEATURE_IP_TUNNEL=y 912 | CONFIG_FEATURE_IP_RULE=y 913 | CONFIG_FEATURE_IP_NEIGH=y 914 | # CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set 915 | CONFIG_IPCALC=y 916 | CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y 917 | CONFIG_FEATURE_IPCALC_FANCY=y 918 | CONFIG_FAKEIDENTD=y 919 | CONFIG_NAMEIF=y 920 | CONFIG_FEATURE_NAMEIF_EXTENDED=y 921 | CONFIG_NBDCLIENT=y 922 | CONFIG_NC=y 923 | # CONFIG_NETCAT is not set 924 | CONFIG_NC_SERVER=y 925 | CONFIG_NC_EXTRA=y 926 | CONFIG_NC_110_COMPAT=y 927 | CONFIG_NETSTAT=y 928 | CONFIG_FEATURE_NETSTAT_WIDE=y 929 | CONFIG_FEATURE_NETSTAT_PRG=y 930 | CONFIG_NSLOOKUP=y 931 | CONFIG_FEATURE_NSLOOKUP_BIG=y 932 | CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS=y 933 | CONFIG_NTPD=y 934 | CONFIG_FEATURE_NTPD_SERVER=y 935 | CONFIG_FEATURE_NTPD_CONF=y 936 | CONFIG_FEATURE_NTP_AUTH=y 937 | CONFIG_PING=y 938 | CONFIG_PING6=y 939 | CONFIG_FEATURE_FANCY_PING=y 940 | CONFIG_PSCAN=y 941 | CONFIG_ROUTE=y 942 | CONFIG_SLATTACH=y 943 | CONFIG_SSL_CLIENT=y 944 | CONFIG_TC=y 945 | CONFIG_FEATURE_TC_INGRESS=y 946 | CONFIG_TCPSVD=y 947 | CONFIG_UDPSVD=y 948 | CONFIG_TELNET=y 949 | CONFIG_FEATURE_TELNET_TTYPE=y 950 | CONFIG_FEATURE_TELNET_AUTOLOGIN=y 951 | CONFIG_FEATURE_TELNET_WIDTH=y 952 | CONFIG_TELNETD=y 953 | CONFIG_FEATURE_TELNETD_STANDALONE=y 954 | CONFIG_FEATURE_TELNETD_INETD_WAIT=y 955 | CONFIG_TFTP=y 956 | CONFIG_FEATURE_TFTP_PROGRESS_BAR=y 957 | CONFIG_FEATURE_TFTP_HPA_COMPAT=y 958 | CONFIG_TFTPD=y 959 | CONFIG_FEATURE_TFTP_GET=y 960 | CONFIG_FEATURE_TFTP_PUT=y 961 | CONFIG_FEATURE_TFTP_BLOCKSIZE=y 962 | # CONFIG_TFTP_DEBUG is not set 963 | CONFIG_TLS=y 964 | CONFIG_TRACEROUTE=y 965 | CONFIG_TRACEROUTE6=y 966 | CONFIG_FEATURE_TRACEROUTE_VERBOSE=y 967 | CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y 968 | CONFIG_TUNCTL=y 969 | CONFIG_FEATURE_TUNCTL_UG=y 970 | CONFIG_VCONFIG=y 971 | CONFIG_WGET=y 972 | CONFIG_FEATURE_WGET_LONG_OPTIONS=y 973 | CONFIG_FEATURE_WGET_STATUSBAR=y 974 | CONFIG_FEATURE_WGET_AUTHENTICATION=y 975 | CONFIG_FEATURE_WGET_TIMEOUT=y 976 | CONFIG_FEATURE_WGET_HTTPS=y 977 | CONFIG_FEATURE_WGET_OPENSSL=y 978 | CONFIG_WHOIS=y 979 | CONFIG_ZCIP=y 980 | CONFIG_UDHCPD=y 981 | # CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set 982 | CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y 983 | CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" 984 | CONFIG_DUMPLEASES=y 985 | CONFIG_DHCPRELAY=y 986 | CONFIG_UDHCPC=y 987 | CONFIG_FEATURE_UDHCPC_ARPING=y 988 | CONFIG_FEATURE_UDHCPC_SANITIZEOPT=y 989 | CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" 990 | CONFIG_UDHCPC6=y 991 | CONFIG_FEATURE_UDHCPC6_RFC3646=y 992 | CONFIG_FEATURE_UDHCPC6_RFC4704=y 993 | CONFIG_FEATURE_UDHCPC6_RFC4833=y 994 | CONFIG_FEATURE_UDHCPC6_RFC5970=y 995 | 996 | # 997 | # Common options for DHCP applets 998 | # 999 | # CONFIG_FEATURE_UDHCP_PORT is not set 1000 | CONFIG_UDHCP_DEBUG=2 1001 | CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 1002 | CONFIG_FEATURE_UDHCP_RFC3397=y 1003 | CONFIG_FEATURE_UDHCP_8021Q=y 1004 | CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" 1005 | 1006 | # 1007 | # Print Utilities 1008 | # 1009 | CONFIG_LPD=y 1010 | CONFIG_LPR=y 1011 | CONFIG_LPQ=y 1012 | 1013 | # 1014 | # Mail Utilities 1015 | # 1016 | CONFIG_MAKEMIME=y 1017 | CONFIG_POPMAILDIR=y 1018 | CONFIG_FEATURE_POPMAILDIR_DELIVERY=y 1019 | CONFIG_REFORMIME=y 1020 | CONFIG_FEATURE_REFORMIME_COMPAT=y 1021 | CONFIG_SENDMAIL=y 1022 | CONFIG_FEATURE_MIME_CHARSET="us-ascii" 1023 | 1024 | # 1025 | # Process Utilities 1026 | # 1027 | CONFIG_FREE=y 1028 | CONFIG_FUSER=y 1029 | CONFIG_IOSTAT=y 1030 | CONFIG_KILL=y 1031 | CONFIG_KILLALL=y 1032 | CONFIG_KILLALL5=y 1033 | CONFIG_LSOF=y 1034 | CONFIG_MPSTAT=y 1035 | CONFIG_NMETER=y 1036 | CONFIG_PGREP=y 1037 | CONFIG_PKILL=y 1038 | CONFIG_PIDOF=y 1039 | CONFIG_FEATURE_PIDOF_SINGLE=y 1040 | CONFIG_FEATURE_PIDOF_OMIT=y 1041 | CONFIG_PMAP=y 1042 | CONFIG_POWERTOP=y 1043 | CONFIG_FEATURE_POWERTOP_INTERACTIVE=y 1044 | CONFIG_PS=y 1045 | CONFIG_FEATURE_PS_WIDE=y 1046 | CONFIG_FEATURE_PS_LONG=y 1047 | # CONFIG_FEATURE_PS_TIME is not set 1048 | # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set 1049 | # CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set 1050 | CONFIG_PSTREE=y 1051 | CONFIG_PWDX=y 1052 | CONFIG_SMEMCAP=y 1053 | CONFIG_BB_SYSCTL=y 1054 | CONFIG_TOP=y 1055 | CONFIG_FEATURE_TOP_INTERACTIVE=y 1056 | CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y 1057 | CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y 1058 | CONFIG_FEATURE_TOP_SMP_CPU=y 1059 | CONFIG_FEATURE_TOP_DECIMALS=y 1060 | CONFIG_FEATURE_TOP_SMP_PROCESS=y 1061 | CONFIG_FEATURE_TOPMEM=y 1062 | CONFIG_UPTIME=y 1063 | CONFIG_FEATURE_UPTIME_UTMP_SUPPORT=y 1064 | CONFIG_WATCH=y 1065 | CONFIG_FEATURE_SHOW_THREADS=y 1066 | 1067 | # 1068 | # Runit Utilities 1069 | # 1070 | CONFIG_CHPST=y 1071 | CONFIG_SETUIDGID=y 1072 | CONFIG_ENVUIDGID=y 1073 | CONFIG_ENVDIR=y 1074 | CONFIG_SOFTLIMIT=y 1075 | CONFIG_RUNSV=y 1076 | CONFIG_RUNSVDIR=y 1077 | # CONFIG_FEATURE_RUNSVDIR_LOG is not set 1078 | CONFIG_SV=y 1079 | CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" 1080 | CONFIG_SVC=y 1081 | CONFIG_SVOK=y 1082 | CONFIG_SVLOGD=y 1083 | # CONFIG_CHCON is not set 1084 | # CONFIG_GETENFORCE is not set 1085 | # CONFIG_GETSEBOOL is not set 1086 | # CONFIG_LOAD_POLICY is not set 1087 | # CONFIG_MATCHPATHCON is not set 1088 | # CONFIG_RUNCON is not set 1089 | # CONFIG_SELINUXENABLED is not set 1090 | # CONFIG_SESTATUS is not set 1091 | # CONFIG_SETENFORCE is not set 1092 | # CONFIG_SETFILES is not set 1093 | # CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set 1094 | # CONFIG_RESTORECON is not set 1095 | # CONFIG_SETSEBOOL is not set 1096 | 1097 | # 1098 | # Shells 1099 | # 1100 | CONFIG_SH_IS_ASH=y 1101 | # CONFIG_SH_IS_HUSH is not set 1102 | # CONFIG_SH_IS_NONE is not set 1103 | # CONFIG_BASH_IS_ASH is not set 1104 | # CONFIG_BASH_IS_HUSH is not set 1105 | CONFIG_BASH_IS_NONE=y 1106 | CONFIG_SHELL_ASH=y 1107 | CONFIG_ASH=y 1108 | CONFIG_ASH_OPTIMIZE_FOR_SIZE=y 1109 | CONFIG_ASH_INTERNAL_GLOB=y 1110 | CONFIG_ASH_BASH_COMPAT=y 1111 | # CONFIG_ASH_BASH_SOURCE_CURDIR is not set 1112 | CONFIG_ASH_BASH_NOT_FOUND_HOOK=y 1113 | CONFIG_ASH_JOB_CONTROL=y 1114 | CONFIG_ASH_ALIAS=y 1115 | CONFIG_ASH_RANDOM_SUPPORT=y 1116 | CONFIG_ASH_EXPAND_PRMT=y 1117 | CONFIG_ASH_IDLE_TIMEOUT=y 1118 | CONFIG_ASH_MAIL=y 1119 | CONFIG_ASH_ECHO=y 1120 | CONFIG_ASH_PRINTF=y 1121 | CONFIG_ASH_TEST=y 1122 | CONFIG_ASH_HELP=y 1123 | CONFIG_ASH_GETOPTS=y 1124 | CONFIG_ASH_CMDCMD=y 1125 | CONFIG_CTTYHACK=y 1126 | CONFIG_HUSH=y 1127 | CONFIG_SHELL_HUSH=y 1128 | CONFIG_HUSH_BASH_COMPAT=y 1129 | CONFIG_HUSH_BRACE_EXPANSION=y 1130 | CONFIG_HUSH_LINENO_VAR=y 1131 | # CONFIG_HUSH_BASH_SOURCE_CURDIR is not set 1132 | CONFIG_HUSH_INTERACTIVE=y 1133 | CONFIG_HUSH_SAVEHISTORY=y 1134 | CONFIG_HUSH_JOB=y 1135 | CONFIG_HUSH_TICK=y 1136 | CONFIG_HUSH_IF=y 1137 | CONFIG_HUSH_LOOPS=y 1138 | CONFIG_HUSH_CASE=y 1139 | CONFIG_HUSH_FUNCTIONS=y 1140 | CONFIG_HUSH_LOCAL=y 1141 | CONFIG_HUSH_RANDOM_SUPPORT=y 1142 | CONFIG_HUSH_MODE_X=y 1143 | CONFIG_HUSH_ECHO=y 1144 | CONFIG_HUSH_PRINTF=y 1145 | CONFIG_HUSH_TEST=y 1146 | CONFIG_HUSH_HELP=y 1147 | CONFIG_HUSH_EXPORT=y 1148 | CONFIG_HUSH_EXPORT_N=y 1149 | CONFIG_HUSH_READONLY=y 1150 | CONFIG_HUSH_KILL=y 1151 | CONFIG_HUSH_WAIT=y 1152 | CONFIG_HUSH_COMMAND=y 1153 | CONFIG_HUSH_TRAP=y 1154 | CONFIG_HUSH_TYPE=y 1155 | CONFIG_HUSH_TIMES=y 1156 | CONFIG_HUSH_READ=y 1157 | CONFIG_HUSH_SET=y 1158 | CONFIG_HUSH_UNSET=y 1159 | CONFIG_HUSH_ULIMIT=y 1160 | CONFIG_HUSH_UMASK=y 1161 | CONFIG_HUSH_GETOPTS=y 1162 | # CONFIG_HUSH_MEMLEAK is not set 1163 | 1164 | # 1165 | # Options common to all shells 1166 | # 1167 | CONFIG_FEATURE_SH_MATH=y 1168 | CONFIG_FEATURE_SH_MATH_64=y 1169 | CONFIG_FEATURE_SH_MATH_BASE=y 1170 | CONFIG_FEATURE_SH_EXTRA_QUIET=y 1171 | # CONFIG_FEATURE_SH_STANDALONE is not set 1172 | # CONFIG_FEATURE_SH_NOFORK is not set 1173 | CONFIG_FEATURE_SH_READ_FRAC=y 1174 | CONFIG_FEATURE_SH_HISTFILESIZE=y 1175 | CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y 1176 | 1177 | # 1178 | # System Logging Utilities 1179 | # 1180 | CONFIG_KLOGD=y 1181 | 1182 | # 1183 | # klogd should not be used together with syslog to kernel printk buffer 1184 | # 1185 | CONFIG_FEATURE_KLOGD_KLOGCTL=y 1186 | CONFIG_LOGGER=y 1187 | CONFIG_LOGREAD=y 1188 | CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y 1189 | CONFIG_SYSLOGD=y 1190 | CONFIG_FEATURE_ROTATE_LOGFILE=y 1191 | CONFIG_FEATURE_REMOTE_LOG=y 1192 | CONFIG_FEATURE_SYSLOGD_DUP=y 1193 | CONFIG_FEATURE_SYSLOGD_CFG=y 1194 | # CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set 1195 | CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 1196 | CONFIG_FEATURE_IPC_SYSLOG=y 1197 | CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 1198 | CONFIG_FEATURE_KMSG_SYSLOG=y 1199 | -------------------------------------------------------------------------------- /doslinux.asm: -------------------------------------------------------------------------------- 1 | org 0x100 2 | 3 | %define DOSLINUX_INT 0xe7 4 | 5 | ; get current default drive 6 | mov ah, 0x19 7 | int 0x21 8 | add al, 'a' ; interrupt returns drive index, not letter in AL 9 | mov [current_drive], al 10 | 11 | ; get current directory, returns pointer to ASCIZ string in DS:SI 12 | mov ah, 0x47 13 | xor dl, dl ; default drive 14 | mov si, current_dir_buffer 15 | int 0x21 16 | 17 | ; detect XMS (eg HIMEM.SYS) and bail if present 18 | mov ax, 0x4300 19 | int 0x2f 20 | cmp al, 0x80 21 | jne no_xms 22 | 23 | ; print error message if XMS found 24 | mov dx, xms_not_supported 25 | mov ah, 0x09 26 | int 0x21 27 | 28 | ; exit 29 | mov ah, 0x4c 30 | int 0x21 31 | 32 | no_xms: 33 | ; detect already running instance of WSL 34 | call detect_dsl 35 | test ax, ax 36 | jz start_linux 37 | 38 | run_command: 39 | ; doslinux is already running, prepare to run linux command 40 | 41 | ; flush disk first 42 | mov ah, 0x0d 43 | int 0x21 44 | 45 | ; invoke the run command syscall 46 | mov ah, 1 47 | mov dl, [current_drive] 48 | mov si, current_dir_buffer 49 | int DOSLINUX_INT 50 | 51 | ; replicate linux cursor position in BIOS 52 | call fix_cursor 53 | 54 | ; exit 55 | mov ah, 0x4c 56 | int 0x21 57 | 58 | start_linux: 59 | ; open bzimage.com 60 | mov ax, 0x3d00 61 | mov dx, bzimage_path 62 | int 0x21 63 | 64 | ; check error 65 | mov dx, bzimage_open_err 66 | jc fatal 67 | 68 | ; store file handle 69 | mov [bzimage_handle], ax 70 | 71 | ; read first sector of bzimage 72 | mov ah, 0x3f 73 | mov dx, bzimage 74 | mov bx, [bzimage_handle] 75 | mov cx, 512 76 | int 0x21 77 | 78 | ; check error 79 | mov dx, bzimage_read_err 80 | jc fatal 81 | 82 | ; pull setup_sects value from header 83 | movzx ax, byte [k_setup_sects_b] 84 | shl ax, 9 ; multiply by 512 to get byte count from sector count 85 | mov [setup_bytes], ax 86 | 87 | ; read remaining setup code 88 | mov ah, 0x3f 89 | mov dx, bzimage + 512 90 | mov bx, [bzimage_handle] 91 | mov cx, [setup_bytes] 92 | int 0x21 93 | 94 | ; check error 95 | mov dx, bzimage_read_err 96 | jc fatal 97 | 98 | ; check magic header value 99 | mov eax, [k_header_magic_d] 100 | cmp eax, 0x53726448 ; 'HdrS' 101 | mov dx, not_kernel_err 102 | jne fatal 103 | 104 | ; pull syssize from header - count of 16 byte paras of system code after setup 105 | mov eax, [k_syssize_d] 106 | shl eax, 4 ; multiply by 16 to get bytes 107 | mov [sys_bytes], eax 108 | 109 | ; calculate sys_load_end pointer 110 | add eax, [sys_load_ptr] 111 | mov [sys_load_end], eax 112 | 113 | ; init unreal mode switching in prep for loading kernel to extended memory 114 | call init_unreal 115 | 116 | .sys_load_loop: 117 | mov ah, 0x3f 118 | mov dx, readbuf 119 | mov bx, [bzimage_handle] 120 | mov cx, READBUF_SIZE 121 | int 0x21 122 | 123 | ; check error 124 | mov dx, bzimage_read_err 125 | jc fatal 126 | 127 | ; do unreal copy 128 | mov si, readbuf 129 | mov edi, [sys_load_ptr] 130 | mov ecx, READBUF_SIZE 131 | call copy_unreal 132 | 133 | ; advance load pointer 134 | add dword [sys_load_ptr], READBUF_SIZE 135 | 136 | ; loop around again if more to read 137 | mov eax, [sys_load_ptr] 138 | cmp eax, [sys_load_end] 139 | jb .sys_load_loop 140 | 141 | ; finished reading kernel, set obligatory kernel params: 142 | 143 | ; use our current video mode for kernel vidmode parameter 144 | mov [k_vidmode_w], word 0 145 | 146 | ; we are not a registered bootloader 147 | mov byte [k_type_of_loader_b], 0xff 148 | 149 | ; set load flags 150 | %define LOADED_HIGH_FLAG 0x01 151 | %define CAN_USE_HEAP_FLAG 0x80 152 | mov byte [k_loadflags_b], LOADED_HIGH_FLAG | CAN_USE_HEAP_FLAG 153 | 154 | ; no ramdisk 155 | mov dword [k_ramdisk_size_d], 0 156 | mov dword [k_ramdisk_image_d], 0 157 | 158 | ; set heap end pointer - TODO is this correct? 159 | %define HEAP_END 0xe000 160 | mov word [k_heap_end_ptr_w], HEAP_END 161 | 162 | ; copy cmd line into place 163 | mov si, cmdline 164 | mov di, bzimage + HEAP_END 165 | mov cx, cmdline.end - cmdline 166 | rep movsb 167 | ; now calculate linear address for pointer 168 | mov ax, ds 169 | movzx eax, ax 170 | shl eax, 4 171 | mov ebx, bzimage + HEAP_END 172 | add ebx, eax 173 | mov [k_cmd_line_ptr_d], ebx 174 | 175 | ; set kernel boot params relevant to relocation 176 | mov dword [k_code32_start_d], kernel_base 177 | 178 | ; write CS:IP of vm86_return into somewhere init can grab it from 179 | call enter_unreal 180 | push es 181 | mov ax, 0x08 182 | mov es, ax 183 | 184 | a32 mov [es:0x100000], word vm86_return 185 | 186 | mov ax, cs 187 | a32 mov [es:0x100002], word ax 188 | 189 | pushf 190 | pop ax 191 | a32 mov [es:0x100004], word ax 192 | 193 | a32 mov [es:0x100006], sp 194 | 195 | mov ax, ss 196 | a32 mov [es:0x100008], word ax 197 | 198 | call exit_unreal 199 | pop es 200 | 201 | ; print initializing message right before starting kernel 202 | mov dx, initializing 203 | mov ah, 0x09 204 | int 0x21 205 | 206 | ; calculate kernel segment 207 | mov ax, ds 208 | movzx eax, ax 209 | shl eax, 4 210 | add eax, bzimage 211 | shr eax, 4 212 | 213 | ; disable interrupts and setup segments/stack 214 | cli 215 | mov ss, ax 216 | mov sp, HEAP_END 217 | mov ds, ax 218 | mov es, ax 219 | mov fs, ax 220 | mov gs, ax 221 | 222 | ; enter kernel 223 | ; see https://www.kernel.org/doc/html/latest/x86/boot.html#running-the-kernel 224 | 225 | ; kernel code seg is + 0x20 226 | add ax, 0x20 227 | 228 | ; since the segment is dynamic we need an indirect jump 229 | mov bx, sp 230 | sub bx, 4 231 | mov [bx], word 0 232 | mov [bx + 2], ax 233 | jmp far [bx] 234 | 235 | vm86_return: 236 | ; now DSL is running we can run the originally invoked command 237 | jmp run_command 238 | 239 | ; 240 | ; helper subroutines 241 | ; 242 | 243 | ; print error message and exit 244 | fatal: 245 | mov ah, 0x09 246 | int 0x21 247 | mov ah, 0x4c 248 | int 0x21 249 | 250 | ; initialize unreal mode switching 251 | init_unreal: 252 | ; setup gdt offset in gdtr 253 | mov eax, ds 254 | shl eax, 4 255 | add eax, gdt 256 | mov [gdtr.offset], eax 257 | 258 | ret 259 | 260 | ; copy from low to extended memory (> 1 MiB) 261 | ; DS:ESI - source (far pointer) 262 | ; EDI - destination (linear address) 263 | ; ECX - byte count 264 | ; clobbers EAX 265 | copy_unreal: 266 | ; zero high bits of ESI 267 | movzx eax, si 268 | mov esi, eax 269 | 270 | ; save ds/es and load 32 bit segment selectors 271 | call enter_unreal 272 | push es 273 | mov ax, 0x08 274 | mov es, ax 275 | 276 | ; copy 4 bytes at a time: 277 | add ecx, 3 278 | shr ecx, 2 279 | 280 | ; do the copy, using 32 bit address override 281 | a32 rep movsd 282 | 283 | ; restore ds/es 284 | call exit_unreal 285 | pop es 286 | 287 | ret 288 | 289 | enter_unreal: 290 | ; load gdt to prepare to enter protected mode 291 | cli 292 | lgdt [gdtr] 293 | 294 | ; enable protected mode 295 | mov eax, cr0 296 | or al, 1 297 | mov cr0, eax 298 | 299 | ret 300 | 301 | exit_unreal: 302 | ; disable protected mode 303 | mov eax, cr0 304 | and al, ~1 305 | mov cr0, eax 306 | 307 | ret 308 | 309 | ; returns line VGA cursor is on in AL, 0 indexed 310 | ; clobbers DX and BX 311 | cursor_line: 312 | ; read cursor pos into bx from vga 313 | mov al, 0x0f 314 | mov dx, 0x3d4 315 | out dx, al 316 | 317 | mov dx, 0x3d5 318 | in al, dx 319 | mov bl, al 320 | 321 | mov al, 0x0e 322 | mov dx, 0x3d4 323 | out dx, al 324 | 325 | mov dx, 0x3d5 326 | in al, dx 327 | mov bh, al 328 | 329 | ; calculate line 330 | mov ax, bx 331 | xor dx, dx 332 | add ax, 79 ; for round-up division 333 | mov bx, 80 334 | div bx 335 | 336 | xor ah, ah 337 | 338 | ret 339 | 340 | ; replicate VGA cursor pos in BIOS 341 | fix_cursor: 342 | call cursor_line 343 | 344 | mov dh, al ; line number 345 | xor dl, dl ; column 346 | xor bh, bh ; page number (?) 347 | mov ah, 0x02 ; set cursor pos 348 | int 0x10 349 | 350 | ret 351 | 352 | 353 | ; detects running DSL instance 354 | ; returns 1 if running in AX, 0 otherwise 355 | detect_dsl: 356 | ; push flags and disable interrupts before we do anything dodgy 357 | pushf 358 | cli 359 | 360 | ; set fs to zero to access IVT 361 | push fs 362 | xor ax, ax 363 | mov fs, ax 364 | 365 | ; save previous handler for doslinux interrupt 366 | mov ax, [fs:DOSLINUX_INT * 4] 367 | push ax 368 | mov ax, [fs:DOSLINUX_INT * 4 + 2] 369 | push ax 370 | 371 | ; set up dummy interrupt handler so we don't crash or invoke any 372 | ; unintended behaviour when calling the doslinux interrupt 373 | mov [fs:DOSLINUX_INT * 4], word .dummy_handler 374 | mov ax, cs 375 | mov [fs:DOSLINUX_INT * 4 + 2], ax 376 | 377 | ; hit it 378 | xor ax, ax 379 | int DOSLINUX_INT 380 | mov [.is_running], ax 381 | 382 | ; restore previous interrupt handler 383 | pop ax 384 | mov [fs:DOSLINUX_INT * 4 + 2], ax 385 | pop ax 386 | mov [fs:DOSLINUX_INT * 4], ax 387 | 388 | ; restore previous fs 389 | pop fs 390 | 391 | ; restore flags 392 | popf 393 | 394 | ; test ax 395 | mov ax, [.is_running] 396 | 397 | ret 398 | 399 | .is_running dw 0 400 | 401 | .dummy_handler: 402 | mov [.is_running], word 0 403 | iret 404 | 405 | ; 406 | ; RO data 407 | ; 408 | 409 | xms_not_supported db "Extended memory manager detected (maybe HIMEM.SYS?) - cannot start DOS Subsystem for Linux", 13, 10, "$" 410 | bzimage_path db "C:\doslinux\bzimage", 0 411 | bzimage_open_err db "Could not open bzImage", 13, 10, "$" 412 | bzimage_read_err db "Could not read bzImage", 13, 10, "$" 413 | not_kernel_err db "bzImage is not a Linux kernel", 13, 10, "$" 414 | initializing db "Starting DOS Subsystem for Linux, please wait...$" 415 | newline db 13, 10, "$" 416 | 417 | ; reserve entire low memory region 418 | cmdline: db "quiet init=/doslinux/init root=/dev/sda1 " 419 | 420 | ; kernel should scroll in software rather than hardware, DOS/BIOS 421 | ; only scrolls in software: 422 | db "nomodeset no-scroll " 423 | 424 | ; reserve low 640k (the maximum) to keep DOS intact during boot 425 | db "reservelow=655360 " 426 | 427 | ; mark phys memory from 0x100000-0x110000 as reserved, we may 428 | ; use high memory area in DOS 429 | db "memmap=64K$0x100000 " 430 | 431 | ; disable kernel PAT support - PAT imposes aliasing restrictions on 432 | ; physical memory pages which cause our mmap of all conventional 433 | ; memory to fail 434 | db "nopat " 435 | 436 | db 0 437 | .end: 438 | 439 | gdt: 440 | ; entry 0x00 : null 441 | dq 0 442 | 443 | ; data entry 444 | dw 0xffff ; limit 0:15 445 | .data_base_0_w: 446 | dw 0x0000 ; base 0:15 447 | .data_base_16_b: 448 | db 0x00 ; base 16:23 449 | db 0b10010010 ; access byte - data 450 | db 0xcf ; flags/(limit 16:19). 4 KB granularity + 32 bit mode flags 451 | .data_base_24_b: 452 | db 0x00 ; base 24:31 453 | .end: 454 | 455 | ; 456 | ; variables 457 | ; 458 | 459 | align 4 460 | 461 | bzimage_handle: dw 0 462 | setup_bytes: dw 0 463 | heap_end: dw 0 464 | 465 | align 4 466 | sys_bytes: dd 0 467 | sys_load_ptr: dd kernel_base 468 | sys_load_end: dd 0 469 | 470 | current_drive: db 0 471 | current_dir_buffer: times 64 db 0 472 | 473 | align 4 474 | gdtr: 475 | dw gdt.end - gdt - 1 476 | .offset: 477 | dd 0 478 | 479 | ; 480 | ; constants 481 | ; 482 | 483 | kernel_base equ 0x200000 484 | 485 | ; kernel real mode header fields 486 | ; see https://www.kernel.org/doc/html/latest/x86/boot.html#the-real-mode-kernel-header 487 | k_setup_sects_b equ bzimage + 0x1f1 488 | k_syssize_d equ bzimage + 0x1f4 489 | k_header_magic_d equ bzimage + 0x202 490 | 491 | ; obligatory fields - we must supply this information to kernel 492 | k_vidmode_w equ bzimage + 0x1fa 493 | k_type_of_loader_b equ bzimage + 0x210 494 | k_loadflags_b equ bzimage + 0x211 495 | k_setup_move_size_w equ bzimage + 0x212 496 | k_ramdisk_image_d equ bzimage + 0x218 497 | k_ramdisk_size_d equ bzimage + 0x21c 498 | k_heap_end_ptr_w equ bzimage + 0x224 499 | k_ext_loader_type_b equ bzimage + 0x227 500 | k_cmd_line_ptr_d equ bzimage + 0x228 501 | 502 | ; reloc fields - we must supply if kernel is relocated 503 | k_code32_start_d equ bzimage + 0x214 504 | k_kernel_alignment_d equ bzimage + 0x230 505 | k_relocatable_kernel_b equ bzimage + 0x234 506 | k_min_alignment_b equ bzimage + 0x235 507 | k_pref_address_q equ bzimage + 0x258 508 | 509 | 510 | align 16 511 | progend: 512 | 513 | READBUF_SIZE equ 4096 514 | 515 | readbuf equ progend 516 | bzimage equ progend + READBUF_SIZE 517 | -------------------------------------------------------------------------------- /init/init.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | // #include 17 | 18 | #include "vm86.h" 19 | #include "panic.h" 20 | 21 | #define CHECKED(expr) { if ((rc = (expr)) < 0) { goto out; } } 22 | 23 | int copy_file(const char* src, const char* dst) { 24 | int rc, src_fd = -1, dst_fd = -1; 25 | struct stat st; 26 | 27 | CHECKED(src_fd = open(src, O_RDONLY | O_CLOEXEC)); 28 | CHECKED(fstat(src_fd, &st)); 29 | CHECKED(dst_fd = open(dst, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, st.st_mode)); 30 | 31 | size_t len = st.st_size; 32 | 33 | while (len > 0) { 34 | ssize_t copied = 0; 35 | CHECKED(copied = copy_file_range(src_fd, NULL, dst_fd, NULL, len, 0)); 36 | len -= copied; 37 | } 38 | 39 | rc = 0; 40 | 41 | out: 42 | if (src_fd >= 0) { 43 | close(src_fd); 44 | } 45 | 46 | if (dst_fd >= 0) { 47 | close(dst_fd); 48 | } 49 | 50 | return rc; 51 | } 52 | 53 | int install_busybox() { 54 | pid_t install_pid = fork(); 55 | 56 | if (install_pid < 0) { 57 | return install_pid; 58 | } 59 | 60 | if (install_pid == 0) { 61 | char busybox[] = "/bin/busybox"; 62 | char install[] = "--install"; 63 | char* argv[] = { busybox, install, NULL }; 64 | execve(busybox, argv, NULL); 65 | perror("execve"); 66 | exit(errno); 67 | } 68 | 69 | while (1) { 70 | int rc, wstat; 71 | 72 | if ((rc = waitpid(install_pid, &wstat, 0)) < 0) { 73 | return rc; 74 | } 75 | 76 | if (WIFEXITED(wstat)) { 77 | return WEXITSTATUS(wstat); 78 | } 79 | } 80 | } 81 | 82 | void initialize() { 83 | // remount hard drive as rw and sync 84 | // sync is needed so that linux does not defer disk writes and MS-DOS can 85 | // see them immediately 86 | if (mount("", "/", "vfat", MS_REMOUNT | MS_SYNCHRONOUS, NULL)) { 87 | fatal("remount root"); 88 | } 89 | 90 | // setup ramdisk for root partition 91 | // TODO - maybe a persistent ext4 fs on a loop device? 92 | 93 | if (mount("", "/doslinux/rootfs", "ramfs", 0, NULL)) { 94 | fatal("mount ramfs"); 95 | } 96 | 97 | // setup procfs 98 | 99 | if (mkdir("/doslinux/rootfs/proc", 0755)) { 100 | fatal("mkdir /proc"); 101 | } 102 | 103 | if (mount("", "/doslinux/rootfs/proc", "proc", 0, NULL)) { 104 | fatal("mount /proc"); 105 | } 106 | 107 | // setup bin and copy busybox into place 108 | 109 | if (mkdir("/doslinux/rootfs/bin", 0755)) { 110 | fatal("mkdir /bin"); 111 | } 112 | 113 | if (copy_file("/doslinux/busybox", "/doslinux/rootfs/bin/busybox")) { 114 | fatal("copy busybox"); 115 | } 116 | 117 | // setup mnt and pivot root 118 | 119 | if (mkdir("/doslinux/rootfs/mnt", 0755)) { 120 | fatal("mkdir /mnt"); 121 | } 122 | 123 | if (mkdir("/doslinux/rootfs/mnt/c", 0755)) { 124 | fatal("mkdir /mnt/c"); 125 | } 126 | 127 | if (syscall(SYS_pivot_root, "/doslinux/rootfs", "/doslinux/rootfs/mnt/c")) { 128 | fatal("pivot_root"); 129 | } 130 | 131 | // setup remaining bin dirs and install busybox 132 | 133 | if (mkdir("/sbin", 0755)) { 134 | fatal("mkdir /sbin"); 135 | } 136 | 137 | if (mkdir("/usr", 0755)) { 138 | fatal("mkdir /usr"); 139 | } 140 | 141 | if (mkdir("/usr/bin", 0755)) { 142 | fatal("mkdir /usr/bin"); 143 | } 144 | 145 | if (mkdir("/usr/sbin", 0755)) { 146 | fatal("mkdir /usr/sbin"); 147 | } 148 | 149 | if (install_busybox()) { 150 | fatal("install busybox"); 151 | } 152 | 153 | // setup /dev 154 | 155 | if (mkdir("/dev", 0755)) { 156 | fatal("mkdir /dev"); 157 | } 158 | 159 | if (mknod("/dev/mem", S_IFCHR | 0600, makedev(1, 1))) { 160 | fatal("mknod mem"); 161 | } 162 | 163 | if (mknod("/dev/ttyS0", S_IFCHR | 0600, makedev(4, 64))) { 164 | fatal("mknod ttyS0"); 165 | } 166 | } 167 | 168 | int run_vmm() { 169 | // open /dev/mem for mapping 170 | int memfd = open("/dev/mem", O_RDWR | O_SYNC); 171 | if (memfd < 0) { 172 | perror("open mem"); 173 | return -1; 174 | } 175 | 176 | // map the entire first MiB of memory in :) 177 | if (mmap(0, 0x110000, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, memfd, 0) == MAP_FAILED) { 178 | perror("mmap"); 179 | return -1; 180 | } 181 | 182 | vm86_init_t* dos = (void*)0x100000; 183 | vm86_run(*dos); 184 | } 185 | 186 | int exec_console() { 187 | int rc, fd; 188 | 189 | CHECKED(fd = open("/dev/ttyS0", O_RDWR)); 190 | 191 | CHECKED(dup2(fd, 0)); 192 | CHECKED(dup2(fd, 1)); 193 | CHECKED(dup2(fd, 2)); 194 | 195 | CHECKED(close(fd)); 196 | 197 | char sh[] = "sh"; 198 | char* argv[] = { sh, NULL }; 199 | 200 | char path[] = "PATH=/usr/bin:/usr/sbin:/bin:/sbin"; 201 | char* envp[] = { path, NULL }; 202 | rc = execve("/bin/busybox", argv, envp); 203 | 204 | out: 205 | return rc; 206 | } 207 | 208 | int main() { 209 | initialize(); 210 | 211 | printf(" ok\n"); 212 | 213 | pid_t rc; 214 | 215 | // fork control shell 216 | rc = fork(); 217 | 218 | if (rc < 0) { 219 | perror("fork"); 220 | } 221 | 222 | if (rc == 0) { 223 | exec_console(); 224 | fatal("run console"); 225 | } 226 | 227 | // fork vmm 228 | rc = fork(); 229 | 230 | if (rc < 0) { 231 | perror("fork"); 232 | } 233 | 234 | if (rc == 0) { 235 | run_vmm(); 236 | perror("run vmm"); 237 | } 238 | 239 | while (1) { 240 | int wstat; 241 | int rc = wait(&wstat); 242 | if (rc < 0) { 243 | fatal("wait"); 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /init/kbd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kbd.h" 9 | #include "panic.h" 10 | #include "vm86.h" 11 | 12 | #define KBD_DATA_PORT 0x60 13 | #define KBD_STATUS_PORT 0x64 14 | 15 | #define KBD_STATUS_HAS_DATA 0x01 16 | #define KBD_STATUS_SYSTEM 0x04 17 | 18 | static void process_key(kbd_t* kbd, uint8_t key); 19 | 20 | void 21 | kbd_init(kbd_t* kbd) 22 | { 23 | memset(kbd->keybuff, 0, sizeof(kbd->keybuff)); 24 | kbd->keybuff_len = 0; 25 | } 26 | 27 | void 28 | kbd_send_input(kbd_t* kbd, uint8_t scancode) 29 | { 30 | process_key(kbd, scancode); 31 | } 32 | 33 | // Glue code for BIOS keyboard services: 34 | 35 | static uint8_t 36 | enqueue_key(kbd_t* kbd, uint16_t keycode) 37 | { 38 | if (kbd->keybuff_len == KBD_BUFFER_SIZE) { 39 | // buffer full, drop input 40 | return 0; 41 | } 42 | 43 | kbd->keybuff[kbd->keybuff_len++] = keycode; 44 | return 1; 45 | } 46 | 47 | static void 48 | wait_for_key(kbd_t* kbd) 49 | { 50 | // wait for stdin to become ready 51 | while (1) { 52 | struct pollfd fds = { .fd = 0, .events = POLLIN, .revents = 0 }; 53 | int rc = poll(&fds, 1, -1); 54 | 55 | if (rc < 0) { 56 | if (errno == EAGAIN) { 57 | continue; 58 | } 59 | 60 | perror("kbd poll"); 61 | return; 62 | } 63 | 64 | if (rc > 0) { 65 | break; 66 | } 67 | } 68 | 69 | // read from stdin 70 | while (1) { 71 | char scan; 72 | ssize_t rc = read(0, &scan, 1); 73 | 74 | if (rc < 0) { 75 | if (errno == EAGAIN) { 76 | continue; 77 | } 78 | 79 | perror("kbd read"); 80 | return; 81 | } 82 | 83 | if (rc == 0) { 84 | // eof? 85 | return; 86 | } 87 | 88 | kbd_send_input(kbd, scan); 89 | } 90 | } 91 | 92 | static void 93 | reset() 94 | { 95 | // TODO ask linux to reset machine 96 | fprintf(stderr, "RESET\r\n"); 97 | halt(); 98 | } 99 | 100 | // BIOS keyboard services follow from here 101 | // Code from SeaBIOS kbd.c 102 | // 103 | // Copyright (C) 2008 Kevin O'Connor 104 | // Copyright (C) 2002 MandrakeSoft S.A. 105 | // 106 | // Code following this comment may be distributed under the terms of the 107 | // GNU LGPLv3 license. 108 | 109 | // BDA kbd_flag[01] bitdefs 110 | #define KF0_RSHIFT (1<<0) 111 | #define KF0_LSHIFT (1<<1) 112 | #define KF0_CTRLACTIVE (1<<2) 113 | #define KF0_ALTACTIVE (1<<3) 114 | #define KF0_SCROLLACTIVE (1<<4) 115 | #define KF0_NUMACTIVE (1<<5) 116 | #define KF0_CAPSACTIVE (1<<6) 117 | #define KF0_LCTRL (1<<8) 118 | #define KF0_LALT (1<<9) 119 | #define KF0_PAUSEACTIVE (1<<11) 120 | #define KF0_SCROLL (1<<12) 121 | #define KF0_NUM (1<<13) 122 | #define KF0_CAPS (1<<14) 123 | 124 | #define KF1_LAST_E1 (1<<0) 125 | #define KF1_LAST_E0 (1<<1) 126 | #define KF1_RCTRL (1<<2) 127 | #define KF1_RALT (1<<3) 128 | #define KF1_101KBD (1<<4) 129 | 130 | typedef uint8_t u8; 131 | typedef uint16_t u16; 132 | 133 | static struct { 134 | u8 kbd_flag0; 135 | u8 kbd_flag1; 136 | u8 kbd_led; 137 | u16 soft_reset_flag; 138 | } _bda; 139 | 140 | #define GET_BDA(x) _bda.x 141 | #define SET_BDA(x,y) _bda.x = (y); 142 | #define GET_GLOBAL(x) x 143 | #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 144 | 145 | static void 146 | dequeue_key(kbd_t* kbd, regs_t* regs, int incr, int extended) 147 | { 148 | for (;;) { 149 | if (kbd->keybuff_len > 0) { 150 | break; 151 | } 152 | 153 | if (!incr) { 154 | regs->eflags.word.lo |= FLAG_ZERO; 155 | return; 156 | } 157 | 158 | wait_for_key(kbd); 159 | } 160 | 161 | uint16_t keycode = kbd->keybuff[0]; 162 | uint8_t ascii = keycode & 0xff; 163 | 164 | if (!extended) { 165 | // Translate extended keys 166 | if (ascii == 0xe0 && keycode & 0xff00) 167 | keycode &= 0xff00; 168 | else if (keycode == 0xe00d || keycode == 0xe00a) 169 | // Extended enter key 170 | keycode = 0x1c00 | ascii; 171 | else if (keycode == 0xe02f) 172 | // Extended '/' key 173 | keycode = 0x352f; 174 | // Technically, if the ascii value is 0xf0 or if the 175 | // 'scancode' is greater than 0x84 then the key should be 176 | // discarded. However, there seems no harm in passing on the 177 | // extended values in these cases. 178 | } 179 | if (ascii == 0xf0 && keycode & 0xff00) 180 | keycode &= 0xff00; 181 | regs->eax.word.lo = keycode; 182 | 183 | if (!incr) { 184 | regs->eflags.word.lo &= ~FLAG_ZERO; 185 | return; 186 | } 187 | 188 | kbd->keybuff_len--; 189 | memmove(kbd->keybuff, &kbd->keybuff[1], kbd->keybuff_len * sizeof(kbd->keybuff[0])); 190 | } 191 | 192 | 193 | // Handle a ps2 style scancode read from the keyboard. 194 | static void 195 | kbd_set_flag(int key_release, u16 set_bit0, u8 set_bit1, u16 toggle_bit) 196 | { 197 | u16 flags0 = GET_BDA(kbd_flag0); 198 | u8 flags1 = GET_BDA(kbd_flag1); 199 | if (key_release) { 200 | flags0 &= ~set_bit0; 201 | flags1 &= ~set_bit1; 202 | } else { 203 | flags0 ^= toggle_bit; 204 | flags0 |= set_bit0; 205 | flags1 |= set_bit1; 206 | } 207 | SET_BDA(kbd_flag0, flags0); 208 | SET_BDA(kbd_flag1, flags1); 209 | } 210 | 211 | static void 212 | kbd_ctrl_break(int key_release) 213 | { 214 | // TODO 215 | (void)key_release; 216 | 217 | // if (!key_release) 218 | // return; 219 | // // Clear keyboard buffer and place 0x0000 in buffer 220 | // u16 buffer_start = GET_BDA(kbd_buf_start_offset); 221 | // SET_BDA(kbd_buf_head, buffer_start); 222 | // SET_BDA(kbd_buf_tail, buffer_start+2); 223 | // SET_FARVAR(SEG_BDA, *(u16*)(buffer_start+0), 0x0000); 224 | // // Set break flag 225 | // SET_BDA(break_flag, 0x80); 226 | // // Generate int 0x1b 227 | // struct bregs br; 228 | // memset(&br, 0, sizeof(br)); 229 | // br.flags = F_IF; 230 | // call16_int(0x1b, &br); 231 | } 232 | 233 | static void 234 | kbd_sysreq(int key_release) 235 | { 236 | // TODO 237 | (void)key_release; 238 | 239 | // // SysReq generates int 0x15/0x85 240 | // struct bregs br; 241 | // memset(&br, 0, sizeof(br)); 242 | // br.ah = 0x85; 243 | // br.al = key_release ? 0x01 : 0x00; 244 | // br.flags = F_IF; 245 | // call16_int(0x15, &br); 246 | } 247 | 248 | static void 249 | kbd_prtscr(int key_release) 250 | { 251 | // TODO 252 | (void)key_release; 253 | 254 | // if (key_release) 255 | // return; 256 | // // PrtScr generates int 0x05 (ctrl-prtscr has keycode 0x7200?) 257 | // struct bregs br; 258 | // memset(&br, 0, sizeof(br)); 259 | // br.flags = F_IF; 260 | // call16_int(0x05, &br); 261 | } 262 | 263 | // read keyboard input 264 | static void 265 | handle_1600(kbd_t* kbd, regs_t* regs) 266 | { 267 | dequeue_key(kbd, regs, 1, 0); 268 | } 269 | 270 | // check keyboard status 271 | static void 272 | handle_1601(kbd_t* kbd, regs_t* regs) 273 | { 274 | dequeue_key(kbd, regs, 0, 0); 275 | } 276 | 277 | // get shift flag status 278 | static void 279 | handle_1602(kbd_t* kbd, regs_t* regs) 280 | { 281 | (void)kbd; 282 | regs->eax.byte.lo = GET_BDA(kbd_flag0); 283 | } 284 | 285 | // store key-stroke into buffer 286 | static void 287 | handle_1605(kbd_t* kbd, regs_t* regs) 288 | { 289 | regs->eax.byte.lo = !enqueue_key(kbd, regs->ecx.word.lo); 290 | } 291 | 292 | // GET KEYBOARD FUNCTIONALITY 293 | static void 294 | handle_1609(kbd_t* kbd, regs_t* regs) 295 | { 296 | (void)kbd; 297 | 298 | // bit Bochs Description 299 | // 7 0 reserved 300 | // 6 0 INT 16/AH=20h-22h supported (122-key keyboard support) 301 | // 5 1 INT 16/AH=10h-12h supported (enhanced keyboard support) 302 | // 4 1 INT 16/AH=0Ah supported 303 | // 3 0 INT 16/AX=0306h supported 304 | // 2 0 INT 16/AX=0305h supported 305 | // 1 0 INT 16/AX=0304h supported 306 | // 0 0 INT 16/AX=0300h supported 307 | // 308 | regs->eax.byte.lo = 0x30; 309 | } 310 | 311 | // GET KEYBOARD ID 312 | static void 313 | handle_160a(kbd_t* kbd, regs_t* regs) 314 | { 315 | (void)kbd; 316 | (void)regs; 317 | 318 | fprintf(stderr, "GET KEYBOARD ID\r\n"); 319 | // u8 param[2]; 320 | // int ret = kbd_command(ATKBD_CMD_GETID, param); 321 | // if (ret) { 322 | // regs->bx = 0; 323 | // return; 324 | // } 325 | // regs->bx = (param[1] << 8) | param[0]; 326 | } 327 | 328 | // read MF-II keyboard input 329 | static void 330 | handle_1610(kbd_t* kbd, regs_t* regs) 331 | { 332 | dequeue_key(kbd, regs, 1, 1); 333 | } 334 | 335 | // check MF-II keyboard status 336 | static void 337 | handle_1611(kbd_t* kbd, regs_t* regs) 338 | { 339 | dequeue_key(kbd, regs, 0, 1); 340 | } 341 | 342 | // get extended keyboard status 343 | static void 344 | handle_1612(kbd_t* kbd, regs_t* regs) 345 | { 346 | (void)kbd; 347 | 348 | regs->eax.word.lo = ((GET_BDA(kbd_flag0) & ~((KF1_RCTRL|KF1_RALT) << 8)) 349 | | ((GET_BDA(kbd_flag1) & (KF1_RCTRL|KF1_RALT)) << 8)); 350 | //BX_DEBUG_INT16("int16: func 12 sending %04x\n",AX); 351 | } 352 | 353 | static void 354 | handle_166f(kbd_t* kbd, regs_t* regs) 355 | { 356 | (void)kbd; 357 | 358 | if (regs->eax.byte.lo == 0x08) 359 | // unsupported, aka normal keyboard 360 | regs->eax.byte.hi = 2; 361 | } 362 | 363 | // keyboard capability check called by DOS 5.0+ keyb 364 | static void 365 | handle_1692(kbd_t* kbd, regs_t* regs) 366 | { 367 | (void)kbd; 368 | 369 | // function int16 ah=0x10-0x12 supported 370 | regs->eax.byte.hi = 0x80; 371 | } 372 | 373 | // 122 keys capability check called by DOS 5.0+ keyb 374 | static void 375 | handle_16a2(kbd_t* kbd, regs_t* regs) 376 | { 377 | (void)kbd; 378 | (void)regs; 379 | 380 | // don't change AH : function int16 ah=0x20-0x22 NOT supported 381 | } 382 | 383 | static void 384 | handle_16XX(kbd_t* kbd, regs_t* regs) 385 | { 386 | (void)kbd; 387 | 388 | fprintf(stderr, "unimplemented keyboard int: AX=%04x\r\n", regs->eax.word.lo); 389 | } 390 | 391 | static void 392 | set_leds(void) 393 | { 394 | // TODO 395 | // u8 shift_flags = (GET_BDA(kbd_flag0) >> 4) & 0x07; 396 | // u8 kbd_led = GET_BDA(kbd_led); 397 | // u8 led_flags = kbd_led & 0x07; 398 | // if (shift_flags == led_flags) 399 | // return; 400 | 401 | // int ret = kbd_command(ATKBD_CMD_SETLEDS, &shift_flags); 402 | // if (ret) 403 | // // Error 404 | // return; 405 | // kbd_led = (kbd_led & ~0x07) | shift_flags; 406 | // SET_BDA(kbd_led, kbd_led); 407 | } 408 | 409 | // INT 16h Keyboard Service Entry Point 410 | void 411 | kbd_int(kbd_t* kbd, regs_t* regs) 412 | { 413 | // XXX - set_leds should be called from irq handler 414 | set_leds(); 415 | 416 | switch (regs->eax.byte.hi) { 417 | case 0x00: handle_1600(kbd, regs); break; 418 | case 0x01: handle_1601(kbd, regs); break; 419 | case 0x02: handle_1602(kbd, regs); break; 420 | case 0x05: handle_1605(kbd, regs); break; 421 | case 0x09: handle_1609(kbd, regs); break; 422 | case 0x0a: handle_160a(kbd, regs); break; 423 | case 0x10: handle_1610(kbd, regs); break; 424 | case 0x11: handle_1611(kbd, regs); break; 425 | case 0x12: handle_1612(kbd, regs); break; 426 | case 0x92: handle_1692(kbd, regs); break; 427 | case 0xa2: handle_16a2(kbd, regs); break; 428 | case 0x6f: handle_166f(kbd, regs); break; 429 | default: handle_16XX(kbd, regs); break; 430 | } 431 | } 432 | 433 | #define none 0 434 | 435 | static struct scaninfo { 436 | u16 normal; 437 | u16 shift; 438 | u16 control; 439 | u16 alt; 440 | } scan_to_keycode[] = { 441 | { none, none, none, none }, 442 | { 0x011b, 0x011b, 0x011b, 0x01f0 }, /* escape */ 443 | { 0x0231, 0x0221, none, 0x7800 }, /* 1! */ 444 | { 0x0332, 0x0340, 0x0300, 0x7900 }, /* 2@ */ 445 | { 0x0433, 0x0423, none, 0x7a00 }, /* 3# */ 446 | { 0x0534, 0x0524, none, 0x7b00 }, /* 4$ */ 447 | { 0x0635, 0x0625, none, 0x7c00 }, /* 5% */ 448 | { 0x0736, 0x075e, 0x071e, 0x7d00 }, /* 6^ */ 449 | { 0x0837, 0x0826, none, 0x7e00 }, /* 7& */ 450 | { 0x0938, 0x092a, none, 0x7f00 }, /* 8* */ 451 | { 0x0a39, 0x0a28, none, 0x8000 }, /* 9( */ 452 | { 0x0b30, 0x0b29, none, 0x8100 }, /* 0) */ 453 | { 0x0c2d, 0x0c5f, 0x0c1f, 0x8200 }, /* -_ */ 454 | { 0x0d3d, 0x0d2b, none, 0x8300 }, /* =+ */ 455 | { 0x0e08, 0x0e08, 0x0e7f, 0x0ef0 }, /* backspace */ 456 | { 0x0f09, 0x0f00, 0x9400, 0xa5f0 }, /* tab */ 457 | { 0x1071, 0x1051, 0x1011, 0x1000 }, /* Q */ 458 | { 0x1177, 0x1157, 0x1117, 0x1100 }, /* W */ 459 | { 0x1265, 0x1245, 0x1205, 0x1200 }, /* E */ 460 | { 0x1372, 0x1352, 0x1312, 0x1300 }, /* R */ 461 | { 0x1474, 0x1454, 0x1414, 0x1400 }, /* T */ 462 | { 0x1579, 0x1559, 0x1519, 0x1500 }, /* Y */ 463 | { 0x1675, 0x1655, 0x1615, 0x1600 }, /* U */ 464 | { 0x1769, 0x1749, 0x1709, 0x1700 }, /* I */ 465 | { 0x186f, 0x184f, 0x180f, 0x1800 }, /* O */ 466 | { 0x1970, 0x1950, 0x1910, 0x1900 }, /* P */ 467 | { 0x1a5b, 0x1a7b, 0x1a1b, 0x1af0 }, /* [{ */ 468 | { 0x1b5d, 0x1b7d, 0x1b1d, 0x1bf0 }, /* ]} */ 469 | { 0x1c0d, 0x1c0d, 0x1c0a, 0x1cf0 }, /* Enter */ 470 | { none, none, none, none }, /* L Ctrl */ 471 | { 0x1e61, 0x1e41, 0x1e01, 0x1e00 }, /* A */ 472 | { 0x1f73, 0x1f53, 0x1f13, 0x1f00 }, /* S */ 473 | { 0x2064, 0x2044, 0x2004, 0x2000 }, /* D */ 474 | { 0x2166, 0x2146, 0x2106, 0x2100 }, /* F */ 475 | { 0x2267, 0x2247, 0x2207, 0x2200 }, /* G */ 476 | { 0x2368, 0x2348, 0x2308, 0x2300 }, /* H */ 477 | { 0x246a, 0x244a, 0x240a, 0x2400 }, /* J */ 478 | { 0x256b, 0x254b, 0x250b, 0x2500 }, /* K */ 479 | { 0x266c, 0x264c, 0x260c, 0x2600 }, /* L */ 480 | { 0x273b, 0x273a, none, 0x27f0 }, /* ;: */ 481 | { 0x2827, 0x2822, none, 0x28f0 }, /* '" */ 482 | { 0x2960, 0x297e, none, 0x29f0 }, /* `~ */ 483 | { none, none, none, none }, /* L shift */ 484 | { 0x2b5c, 0x2b7c, 0x2b1c, 0x2bf0 }, /* |\ */ 485 | { 0x2c7a, 0x2c5a, 0x2c1a, 0x2c00 }, /* Z */ 486 | { 0x2d78, 0x2d58, 0x2d18, 0x2d00 }, /* X */ 487 | { 0x2e63, 0x2e43, 0x2e03, 0x2e00 }, /* C */ 488 | { 0x2f76, 0x2f56, 0x2f16, 0x2f00 }, /* V */ 489 | { 0x3062, 0x3042, 0x3002, 0x3000 }, /* B */ 490 | { 0x316e, 0x314e, 0x310e, 0x3100 }, /* N */ 491 | { 0x326d, 0x324d, 0x320d, 0x3200 }, /* M */ 492 | { 0x332c, 0x333c, none, 0x33f0 }, /* ,< */ 493 | { 0x342e, 0x343e, none, 0x34f0 }, /* .> */ 494 | { 0x352f, 0x353f, none, 0x35f0 }, /* /? */ 495 | { none, none, none, none }, /* R Shift */ 496 | { 0x372a, 0x372a, 0x9600, 0x37f0 }, /* * */ 497 | { none, none, none, none }, /* L Alt */ 498 | { 0x3920, 0x3920, 0x3920, 0x3920 }, /* space */ 499 | { none, none, none, none }, /* caps lock */ 500 | { 0x3b00, 0x5400, 0x5e00, 0x6800 }, /* F1 */ 501 | { 0x3c00, 0x5500, 0x5f00, 0x6900 }, /* F2 */ 502 | { 0x3d00, 0x5600, 0x6000, 0x6a00 }, /* F3 */ 503 | { 0x3e00, 0x5700, 0x6100, 0x6b00 }, /* F4 */ 504 | { 0x3f00, 0x5800, 0x6200, 0x6c00 }, /* F5 */ 505 | { 0x4000, 0x5900, 0x6300, 0x6d00 }, /* F6 */ 506 | { 0x4100, 0x5a00, 0x6400, 0x6e00 }, /* F7 */ 507 | { 0x4200, 0x5b00, 0x6500, 0x6f00 }, /* F8 */ 508 | { 0x4300, 0x5c00, 0x6600, 0x7000 }, /* F9 */ 509 | { 0x4400, 0x5d00, 0x6700, 0x7100 }, /* F10 */ 510 | { none, none, none, none }, /* Num Lock */ 511 | { none, none, none, none }, /* Scroll Lock */ 512 | { 0x4700, 0x4737, 0x7700, none }, /* 7 Home */ 513 | { 0x4800, 0x4838, 0x8d00, none }, /* 8 UP */ 514 | { 0x4900, 0x4939, 0x8400, none }, /* 9 PgUp */ 515 | { 0x4a2d, 0x4a2d, 0x8e00, 0x4af0 }, /* - */ 516 | { 0x4b00, 0x4b34, 0x7300, none }, /* 4 Left */ 517 | { 0x4c00, 0x4c35, 0x8f00, none }, /* 5 */ 518 | { 0x4d00, 0x4d36, 0x7400, none }, /* 6 Right */ 519 | { 0x4e2b, 0x4e2b, 0x9000, 0x4ef0 }, /* + */ 520 | { 0x4f00, 0x4f31, 0x7500, none }, /* 1 End */ 521 | { 0x5000, 0x5032, 0x9100, none }, /* 2 Down */ 522 | { 0x5100, 0x5133, 0x7600, none }, /* 3 PgDn */ 523 | { 0x5200, 0x5230, 0x9200, none }, /* 0 Ins */ 524 | { 0x5300, 0x532e, 0x9300, none }, /* Del */ 525 | { none, none, none, none }, /* SysReq */ 526 | { none, none, none, none }, 527 | { 0x565c, 0x567c, none, none }, /* \| */ 528 | { 0x8500, 0x8700, 0x8900, 0x8b00 }, /* F11 */ 529 | { 0x8600, 0x8800, 0x8a00, 0x8c00 }, /* F12 */ 530 | }; 531 | struct scaninfo key_ext_enter = { 532 | 0xe00d, 0xe00d, 0xe00a, 0xa600 533 | }; 534 | struct scaninfo key_ext_slash = { 535 | 0xe02f, 0xe02f, 0x9500, 0xa400 536 | }; 537 | 538 | // Handle a ps2 style scancode read from the keyboard. 539 | static void 540 | __process_key(kbd_t* kbd, uint8_t scancode) 541 | { 542 | // Check for multi-scancode key sequences 543 | uint8_t flags1 = GET_BDA(kbd_flag1); 544 | if (scancode == 0xe0 || scancode == 0xe1) { 545 | // Start of two byte extended (e0) or three byte pause key (e1) sequence 546 | uint8_t eflag = scancode == 0xe0 ? KF1_LAST_E0 : KF1_LAST_E1; 547 | SET_BDA(kbd_flag1, flags1 | eflag); 548 | return; 549 | } 550 | int key_release = scancode & 0x80; 551 | scancode &= ~0x80; 552 | if (flags1 & (KF1_LAST_E0|KF1_LAST_E1)) { 553 | if (flags1 & KF1_LAST_E1 && scancode == 0x1d) 554 | // Ignore second byte of pause key (e1 1d 45 / e1 9d c5) 555 | return; 556 | // Clear E0/E1 flag in memory for next key event 557 | SET_BDA(kbd_flag1, flags1 & ~(KF1_LAST_E0|KF1_LAST_E1)); 558 | } 559 | 560 | // Check for special keys 561 | switch (scancode) { 562 | case 0x3a: /* Caps Lock */ 563 | kbd_set_flag(key_release, KF0_CAPS, 0, KF0_CAPSACTIVE); 564 | return; 565 | case 0x2a: /* L Shift */ 566 | if (flags1 & KF1_LAST_E0) 567 | // Ignore fake shifts 568 | return; 569 | kbd_set_flag(key_release, KF0_LSHIFT, 0, 0); 570 | return; 571 | case 0x36: /* R Shift */ 572 | if (flags1 & KF1_LAST_E0) 573 | // Ignore fake shifts 574 | return; 575 | kbd_set_flag(key_release, KF0_RSHIFT, 0, 0); 576 | return; 577 | case 0x1d: /* Ctrl */ 578 | if (flags1 & KF1_LAST_E0) 579 | kbd_set_flag(key_release, KF0_CTRLACTIVE, KF1_RCTRL, 0); 580 | else 581 | kbd_set_flag(key_release, KF0_CTRLACTIVE | KF0_LCTRL, 0, 0); 582 | return; 583 | case 0x38: /* Alt */ 584 | if (flags1 & KF1_LAST_E0) 585 | kbd_set_flag(key_release, KF0_ALTACTIVE, KF1_RALT, 0); 586 | else 587 | kbd_set_flag(key_release, KF0_ALTACTIVE | KF0_LALT, 0, 0); 588 | return; 589 | case 0x45: /* Num Lock */ 590 | if (flags1 & KF1_LAST_E1) 591 | // XXX - pause key. 592 | return; 593 | kbd_set_flag(key_release, KF0_NUM, 0, KF0_NUMACTIVE); 594 | return; 595 | case 0x46: /* Scroll Lock */ 596 | if (flags1 & KF1_LAST_E0) { 597 | kbd_ctrl_break(key_release); 598 | return; 599 | } 600 | kbd_set_flag(key_release, KF0_SCROLL, 0, KF0_SCROLLACTIVE); 601 | return; 602 | 603 | case 0x37: /* * */ 604 | if (flags1 & KF1_LAST_E0) { 605 | kbd_prtscr(key_release); 606 | return; 607 | } 608 | break; 609 | case 0x54: /* SysReq */ 610 | kbd_sysreq(key_release); 611 | return; 612 | case 0x53: /* Del */ 613 | if ((GET_BDA(kbd_flag0) & (KF0_CTRLACTIVE|KF0_ALTACTIVE)) 614 | == (KF0_CTRLACTIVE|KF0_ALTACTIVE) && !key_release) { 615 | // Ctrl+alt+del - reset machine. 616 | SET_BDA(soft_reset_flag, 0x1234); 617 | reset(); 618 | } 619 | break; 620 | 621 | default: 622 | break; 623 | } 624 | 625 | // Handle generic keys 626 | if (key_release) 627 | // ignore key releases 628 | return; 629 | if (!scancode || scancode >= ARRAY_SIZE(scan_to_keycode)) { 630 | dprintf(1, "__process_key unknown scancode read: 0x%02x!\n", scancode); 631 | return; 632 | } 633 | struct scaninfo *info = &scan_to_keycode[scancode]; 634 | if (flags1 & KF1_LAST_E0 && (scancode == 0x1c || scancode == 0x35)) 635 | info = (scancode == 0x1c ? &key_ext_enter : &key_ext_slash); 636 | u16 flags0 = GET_BDA(kbd_flag0); 637 | u16 keycode; 638 | if (flags0 & KF0_ALTACTIVE) { 639 | keycode = GET_GLOBAL(info->alt); 640 | } else if (flags0 & KF0_CTRLACTIVE) { 641 | keycode = GET_GLOBAL(info->control); 642 | } else { 643 | u8 useshift = flags0 & (KF0_RSHIFT|KF0_LSHIFT) ? 1 : 0; 644 | u8 ascii = GET_GLOBAL(info->normal) & 0xff; 645 | if ((flags0 & KF0_NUMACTIVE && scancode >= 0x47 && scancode <= 0x53) 646 | || (flags0 & KF0_CAPSACTIVE && ascii >= 'a' && ascii <= 'z')) 647 | // Numlock/capslock toggles shift on certain keys 648 | useshift ^= 1; 649 | if (useshift) 650 | keycode = GET_GLOBAL(info->shift); 651 | else 652 | keycode = GET_GLOBAL(info->normal); 653 | } 654 | if (flags1 & KF1_LAST_E0 && scancode >= 0x47 && scancode <= 0x53) { 655 | /* extended keys handling */ 656 | if (flags0 & KF0_ALTACTIVE) 657 | keycode = (scancode + 0x50) << 8; 658 | else 659 | keycode = (keycode & 0xff00) | 0xe0; 660 | } 661 | if (keycode) 662 | enqueue_key(kbd, keycode); 663 | } 664 | 665 | static void 666 | process_key(kbd_t* kbd, u8 key) 667 | { 668 | // TODO 669 | // if (CONFIG_KBD_CALL_INT15_4F) { 670 | // // allow for keyboard intercept 671 | // struct bregs br; 672 | // memset(&br, 0, sizeof(br)); 673 | // br.eax = (0x4f << 8) | key; 674 | // br.flags = F_IF|F_CF; 675 | // call16_int(0x15, &br); 676 | // if (!(br.flags & F_CF)) 677 | // return; 678 | // key = br.eax; 679 | // } 680 | 681 | __process_key(kbd, key); 682 | } 683 | -------------------------------------------------------------------------------- /init/kbd.h: -------------------------------------------------------------------------------- 1 | #ifndef KBD_H 2 | #define KBD_H 3 | 4 | #include 5 | 6 | #include "vm86.h" 7 | 8 | #define KBD_IRQ 1 9 | #define KBD_BUFFER_SIZE 16 10 | #define KBD_PORT_LO 0x60 11 | #define KBD_PORT_HI 0x64 12 | 13 | typedef struct kbd { 14 | uint16_t keybuff[KBD_BUFFER_SIZE]; 15 | size_t keybuff_len; 16 | } 17 | kbd_t; 18 | 19 | void 20 | kbd_init(kbd_t* kbd); 21 | 22 | void 23 | kbd_send_input(kbd_t* kbd, uint8_t scancode); 24 | 25 | void 26 | kbd_int(kbd_t* kbd, regs_t* regs); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /init/panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "panic.h" 6 | 7 | __attribute__((noreturn)) void 8 | halt() 9 | { 10 | if (getpid() == 1) { 11 | // if init dies the kernel will panic 12 | while (1) { 13 | sleep(1); 14 | } 15 | } else { 16 | exit(EXIT_FAILURE); 17 | } 18 | } 19 | 20 | __attribute__((noreturn)) void 21 | fatal(const char* msg) 22 | { 23 | perror(msg); 24 | halt(); 25 | } 26 | 27 | __attribute__((noreturn)) void 28 | panic(const char* msg) 29 | { 30 | printf("panic: %s\n", msg); 31 | halt(); 32 | } 33 | -------------------------------------------------------------------------------- /init/panic.h: -------------------------------------------------------------------------------- 1 | #ifndef PANIC_H 2 | #define PANIC_H 3 | 4 | // prints errno based message and panics 5 | __attribute__((noreturn)) void 6 | fatal(const char* msg); 7 | 8 | // panics with a simple message, no errno 9 | __attribute__((noreturn)) void 10 | panic(const char* msg); 11 | 12 | // halts machine, no message 13 | __attribute__((noreturn)) void 14 | halt(); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /init/term.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "panic.h" 12 | #include "term.h" 13 | 14 | #define SCREEN_WIDTH 80 15 | #define SCREEN_HEIGHT 25 16 | 17 | static struct termios normal_term; 18 | static struct termios raw_term; 19 | 20 | static int 21 | vga_cursor_line() 22 | { 23 | uint16_t raw_pos = 0; 24 | outb(0x0f, 0x3d4); 25 | raw_pos |= inb(0x3d5); 26 | outb(0x0e, 0x3d4); 27 | raw_pos |= (uint16_t)inb(0x3d5) << 8; 28 | 29 | return raw_pos / SCREEN_WIDTH; 30 | } 31 | 32 | void 33 | term_init() 34 | { 35 | if (tcgetattr(STDIN_FILENO, &normal_term)) { 36 | fatal("tcgetattr"); 37 | } 38 | 39 | raw_term = normal_term; 40 | 41 | // see https://linux.die.net/man/3/tcgetattr for these flags 42 | raw_term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP 43 | | INLCR | IGNCR | ICRNL | IXON); 44 | raw_term.c_oflag &= ~OPOST; 45 | raw_term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); 46 | raw_term.c_cflag &= ~(CSIZE | PARENB); 47 | raw_term.c_cflag |= CS8; 48 | } 49 | 50 | void 51 | term_yield_to_dos() 52 | { 53 | // get raw scancodes from stdin rather than keycodes or ascii 54 | 55 | if (ioctl(STDIN_FILENO, KDSKBMODE, K_RAW)) { 56 | fatal("set stdin raw mode"); 57 | } 58 | 59 | // arrange for SIGIO to be raised when input is available 60 | 61 | if (fcntl(STDIN_FILENO, F_SETSIG, SIGIO)) { 62 | fatal("set stdin async signal"); 63 | } 64 | 65 | if (fcntl(STDIN_FILENO, F_SETOWN, getpid())) { 66 | fatal("set stdin owner"); 67 | } 68 | 69 | if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK | O_ASYNC)) { 70 | fatal("set stdin nonblock"); 71 | } 72 | 73 | // put stdin into raw mode 74 | 75 | if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw_term)) { 76 | fatal("tcsetattr"); 77 | } 78 | } 79 | 80 | void 81 | term_acquire() 82 | { 83 | // select translated keyboard mode 84 | 85 | if (ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE)) { 86 | fatal("set stdin xlate mode"); 87 | } 88 | 89 | // disable O_NONBLOCK and O_ASYNC on terminal 90 | 91 | if (fcntl(STDIN_FILENO, F_SETFL, 0)) { 92 | fatal("set stdin normal"); 93 | } 94 | 95 | // put stdin into normal mode 96 | 97 | if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &normal_term)) { 98 | fatal("tcsetattr"); 99 | } 100 | 101 | // replicate VGA cursor position in console 102 | 103 | int line = vga_cursor_line(); 104 | printf("\033[%d;%dH", line + 1, 1); 105 | fflush(stdout); 106 | } 107 | -------------------------------------------------------------------------------- /init/term.h: -------------------------------------------------------------------------------- 1 | #ifndef TERM_H 2 | #define TERM_H 3 | 4 | void 5 | term_init(); 6 | 7 | void 8 | term_acquire(); 9 | 10 | void 11 | term_yield_to_dos(); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /init/vm86.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "kbd.h" 14 | #include "panic.h" 15 | #include "term.h" 16 | #include "vm86.h" 17 | 18 | typedef struct task { 19 | regs_t* regs; 20 | kbd_t kbd; 21 | bool pending_interrupt; 22 | uint8_t pending_interrupt_nr; 23 | } 24 | task_t; 25 | 26 | enum rep_kind { 27 | NONE, 28 | REP, 29 | }; 30 | 31 | enum bit_size { 32 | BITS16 = 0, 33 | BITS32 = 1, 34 | }; 35 | 36 | static void* 37 | linear(uint16_t segment, uint16_t offset) 38 | { 39 | uint32_t seg32 = segment; 40 | uint32_t off32 = offset; 41 | uint32_t lin = (seg32 << 4) + off32; 42 | return (void*)lin; 43 | } 44 | 45 | static uint8_t 46 | peek8(uint16_t segment, uint16_t offset) 47 | { 48 | return *(uint8_t*)linear(segment, offset); 49 | } 50 | 51 | static void 52 | poke8(uint16_t segment, uint16_t offset, uint8_t value) 53 | { 54 | *(uint8_t*)linear(segment, offset) = value; 55 | } 56 | 57 | static void 58 | poke16(uint16_t segment, uint16_t offset, uint16_t value) 59 | { 60 | *(uint16_t*)linear(segment, offset) = value; 61 | } 62 | 63 | static void 64 | poke32(uint16_t segment, uint16_t offset, uint32_t value) 65 | { 66 | *(uint32_t*)linear(segment, offset) = value; 67 | } 68 | 69 | static uint8_t 70 | peekip(regs_t* regs, uint16_t offset) 71 | { 72 | return peek8(regs->cs.word.lo, regs->eip.word.lo + offset); 73 | } 74 | 75 | struct ivt_descr { 76 | uint16_t offset; 77 | uint16_t segment; 78 | }; 79 | 80 | static struct ivt_descr* const IVT = 0; 81 | 82 | static void 83 | push16(regs_t* regs, uint16_t value) 84 | { 85 | regs->esp.word.lo -= 2; 86 | poke16(regs->ss.word.lo, regs->esp.word.lo, value); 87 | } 88 | 89 | static void do_pending_int(task_t* task); 90 | 91 | static void 92 | do_int(task_t* task, uint8_t vector) 93 | { 94 | push16(task->regs, task->regs->eflags.word.lo); 95 | push16(task->regs, task->regs->cs.word.lo); 96 | push16(task->regs, task->regs->eip.word.lo); 97 | struct ivt_descr* descr = &IVT[vector]; 98 | task->regs->cs.word.lo = descr->segment; 99 | task->regs->eip.dword = descr->offset; 100 | } 101 | 102 | static void 103 | do_software_int(task_t* task, uint8_t vector) 104 | { 105 | do_int(task, vector); 106 | } 107 | 108 | static void 109 | do_pending_int(task_t* task) 110 | { 111 | if (task->pending_interrupt) { 112 | task->pending_interrupt = false; 113 | do_int(task, task->pending_interrupt_nr); 114 | } 115 | } 116 | 117 | static bool 118 | is_port_whitelisted(uint16_t port) 119 | { 120 | // ports whitelisted here are directly accessed by DOS rather than through 121 | // BIOS. we need to do something about them eventually, but for now just 122 | // let access succeed without intervention. 123 | 124 | // programmable interrupt controller 125 | if (port == 0x20 || port == 0x21 || port == 0xa0 || port == 0xa1) { 126 | return true; 127 | } 128 | 129 | // programmable interval timer 130 | if (port >= 0x40 && port <= 0x43) { 131 | // TODO should we handle timing ourselves? it might mess with linux 132 | return true; 133 | } 134 | 135 | // primary ATA 136 | if (port >= 0x1f0 && port <= 0x1f7) { 137 | return true; 138 | } 139 | 140 | // secondary ATA 141 | if (port >= 0x170 && port <= 0x177) { 142 | return true; 143 | } 144 | 145 | // VGA 146 | if (port >= 0x3b0 && port <= 0x3df) { 147 | return true; 148 | } 149 | 150 | // floppy disk 151 | if (port >= 0x3f0 && port <= 0x3f7) { 152 | return true; 153 | } 154 | 155 | // dunno what these are 156 | if (port >= 0x1ce && port <= 0x1cf) { 157 | return true; 158 | } 159 | 160 | if (port == 0x402) { 161 | return true; 162 | } 163 | 164 | if (port == 0x608) { 165 | return true; 166 | } 167 | 168 | return false; 169 | } 170 | 171 | static uint8_t 172 | do_inb(task_t* task, uint16_t port) 173 | { 174 | uint8_t value = inb(port); 175 | 176 | if (!is_port_whitelisted(port)) { 177 | printf("inb port %04x value %02x cs:ip %04x:%04x\r\n", 178 | port, value, task->regs->cs.word.lo, task->regs->eip.word.lo); 179 | } 180 | 181 | return value; 182 | } 183 | 184 | static uint16_t 185 | do_inw(task_t* task, uint16_t port) 186 | { 187 | uint16_t value = inw(port); 188 | 189 | if (!is_port_whitelisted(port)) { 190 | printf("inw port %04x value %04x cs:ip %04x:%04x\r\n", 191 | port, value, task->regs->cs.word.lo, task->regs->eip.word.lo); 192 | } 193 | 194 | return value; 195 | } 196 | 197 | static uint32_t 198 | do_ind(task_t* task, uint16_t port) 199 | { 200 | uint32_t value = inl(port); 201 | 202 | if (!is_port_whitelisted(port)) { 203 | printf("ind port %04x value %08x cs:ip %04x:%04x\r\n", 204 | port, value, task->regs->cs.word.lo, task->regs->eip.word.lo); 205 | } 206 | 207 | return value; 208 | } 209 | 210 | static void 211 | do_outb(task_t* task, uint16_t port, uint8_t value) 212 | { 213 | if (port == 0x20) { 214 | // ignore pic writes, they mess with stuff 215 | return; 216 | } 217 | 218 | if (!is_port_whitelisted(port)) { 219 | printf("outb port %04x value %02x cs:ip %04x:%04x\r\n", 220 | port, value, task->regs->cs.word.lo, task->regs->eip.word.lo); 221 | } 222 | 223 | outb(value, port); 224 | } 225 | 226 | static void 227 | do_outw(task_t* task, uint16_t port, uint16_t value) 228 | { 229 | if (!is_port_whitelisted(port)) { 230 | printf("outw port %04x value %04x cs:ip %04x:%04x\r\n", 231 | port, value, task->regs->cs.word.lo, task->regs->eip.word.lo); 232 | } 233 | 234 | outw(value, port); 235 | } 236 | 237 | static void 238 | do_outd(task_t* task, uint16_t port, uint32_t value) 239 | { 240 | if (!is_port_whitelisted(port)) { 241 | printf("outd port %04x value %08x cs:ip %04x:%04x\r\n", 242 | port, value, task->regs->cs.word.lo, task->regs->eip.word.lo); 243 | } 244 | 245 | outl(value, port); 246 | } 247 | 248 | static void 249 | do_insb(task_t* task) 250 | { 251 | poke8(task->regs->es16.word.lo, task->regs->edi.word.lo, do_inb(task, task->regs->edx.word.lo)); 252 | task->regs->edi.word.lo += 1; 253 | } 254 | 255 | static void 256 | do_insw(task_t* task) 257 | { 258 | uint16_t value = do_inw(task, task->regs->edx.word.lo); 259 | poke16(task->regs->es16.word.lo, task->regs->edi.word.lo, value); 260 | task->regs->edi.word.lo += 2; 261 | } 262 | 263 | static void 264 | do_insd(task_t* task) 265 | { 266 | uint32_t value = do_ind(task, task->regs->edx.word.lo); 267 | poke32(task->regs->es16.word.lo, task->regs->edi.word.lo, value); 268 | task->regs->edi.word.lo += 4; 269 | } 270 | 271 | static uint32_t 272 | rep_count(regs_t* regs, enum rep_kind rep_kind, enum bit_size operand, enum bit_size address) 273 | { 274 | if (rep_kind == NONE) { 275 | return 1; 276 | } else { 277 | if (operand ^ address) { 278 | return regs->ecx.dword; 279 | } else { 280 | return regs->ecx.word.lo; 281 | } 282 | } 283 | } 284 | 285 | static void 286 | emulate_insn(task_t* task) 287 | { 288 | enum bit_size address = BITS16; 289 | enum bit_size operand = BITS16; 290 | enum rep_kind rep_kind = NONE; 291 | 292 | prefix: 293 | switch (peekip(task->regs, 0)) { 294 | case 0x66: 295 | operand = BITS32; 296 | task->regs->eip.word.lo++; 297 | goto prefix; 298 | case 0x67: 299 | address = BITS32; 300 | task->regs->eip.word.lo++; 301 | goto prefix; 302 | case 0xf3: 303 | rep_kind = REP; 304 | task->regs->eip.word.lo++; 305 | goto prefix; 306 | 307 | // segment overrides, just ignore: 308 | case 0x2e: // cs 309 | case 0x3e: // ds 310 | case 0x26: // es 311 | case 0x36: // ss 312 | case 0x64: // fs 313 | case 0x65: // gs 314 | goto prefix; 315 | 316 | default: 317 | break; 318 | } 319 | 320 | #define REPEAT(blk) do { \ 321 | for (uint32_t count = rep_count(task->regs, rep_kind, operand, address); count; count--) { \ 322 | blk \ 323 | } \ 324 | if (rep_kind != NONE) { \ 325 | task->regs->ecx.dword = 0; \ 326 | } \ 327 | } while (0) 328 | 329 | switch (peekip(task->regs, 0)) { 330 | case 0x6c: { 331 | // INSB 332 | 333 | REPEAT({ 334 | do_insb(task); 335 | }); 336 | 337 | task->regs->eip.word.lo += 1; 338 | return; 339 | } 340 | case 0x6d: { 341 | // INSW 342 | 343 | REPEAT({ 344 | if (operand == BITS32) { 345 | do_insd(task); 346 | } else { 347 | do_insw(task); 348 | } 349 | }); 350 | 351 | task->regs->eip.word.lo += 1; 352 | return; 353 | } 354 | case 0xe4: 355 | // INB imm 356 | task->regs->eax.byte.lo = do_inb(task, peekip(task->regs, 1)); 357 | task->regs->eip.word.lo += 2; 358 | return; 359 | case 0xe5: 360 | // INW imm 361 | if (operand == BITS32) { 362 | task->regs->eax.dword = do_ind(task, peekip(task->regs, 1)); 363 | } else { 364 | task->regs->eax.word.lo = do_inw(task, peekip(task->regs, 1)); 365 | } 366 | task->regs->eip.word.lo += 2; 367 | return; 368 | case 0xe6: 369 | // OUTB imm 370 | do_outb(task, peekip(task->regs, 1), task->regs->eax.byte.lo); 371 | task->regs->eip.word.lo += 2; 372 | return; 373 | case 0xe7: 374 | // OUTW imm 375 | if (operand == BITS32) { 376 | do_outd(task, peekip(task->regs, 1), task->regs->eax.dword); 377 | } else { 378 | do_outw(task, peekip(task->regs, 1), task->regs->eax.word.lo); 379 | } 380 | task->regs->eip.word.lo += 2; 381 | return; 382 | case 0xec: 383 | // INB DX 384 | task->regs->eax.byte.lo = do_inb(task, task->regs->edx.word.lo); 385 | task->regs->eip.word.lo += 1; 386 | return; 387 | case 0xed: 388 | // INW DX 389 | if (operand == BITS32) { 390 | task->regs->eax.dword = do_ind(task, task->regs->edx.word.lo); 391 | } else { 392 | task->regs->eax.word.lo = do_inw(task, task->regs->edx.word.lo); 393 | } 394 | task->regs->eip.word.lo += 1; 395 | return; 396 | case 0xee: 397 | // OUTB DX 398 | do_outb(task, task->regs->edx.word.lo, task->regs->eax.byte.lo); 399 | task->regs->eip.word.lo += 1; 400 | return; 401 | case 0xef: 402 | // OUTW DX 403 | if (operand == BITS32) { 404 | do_outd(task, task->regs->edx.word.lo, task->regs->eax.dword); 405 | } else { 406 | do_outw(task, task->regs->edx.word.lo, task->regs->eax.word.lo); 407 | } 408 | task->regs->eip.word.lo += 1; 409 | return; 410 | case 0xf4: { 411 | // HLT 412 | 413 | if (!(task->regs->eflags.word.lo & FLAG_INTERRUPT)) { 414 | panic("8086 task halted CPU with interrupts disabled"); 415 | } 416 | 417 | // just no-op on HLT for now 418 | 419 | task->regs->eip.word.lo += 1; 420 | 421 | return; 422 | } 423 | default: 424 | printf("[%04x:%04x] unknown instruction in gpf: %02x\n", 425 | task->regs->cs.word.lo, 426 | task->regs->eip.word.lo, 427 | peekip(task->regs, 0)); 428 | halt(); 429 | } 430 | 431 | panic("unhandled GPF"); 432 | } 433 | 434 | void 435 | vm86_interrupt(task_t* task, uint8_t vector) 436 | { 437 | if (task->regs->eflags.word.lo & FLAG_INTERRUPT) { 438 | // printf("Dispatching interrupt %04x\r\n", vector); 439 | do_int(task, vector); 440 | } else { 441 | printf("Setting pending interrupt %04x\r\n", vector); 442 | task->pending_interrupt = true; 443 | task->pending_interrupt_nr = vector; 444 | } 445 | } 446 | 447 | void 448 | vm86_gpf(task_t* task) 449 | { 450 | emulate_insn(task); 451 | 452 | // FIXME something is setting NT, IOPL=3, and a reserved bit in EFLAGS 453 | // not sure what's happening, but this causes things to break and clearing 454 | // these bits seems to work around it for now ¯\_(ツ)_/¯ 455 | task->regs->eflags.dword &= ~(0xf << 12); 456 | } 457 | 458 | static void 459 | do_syscall(task_t* task) 460 | { 461 | uint8_t ah = task->regs->eax.byte.hi; 462 | 463 | switch (ah) { 464 | case 0: { 465 | // presence test 466 | task->regs->eax.word.lo = 1; 467 | break; 468 | } 469 | case 1: { 470 | // run command 471 | 472 | // first acquire ownership of the terminal 473 | term_acquire(); 474 | 475 | uint32_t prog_base = (uint32_t)task->regs->cs.word.lo << 4; 476 | 477 | // extract command to execute out of PSP 478 | uint8_t* psp = (uint8_t*)prog_base; 479 | size_t cmdline_len = psp[0x80]; 480 | uint8_t* cmdline_raw = psp + 0x81; 481 | 482 | char cmdline[256] = { 0 }; 483 | memcpy(cmdline, cmdline_raw, cmdline_len); 484 | 485 | // extract current DOS drive from DL and path from SI 486 | char current_dos_drive = task->regs->edx.byte.lo; 487 | 488 | if (current_dos_drive >= 'a' && current_dos_drive <= 'z') { 489 | const char* current_dos_path = linear(task->regs->cs.word.lo, task->regs->esi.word.lo); 490 | 491 | char linux_dir[70] = "/mnt/"; 492 | char* linux_dir_ptr = linux_dir + 5; 493 | 494 | *linux_dir_ptr++ = current_dos_drive; 495 | *linux_dir_ptr++ = '/'; 496 | 497 | for (size_t i = 0; i < 64; i++) { 498 | if (current_dos_path[i] == 0) { 499 | break; 500 | } 501 | 502 | if (current_dos_path[i] == '\\') { 503 | *linux_dir_ptr++ = '/'; 504 | } else { 505 | *linux_dir_ptr++ = current_dos_path[i]; 506 | } 507 | } 508 | 509 | *linux_dir_ptr++ = 0; 510 | 511 | int rc = chdir(linux_dir); 512 | 513 | if (rc < 0) { 514 | perror("warn: cannot chdir"); 515 | } 516 | } 517 | 518 | // execute the command 519 | pid_t child = fork(); 520 | 521 | if (child < 0) { 522 | perror("fork"); 523 | break; 524 | } 525 | 526 | if (child == 0) { 527 | char sh[] = "sh"; 528 | char opt_c[] = "-c"; 529 | char* argv[] = { sh, opt_c, cmdline, NULL }; 530 | 531 | char path[] = "PATH=/usr/bin:/usr/sbin:/bin:/sbin"; 532 | char* envp[] = { path, NULL }; 533 | 534 | execve("/bin/busybox", argv, envp); 535 | } 536 | 537 | while (1) { 538 | int wstat; 539 | int rc = waitpid(child, &wstat, 0); 540 | 541 | if (rc < 0) { 542 | perror("waitpid"); 543 | break; 544 | } 545 | 546 | if (WIFEXITED(wstat)) { 547 | break; 548 | } 549 | } 550 | 551 | // yield terminal ownership back to DOS 552 | term_yield_to_dos(); 553 | } 554 | default: { 555 | break; 556 | } 557 | } 558 | } 559 | 560 | static volatile sig_atomic_t 561 | received_keyboard_input = 0; 562 | 563 | static void 564 | on_sigio(int sig, siginfo_t* info, void* context) 565 | { 566 | (void)sig; 567 | (void)context; 568 | 569 | if (info->si_fd == STDIN_FILENO && (info->si_band & POLLIN)) { 570 | // data to be read on stdin 571 | received_keyboard_input = 1; 572 | } 573 | } 574 | 575 | static void 576 | setup_sigio() 577 | { 578 | struct sigaction sa = { 0 }; 579 | sa.sa_sigaction = on_sigio; 580 | sa.sa_flags = SA_SIGINFO; 581 | sigemptyset(&sa.sa_mask); 582 | 583 | if (sigaction(SIGIO, &sa, NULL)) { 584 | fatal("sigaction SIGIO"); 585 | } 586 | } 587 | 588 | __attribute__((noreturn)) void 589 | vm86_run(struct vm86_init init_params) 590 | { 591 | // need elevated port privileges for init 592 | iopl(3); 593 | 594 | struct vm86plus_struct vm86 = { 0 }; 595 | vm86.regs.cs = init_params.cs; 596 | vm86.regs.eip = init_params.ip; 597 | vm86.regs.eflags = init_params.flags; 598 | vm86.regs.esp = init_params.sp; 599 | vm86.regs.ss = init_params.ss; 600 | vm86.regs.ds = init_params.ss; 601 | vm86.regs.es = init_params.ss; 602 | vm86.regs.fs = init_params.ss; 603 | 604 | // cannot emulate 386 as we rely on port I/O trapping 605 | vm86.cpu_type = 2; 606 | 607 | // make sure we always trap DOSLINUX_INT 608 | vm86.int_revectored.__map[DOSLINUX_INT >> 5] |= 1 << (DOSLINUX_INT & 0x1f); 609 | 610 | task_t task = { 0 }; 611 | task.regs = (void*)&vm86.regs; 612 | kbd_init(&task.kbd); 613 | 614 | setup_sigio(); 615 | term_init(); 616 | term_yield_to_dos(); 617 | 618 | while (1) { 619 | // set IOPL=0 before returning to DOS so we can intercept port I/O 620 | iopl(0); 621 | 622 | int rc = syscall(SYS_vm86, VM86_ENTER, &vm86); 623 | 624 | // and then reenable it for the supervisor 625 | iopl(3); 626 | 627 | switch (VM86_TYPE(rc)) { 628 | case VM86_SIGNAL: { 629 | if (received_keyboard_input) { 630 | // even if we race with a second signal here, we should 631 | // always catch the input in the read call anyway 632 | received_keyboard_input = 0; 633 | 634 | while (1) { 635 | char scancode; 636 | ssize_t nread = read(STDIN_FILENO, &scancode, 1); 637 | 638 | if (nread < 0 && errno == EAGAIN) { 639 | break; 640 | } 641 | 642 | if (nread == 0) { 643 | // eof? what to do... 644 | break; 645 | } 646 | 647 | kbd_send_input(&task.kbd, scancode); 648 | 649 | // IRQ #1 is ivec 9 - TODO handle PIC remapping 650 | // vm86_interrupt(&task, 0x09); 651 | } 652 | } 653 | break; 654 | } 655 | case VM86_UNKNOWN: { 656 | vm86_gpf(&task); 657 | break; 658 | } 659 | case VM86_INTx: { 660 | uint8_t vector = VM86_ARG(rc); 661 | uint8_t ah = task.regs->eax.byte.hi; 662 | uint16_t ax = task.regs->eax.word.lo; 663 | 664 | if (vector == 0xe7) { 665 | // doslinux syscall 666 | do_syscall(&task); 667 | break; 668 | } 669 | 670 | if (vector == 0x16) { 671 | // BIOS keyboard services 672 | kbd_int(&task.kbd, task.regs); 673 | break; 674 | } 675 | 676 | if (vector == 0x15 && ah == 0x4f) { 677 | // keyboard intercept 678 | do_software_int(&task, VM86_ARG(rc)); 679 | break; 680 | } 681 | 682 | if (vector == 0x15 && ax == 0x5305) { 683 | // APM cpu idle 684 | break; 685 | } 686 | 687 | if (vector == 0x13 && ah == 0x02) { 688 | // disk - read sectors into memory 689 | do_software_int(&task, VM86_ARG(rc)); 690 | break; 691 | } 692 | 693 | if (vector == 0x1a && ah <= 0x0f) { 694 | // BIOS time services 695 | do_software_int(&task, VM86_ARG(rc)); 696 | break; 697 | } 698 | 699 | // log all non-whitelisted software interrupts 700 | printf("VM86_INTx: %02x AX=%04x CS:IP=%04x:%04x\r\n", 701 | VM86_ARG(rc), task.regs->eax.word.lo, task.regs->cs.word.lo, task.regs->eip.word.lo); 702 | 703 | do_software_int(&task, VM86_ARG(rc)); 704 | break; 705 | } 706 | case VM86_STI: { 707 | printf("VM86_STI\r\n"); 708 | do_pending_int(&task); 709 | break; 710 | } 711 | case VM86_PICRETURN: { 712 | // this can only happen if vm86plus_info_struct.force_return_for_pic 713 | // is set, and this field is never set by us, set by the kernel, or 714 | // even set by dosemu it seems. this just shouldn't happen. 715 | panic("VM86_PICRETURN should never occur"); 716 | break; 717 | } 718 | case VM86_TRAP: { 719 | // ignore 720 | break; 721 | } 722 | default: { 723 | printf("unknown vm86 return code: %d\n", rc); 724 | break; 725 | } 726 | } 727 | } 728 | } 729 | -------------------------------------------------------------------------------- /init/vm86.h: -------------------------------------------------------------------------------- 1 | #ifndef VM86_H 2 | #define VM86_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define DOSLINUX_INT 0xe7 9 | 10 | #define FLAG_ZERO (1 << 6) 11 | #define FLAG_INTERRUPT (1 << 9) 12 | #define FLAG_VM8086 (1 << 17) 13 | 14 | typedef union reg32 { 15 | uint32_t dword; 16 | struct { 17 | uint16_t lo; 18 | uint16_t hi; 19 | } word; 20 | struct { 21 | uint8_t lo; 22 | uint8_t hi; 23 | uint8_t res1; 24 | uint8_t res2; 25 | } byte; 26 | } 27 | reg32_t; 28 | 29 | // this is like vm86_regs, but all registers are of union type reg32_t 30 | typedef struct regs { 31 | reg32_t ebx; 32 | reg32_t ecx; 33 | reg32_t edx; 34 | reg32_t esi; 35 | reg32_t edi; 36 | reg32_t ebp; 37 | reg32_t eax; 38 | reg32_t __null_ds; 39 | reg32_t __null_es; 40 | reg32_t __null_fs; 41 | reg32_t __null_gs; 42 | reg32_t orig_eax; 43 | reg32_t eip; 44 | reg32_t cs; 45 | reg32_t eflags; 46 | reg32_t esp; 47 | reg32_t ss; 48 | 49 | reg32_t es16; 50 | reg32_t ds16; 51 | reg32_t fs16; 52 | reg32_t gs16; 53 | } 54 | regs_t; 55 | 56 | typedef struct vm86_init { 57 | uint16_t ip; 58 | uint16_t cs; 59 | uint16_t flags; 60 | uint16_t sp; 61 | uint16_t ss; 62 | } __attribute__((packed)) 63 | vm86_init_t; 64 | 65 | __attribute__((noreturn)) void 66 | vm86_run(vm86_init_t init_params); 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /mtoolsrc: -------------------------------------------------------------------------------- 1 | drive c: file="hdd.img" partition=1 mtools_skip_check=1 2 | -------------------------------------------------------------------------------- /script/build-busybox: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | BUSYBOX=busybox-1.32.0 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | if [ ! -e "$BUSYBOX.tar.bz2" ]; then 8 | echo "+++ Downloading $BUSYBOX.tar.bz2" 9 | wget "https://busybox.net/downloads/$BUSYBOX.tar.bz2" 10 | fi 11 | 12 | if [ ! -d "$BUSYBOX" ]; then 13 | echo "+++ Extracting $BUSYBOX.tar.bz2" 14 | tar xf "$BUSYBOX.tar.bz2" 15 | fi 16 | 17 | echo "+++ Configuring $BUSYBOX" 18 | 19 | cp busybox-config "$BUSYBOX/.config" 20 | 21 | echo "+++ Building $BUSYBOX" 22 | 23 | cd "$BUSYBOX" 24 | make -j "$J" 25 | -------------------------------------------------------------------------------- /script/build-linux: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | LINUX=linux-5.8.9 4 | 5 | cd "$(dirname "$0")/.." 6 | 7 | if [ ! -e "$LINUX.tar.gz" ]; then 8 | echo "+++ Downloading $LINUX.tar.gz" 9 | wget "https://cdn.kernel.org/pub/linux/kernel/v5.x/$LINUX.tar.gz" 10 | fi 11 | 12 | if [ ! -d "$LINUX" ]; then 13 | echo "+++ Extracting $LINUX.tar.gz" 14 | tar xf "$LINUX.tar.gz" 15 | fi 16 | 17 | echo "+++ Configuring $LINUX" 18 | 19 | cp linux-config-doslinux "$LINUX/.config" 20 | 21 | echo "+++ Building $LINUX" 22 | 23 | cd "$LINUX" 24 | make -j "$J" 25 | -------------------------------------------------------------------------------- /script/build-prereq: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | cd "$(dirname "$0")" 4 | ./build-linux 5 | ./build-busybox 6 | --------------------------------------------------------------------------------