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