diff --git a/.gitignore b/.gitignore index a683549..e92c619 100644 --- a/.gitignore +++ b/.gitignore @@ -1,54 +1,54 @@ -# Prerequisites -*.d - -# Object files -*.o -*.ko -*.obj -*.elf - -# Linker output -*.ilk -*.map -*.exp - -# Precompiled Headers -*.gch -*.pch - -# Libraries -*.lib -*.a -*.la -*.lo - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.out -*.app -*.i*86 -*.x86_64 -*.hex - -# Debug files -*.dSYM/ -*.su -*.idb -*.pdb - -# Kernel Module Compile Results -*.mod* -*.cmd -.tmp_versions/ -modules.order -Module.symvers -Mkfile.old -dkms.conf -.vscode/* +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf +.vscode/* TODO.md \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 23b5225..2e3cbc7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ -language: C - -before_install: - - sudo apt-get update - - sudo apt-get install -y nasm grub-pc-bin - - sudo ln -s /usr/bin/gcc /usr/bin/i686-elf-gcc - - sudo ln -s /usr/bin/ld /usr/bin/i686-elf-ld - -script: make clean all +language: C + +before_install: + - sudo apt-get update + - sudo apt-get install -y nasm grub-pc-bin + - sudo ln -s /usr/bin/gcc /usr/bin/i686-elf-gcc + - sudo ln -s /usr/bin/ld /usr/bin/i686-elf-ld + +script: make clean all diff --git a/LICENSE b/LICENSE index ac929ed..c601388 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,674 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - iceOS - Copyright (C) 2019 Marco Cetica - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - iceOS Copyright (C) 2019 Marco Cetica - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + iceOS + Copyright (C) 2019 Marco Cetica + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + iceOS Copyright (C) 2019 Marco Cetica + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/Makefile b/Makefile index 102b5d3..2fe8394 100644 --- a/Makefile +++ b/Makefile @@ -1,57 +1,57 @@ -LD = i686-elf-ld -LFLAGS = -melf_i386 -nostdlib -O2 -T link.ld - -all: prepare cpu kernel_code drivers libc userspace mem link iso - -prepare: - mkdir -p obj/ - mkdir -p isodir/boot/grub/ - cp grub.cfg isodir/boot/grub/grub.cfg - -cpu: - make -C kernel/cpu - cp kernel/cpu/*.o obj/ - -kernel_code: - make -C kernel - cp kernel/*.o obj/ - -drivers: - make -C kernel/drivers/ - cp kernel/drivers/*.o obj/ - -libc: - make -C kernel/libc - cp kernel/libc/*.o obj/ - -userspace: - make -C kernel/userspace - cp kernel/userspace/*.o obj/ - -mem: - make -C kernel/mem - cp kernel/mem/*.o obj/ - -link: - $(LD) $(LFLAGS) -o isodir/boot/vulcanos.bin obj/*.o - -iso: - grub-mkrescue isodir -o vulcanos.iso - -clean: - rm -rf obj/ kernel/*.o kernel/cpu/*.o - rm -rf kernel/userspace/*.o kernel/mem/*.o - rm -rf kernel/drivers/*.o kernel/libc/*.o - rm -rf vulcanos.iso bochslog.txt commands isodir - -bochs: - bochs -f bochs_cfg -q - -run: - qemu-system-x86_64 -cdrom vulcanos.iso -cpu qemu32 - -run-debug: - qemu-system-x86_64 -cdrom vulcanos.iso -d exec,cpu - -run-curses: - qemu-system-x86_64 -cdrom vulcanos.iso -curses -cpu qemu32 +LD = i686-elf-ld +LFLAGS = -melf_i386 -nostdlib -O2 -T link.ld + +all: prepare cpu kernel_code drivers libc userspace mem link iso + +prepare: + mkdir -p obj/ + mkdir -p isodir/boot/grub/ + cp grub.cfg isodir/boot/grub/grub.cfg + +cpu: + make -C kernel/cpu + cp kernel/cpu/*.o obj/ + +kernel_code: + make -C kernel + cp kernel/*.o obj/ + +drivers: + make -C kernel/drivers/ + cp kernel/drivers/*.o obj/ + +libc: + make -C kernel/libc + cp kernel/libc/*.o obj/ + +userspace: + make -C kernel/userspace + cp kernel/userspace/*.o obj/ + +mem: + make -C kernel/mem + cp kernel/mem/*.o obj/ + +link: + $(LD) $(LFLAGS) -o isodir/boot/vulcanos.bin obj/*.o + +iso: + grub-mkrescue isodir -o vulcanos.iso + +clean: + rm -rf obj/ kernel/*.o kernel/cpu/*.o + rm -rf kernel/userspace/*.o kernel/mem/*.o + rm -rf kernel/drivers/*.o kernel/libc/*.o + rm -rf vulcanos.iso bochslog.txt commands isodir + +bochs: + bochs -f bochs_cfg -q + +run: + qemu-system-x86_64 -cdrom vulcanos.iso -cpu qemu32 + +run-debug: + qemu-system-x86_64 -cdrom vulcanos.iso -d exec,cpu + +run-curses: + qemu-system-x86_64 -cdrom vulcanos.iso -curses -cpu qemu32 diff --git a/README.md b/README.md index 5df1ec0..cfef72f 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,37 @@ -# VulcanOS [![Build Status](https://travis-ci.com/ice-bit/vulcanos.svg?branch=master)](https://travis-ci.com/ice-bit/vulcanos) -**VulcanOS** is a x86 monolithic kernel written in C from scratch following the UNIX philosophy. This project is just a student learning tool to know more about operating systems, do not expect nothing more than a toy. -
- -
VulcanOS running under QEMU
-


- -## Installation -### Requirements -Before building this project you need to setup a [cross compiler](https://wiki.osdev.org/GCC_Cross-Compiler). Also install the following packages: - -- nasm -- bochs -- grub -- mtools(only for Arch Linux) - -After that, you can build iceOS just by running the command listed below. -1. Type `make all` to compile the system and to create an ISO -2. Type `make run` to start it in QEMU or `make bochs` to start it with bochs(only for debug purposes). - -You can also find a ISO file -[here](https://github.com/ice-bit/vulcanos/raw/master/imgs/vulcanos.iso)(md5sum: `a706cdfeea573e08550e599717d3f519`) - -## Features -iceOS has the following features: -- [x] VGA driver -- [x] Interrupts -- [x] PIC & PIT driver -- [x] PS/2 driver -- [x] Heap -- [x] Paging -- [ ] VFS driver -- [ ] Usermode - - -## License -VulcanOS is released under GPLv3, you can obtain a copy of this license by cloning this repository or by visiting [this](https://opensource.org/licenses/GPL-3.0) page. +# VulcanOS [![Build Status](https://travis-ci.com/ice-bit/vulcanos.svg?branch=master)](https://travis-ci.com/ice-bit/vulcanos) +**VulcanOS** is a x86 monolithic kernel written in C from scratch following the UNIX philosophy. This project is just a student learning tool to know more about operating systems, do not expect nothing more than a toy. +
+ +
VulcanOS running under QEMU
+


+ +## Installation +### Requirements +Before building this project you need to setup a [cross compiler](https://wiki.osdev.org/GCC_Cross-Compiler). Also install the following packages: + +- nasm +- bochs +- grub +- mtools(only for Arch Linux) + +After that, you can build iceOS just by running the command listed below. +1. Type `make all` to compile the system and to create an ISO +2. Type `make run` to start it in QEMU or `make bochs` to start it with bochs(only for debug purposes). + +You can also find a ISO file +[here](https://github.com/ice-bit/vulcanos/raw/master/imgs/vulcanos.iso)(md5sum: `a706cdfeea573e08550e599717d3f519`) + +## Features +iceOS has the following features: +- [x] VGA driver +- [x] Interrupts +- [x] PIC & PIT driver +- [x] PS/2 driver +- [x] Heap +- [x] Paging +- [ ] VFS driver +- [ ] Usermode + + +## License +VulcanOS is released under GPLv3, you can obtain a copy of this license by cloning this repository or by visiting [this](https://opensource.org/licenses/GPL-3.0) page. diff --git a/bochs_cfg b/bochs_cfg index df47b6c..6cb55c1 100644 --- a/bochs_cfg +++ b/bochs_cfg @@ -1,12 +1,12 @@ -# System configuration. -romimage: file=$BXSHARE/BIOS-bochs-latest -vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest -cpu: model=corei7_ivy_bridge_3770k, ips=120000000 -clock: sync=slowdown -megs: 256 -boot: cdrom, disk - - -# CDROM -ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +# System configuration. +romimage: file=$BXSHARE/BIOS-bochs-latest +vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest +cpu: model=corei7_ivy_bridge_3770k, ips=120000000 +clock: sync=slowdown +megs: 256 +boot: cdrom, disk + + +# CDROM +ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 ata1-master: type=cdrom, path="iceOS.iso", status=inserted \ No newline at end of file diff --git a/fs_generator.c b/fs_generator.c index 243479e..869b0ef 100644 --- a/fs_generator.c +++ b/fs_generator.c @@ -1,55 +1,55 @@ -/* This program comes from James Molloy tutorial - * on how to create an UNIX clone You can find the original code at: - * http://www.jamesmolloy.co.uk/tutorial_html/8.-The%20VFS%20and%20the%20initrd.html */ - -#include -#include -#include - -struct initrd_header { - unsigned char magic; // Magic number for consistency - char name[64]; - unsigned int offset; // Offset of the file start - unsigned int length; -}; - -int main(int argc, char **argv) { - int heads = (argc - 1) / 2; - struct initrd_header headers[64]; - printf("Size of header(in bytes): %ld\n", sizeof(struct initrd_header)); - unsigned int off = sizeof(struct initrd_header) * 64 + sizeof(int); - for(int i = 0; i < heads; i++) { - printf("Writing file %s->%s at 0x%d\n", argv[i*2+1], argv[i*2+2], off); - strcpy(headers[i].name, argv[i*2+2]); - headers[i].offset = off; - FILE *stream = fopen(argv[i*2+1], "r"); - if(stream == 0) { - puts("Error, file not found!"); - return 1; - } - fseek(stream, 0, SEEK_END); - headers[i].length = ftell(stream); - off += headers[i].length; - fclose(stream); - headers[i].magic = 0xBF; - } - - FILE *wstream = fopen("./initrd.img", "w"); - unsigned char *data = (unsigned char*)malloc(off); - fwrite(&heads, sizeof(int), 1, wstream); - fwrite(&heads, sizeof(struct initrd_header), 64, wstream); - - for(int i = 0; i < heads; i++) { - FILE *stream = fopen(argv[i*2+1], "r"); - unsigned char *buf = (unsigned char*)malloc(headers[i].length); - fread(buf, 1, headers[i].length, stream); - fread(buf, 1, headers[i].length, wstream); - fclose(stream); - free(buf); - } - - fclose(wstream); - free(data); - - return 0; +/* This program comes from James Molloy tutorial + * on how to create an UNIX clone You can find the original code at: + * http://www.jamesmolloy.co.uk/tutorial_html/8.-The%20VFS%20and%20the%20initrd.html */ + +#include +#include +#include + +struct initrd_header { + unsigned char magic; // Magic number for consistency + char name[64]; + unsigned int offset; // Offset of the file start + unsigned int length; +}; + +int main(int argc, char **argv) { + int heads = (argc - 1) / 2; + struct initrd_header headers[64]; + printf("Size of header(in bytes): %ld\n", sizeof(struct initrd_header)); + unsigned int off = sizeof(struct initrd_header) * 64 + sizeof(int); + for(int i = 0; i < heads; i++) { + printf("Writing file %s->%s at 0x%d\n", argv[i*2+1], argv[i*2+2], off); + strcpy(headers[i].name, argv[i*2+2]); + headers[i].offset = off; + FILE *stream = fopen(argv[i*2+1], "r"); + if(stream == 0) { + puts("Error, file not found!"); + return 1; + } + fseek(stream, 0, SEEK_END); + headers[i].length = ftell(stream); + off += headers[i].length; + fclose(stream); + headers[i].magic = 0xBF; + } + + FILE *wstream = fopen("./initrd.img", "w"); + unsigned char *data = (unsigned char*)malloc(off); + fwrite(&heads, sizeof(int), 1, wstream); + fwrite(&heads, sizeof(struct initrd_header), 64, wstream); + + for(int i = 0; i < heads; i++) { + FILE *stream = fopen(argv[i*2+1], "r"); + unsigned char *buf = (unsigned char*)malloc(headers[i].length); + fread(buf, 1, headers[i].length, stream); + fread(buf, 1, headers[i].length, wstream); + fclose(stream); + free(buf); + } + + fclose(wstream); + free(data); + + return 0; } \ No newline at end of file diff --git a/grub.cfg b/grub.cfg index 86afc3c..fe822fc 100644 --- a/grub.cfg +++ b/grub.cfg @@ -1,7 +1,7 @@ -set timeout = 0 -set default = 0 - -menuentry "VulcanOS" { - multiboot2 /boot/vulcanos.bin - boot -} +set timeout = 0 +set default = 0 + +menuentry "VulcanOS" { + multiboot2 /boot/vulcanos.bin + boot +} diff --git a/kernel/Makefile b/kernel/Makefile index abcec33..cbe85cf 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -1,10 +1,10 @@ -OBJS = kernel_main.o - -CC = i686-elf-gcc # cross-compiler -CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c - - -all: ${OBJS} - -%.o: %.c +OBJS = kernel_main.o + +CC = i686-elf-gcc # cross-compiler +CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c + + +all: ${OBJS} + +%.o: %.c $(CC) $(CFLAGS) $< -o $@ \ No newline at end of file diff --git a/kernel/cpu/Makefile b/kernel/cpu/Makefile index 339e604..38757eb 100644 --- a/kernel/cpu/Makefile +++ b/kernel/cpu/Makefile @@ -1,8 +1,9 @@ -OBJS = kernel_loader.asm.o ports.asm.o \ - gdt.asm.o idt.asm.o interrupts.asm.o - -ASM = nasm -ASMFLAGS = -f elf32 -all: $(OBJS) -%.asm.o: %.asm - $(ASM) $(ASMFLAGS) $< -o $@ +OBJS = main.asm.o ports.asm.o \ + gdt.asm.o idt.asm.o \ + interrupts.asm.o header.asm.o + +ASM = nasm +ASMFLAGS = -f elf32 +all: $(OBJS) +%.asm.o: %.asm + $(ASM) $(ASMFLAGS) $< -o $@ diff --git a/kernel/cpu/gdt.asm b/kernel/cpu/gdt.asm index b3ca5ef..d8a919f 100644 --- a/kernel/cpu/gdt.asm +++ b/kernel/cpu/gdt.asm @@ -1,22 +1,22 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; vulcanOS Kernel ; -; Developed by Marco 'icebit' Cetica ; -; (c) 2019-2021 ; -; Released under GPLv3 ; -; https://github.com/ice-bit/iceOS ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -global gdt_flush ; for drivers/gdt.c - -section .text -gdt_flush: - mov eax, [esp+4] ; get address of gdt_ptr_t - lgdt [eax] ; Load GDT - mov ax, 0x10 ; offset in the GDT of the data segment - mov ds, ax ; Load data segment selectors - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - jmp 0x08:.flush ; offset in the GDT of the code segment -.flush: - ret +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; vulcanOS Kernel ; +; Developed by Marco 'icebit' Cetica ; +; (c) 2019-2021 ; +; Released under GPLv3 ; +; https://github.com/ice-bit/vulcanos ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +global gdt_flush ; for drivers/gdt.c + +section .text +gdt_flush: + mov eax, [esp+4] ; get address of gdt_ptr_t + lgdt [eax] ; Load GDT + mov ax, 0x10 ; offset in the GDT of the data segment + mov ds, ax ; Load data segment selectors + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + jmp 0x08:.flush ; offset in the GDT of the code segment +.flush: + ret diff --git a/kernel/cpu/header.asm b/kernel/cpu/header.asm new file mode 100644 index 0000000..bec5032 --- /dev/null +++ b/kernel/cpu/header.asm @@ -0,0 +1,19 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; vulcanOS Kernel ; +; Developed by Marco 'icebit' Cetica ; +; (c) 2019-2021 ; +; Released under GPLv3 ; +; https://github.com/ice-bit/vulcanos ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +section .multiboot_header +header_s: + dd 0xE85250D6 ; Magic number for multiboot + dd 0 ; Protected mode flag + dd header_e - header_s ; Header length + dd 0x100000000 - (0xE85250D6 + 0 + (header_e - header_s)) ; Checksum + + ; Other flags + dw 0 ; Type + dw 0 ; Flags + dw 0 ; Size +header_e: \ No newline at end of file diff --git a/kernel/cpu/idt.asm b/kernel/cpu/idt.asm index 9846d3a..d26fe87 100644 --- a/kernel/cpu/idt.asm +++ b/kernel/cpu/idt.asm @@ -1,14 +1,14 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; vulcanOS Kernel ; -; Developed by Marco 'icebit' Cetica ; -; (c) 2019-2021 ; -; Released under GPLv3 ; -; https://github.com/ice-bit/iceOS ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -global idt_flush ; for drivers/idt.c - -section .text -idt_flush: - mov eax, [esp+4] ; Retrieve idt_ptr_t* - lidt [eax] - ret +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; vulcanOS Kernel ; +; Developed by Marco 'icebit' Cetica ; +; (c) 2019-2021 ; +; Released under GPLv3 ; +; https://github.com/ice-bit/vulcanos ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +global idt_flush ; for drivers/idt.c + +section .text +idt_flush: + mov eax, [esp+4] ; Retrieve idt_ptr_t* + lidt [eax] + ret diff --git a/kernel/cpu/interrupts.asm b/kernel/cpu/interrupts.asm index 7225ca2..ff8d8b3 100644 --- a/kernel/cpu/interrupts.asm +++ b/kernel/cpu/interrupts.asm @@ -1,159 +1,159 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; vulcanOS Kernel ; -; Developed by Marco 'icebit' Cetica ; -; (c) 2019-2021 ; -; Released under GPLv3 ; -; https://github.com/ice-bit/iceOS ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -extern isr_handler ; Defined in drivers/isr.h -extern irq_handler ; Defined in drivers/isr.h - -; Let's implement all ISR in a very handy way -%macro ISR_NOERRCODE 1 - global isr%1 - isr%1: - cli ; Disable interrupts - push byte 0 ; Push dummy error code - push byte %1 ; Push interrupt number - jmp isr_common ; goto ISR handler -%endmacro - -%macro ISR_ERRCODE 1 - global isr%1 - isr%1: - cli ; Disable interrupts - push byte %1 ; Push interrupt number - jmp isr_common ; goto ISR handler -%endmacro - -; Now we have to do the same thing for Interrupt Requests, -; in this case the first parameter is the IRQ number while -; the second one is the ISR number to be remapped to -%macro IRQ 2 - global irq%1 - irq%1: - cli ; Disable interrupts - push byte 0 ; Push dummy error code - push byte %2 ; Push interrupt number - jmp irq_common ; goto IRQ handler -%endmacro - -; isr_common is a common handler for all -; Interrupt Service Routines declared in the system -; It's main scope is to save current register's states -; into the stack, call the C high level handler -; and restore the register's original values from -; the stack -isr_common: - ;; Save register's content into the stack ;; - pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax - - mov ax, ds ; Get 16 bits of eax(e.g ds) - push eax - - mov ax, 0x10 ; Load the kernel data segment descriptor - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - ;; Call C handler ;; - call isr_handler ; Call C handler - - ;; Restore register's content from the stack ;; - pop eax ; Restore original data segment selector - - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax - add esp, 8 ; Cleans up pushed error code and ISR number - sti ; Re-enable interrupts - iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp - - -; irq_common is a common handler for all -; Interrupt Requests, it's very similar to the -; ISR one -irq_common: - ;; Save register's content into the stack ;; - pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax - - mov ax, ds ; Get 16 bits of eax(e.g ds) - push eax - - mov ax, 0x10 ; Load the kernel data segment descriptor - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - ;; Call C handler ;; - call irq_handler ; Call C handler - - ;; Restore register's content from the stack ;; - pop ebx ; Restore original data segment selector - - mov ds, bx - mov es, bx - mov fs, bx - mov gs, bx - - popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax - add esp, 8 ; Cleans up pushed error code and ISR number - sti ; Re-enable interrupts - iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp - -; Standard x86 ISRs (only 8,10-14 and 17 requires to push error codes to the stack) -ISR_NOERRCODE 0 -ISR_NOERRCODE 1 -ISR_NOERRCODE 2 -ISR_NOERRCODE 3 -ISR_NOERRCODE 4 -ISR_NOERRCODE 5 -ISR_NOERRCODE 6 -ISR_NOERRCODE 7 -ISR_ERRCODE 8 -ISR_NOERRCODE 9 -ISR_ERRCODE 10 -ISR_ERRCODE 11 -ISR_ERRCODE 12 -ISR_ERRCODE 13 -ISR_ERRCODE 14 -ISR_NOERRCODE 15 -ISR_NOERRCODE 16 -ISR_NOERRCODE 17 -ISR_NOERRCODE 18 -ISR_NOERRCODE 19 -ISR_NOERRCODE 20 -ISR_NOERRCODE 21 -ISR_NOERRCODE 22 -ISR_NOERRCODE 23 -ISR_NOERRCODE 24 -ISR_NOERRCODE 25 -ISR_NOERRCODE 26 -ISR_NOERRCODE 27 -ISR_NOERRCODE 28 -ISR_NOERRCODE 29 -ISR_NOERRCODE 30 -ISR_NOERRCODE 31 - -IRQ 0, 32 -IRQ 1, 33 -IRQ 2, 34 -IRQ 3, 35 -IRQ 4, 36 -IRQ 5, 37 -IRQ 6, 38 -IRQ 7, 39 -IRQ 8, 40 -IRQ 9, 41 -IRQ 10, 42 -IRQ 11, 43 -IRQ 12, 44 -IRQ 13, 45 -IRQ 14, 46 -IRQ 15, 47 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; vulcanOS Kernel ; +; Developed by Marco 'icebit' Cetica ; +; (c) 2019-2021 ; +; Released under GPLv3 ; +; https://github.com/ice-bit/vulcanos ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +extern isr_handler ; Defined in drivers/isr.h +extern irq_handler ; Defined in drivers/isr.h + +; Let's implement all ISR in a very handy way +%macro ISR_NOERRCODE 1 + global isr%1 + isr%1: + cli ; Disable interrupts + push byte 0 ; Push dummy error code + push byte %1 ; Push interrupt number + jmp isr_common ; goto ISR handler +%endmacro + +%macro ISR_ERRCODE 1 + global isr%1 + isr%1: + cli ; Disable interrupts + push byte %1 ; Push interrupt number + jmp isr_common ; goto ISR handler +%endmacro + +; Now we have to do the same thing for Interrupt Requests, +; in this case the first parameter is the IRQ number while +; the second one is the ISR number to be remapped to +%macro IRQ 2 + global irq%1 + irq%1: + cli ; Disable interrupts + push byte 0 ; Push dummy error code + push byte %2 ; Push interrupt number + jmp irq_common ; goto IRQ handler +%endmacro + +; isr_common is a common handler for all +; Interrupt Service Routines declared in the system +; It's main scope is to save current register's states +; into the stack, call the C high level handler +; and restore the register's original values from +; the stack +isr_common: + ;; Save register's content into the stack ;; + pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax + + mov ax, ds ; Get 16 bits of eax(e.g ds) + push eax + + mov ax, 0x10 ; Load the kernel data segment descriptor + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ;; Call C handler ;; + call isr_handler ; Call C handler + + ;; Restore register's content from the stack ;; + pop eax ; Restore original data segment selector + + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax + add esp, 8 ; Cleans up pushed error code and ISR number + sti ; Re-enable interrupts + iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp + + +; irq_common is a common handler for all +; Interrupt Requests, it's very similar to the +; ISR one +irq_common: + ;; Save register's content into the stack ;; + pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax + + mov ax, ds ; Get 16 bits of eax(e.g ds) + push eax + + mov ax, 0x10 ; Load the kernel data segment descriptor + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ;; Call C handler ;; + call irq_handler ; Call C handler + + ;; Restore register's content from the stack ;; + pop ebx ; Restore original data segment selector + + mov ds, bx + mov es, bx + mov fs, bx + mov gs, bx + + popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax + add esp, 8 ; Cleans up pushed error code and ISR number + sti ; Re-enable interrupts + iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp + +; Standard x86 ISRs (only 8,10-14 and 17 requires to push error codes to the stack) +ISR_NOERRCODE 0 +ISR_NOERRCODE 1 +ISR_NOERRCODE 2 +ISR_NOERRCODE 3 +ISR_NOERRCODE 4 +ISR_NOERRCODE 5 +ISR_NOERRCODE 6 +ISR_NOERRCODE 7 +ISR_ERRCODE 8 +ISR_NOERRCODE 9 +ISR_ERRCODE 10 +ISR_ERRCODE 11 +ISR_ERRCODE 12 +ISR_ERRCODE 13 +ISR_ERRCODE 14 +ISR_NOERRCODE 15 +ISR_NOERRCODE 16 +ISR_NOERRCODE 17 +ISR_NOERRCODE 18 +ISR_NOERRCODE 19 +ISR_NOERRCODE 20 +ISR_NOERRCODE 21 +ISR_NOERRCODE 22 +ISR_NOERRCODE 23 +ISR_NOERRCODE 24 +ISR_NOERRCODE 25 +ISR_NOERRCODE 26 +ISR_NOERRCODE 27 +ISR_NOERRCODE 28 +ISR_NOERRCODE 29 +ISR_NOERRCODE 30 +ISR_NOERRCODE 31 + +IRQ 0, 32 +IRQ 1, 33 +IRQ 2, 34 +IRQ 3, 35 +IRQ 4, 36 +IRQ 5, 37 +IRQ 6, 38 +IRQ 7, 39 +IRQ 8, 40 +IRQ 9, 41 +IRQ 10, 42 +IRQ 11, 43 +IRQ 12, 44 +IRQ 13, 45 +IRQ 14, 46 +IRQ 15, 47 diff --git a/kernel/cpu/kernel_loader.asm b/kernel/cpu/kernel_loader.asm deleted file mode 100644 index eb08d1e..0000000 --- a/kernel/cpu/kernel_loader.asm +++ /dev/null @@ -1,43 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; vulcanOS Kernel ; -; Developed by Marco 'icebit' Cetica ; -; (c) 2019-2021 ; -; Released under GPLv3 ; -; https://github.com/ice-bit/iceOS ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -[BITS 32] ; We should be in protected mode -section .multiboot - -head_s: - dd 0xE85250D6 ; Multiboot header magic number - dd 0 ; Protected mode flag - dd head_e - head_s ; Header length - dd 0x100000000 - (0xE85250D6 + 0 + (head_e - head_s)) ; Checksum of above - - ; Other flags - dw 0 ; type - dw 0 ; flags - dd 0 ; size - -head_e: - -GLOBAL kernel_loader -EXTERN kernel_main - -section .text -kernel_loader: - mov esp, kernel_stack + KERNEL_STACK_SZ ; Define stack pointer - push eax ; Set multiboot header - call kernel_main ; Jump into kernel's main function -.loop: - jmp .loop ; If the kernel returns, go into an infinite loop. - ; This will prevent the CPU to run non-kernel instructions - ; from the memory - -KERNEL_STACK_SZ equ 4096 ; Stack size(4KiB) - -section .bss -align 4 -kernel_stack: - resb KERNEL_STACK_SZ ; Reserve 4 KiB diff --git a/kernel/cpu/main.asm b/kernel/cpu/main.asm new file mode 100644 index 0000000..d107ace --- /dev/null +++ b/kernel/cpu/main.asm @@ -0,0 +1,27 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; vulcanOS Kernel ; +; Developed by Marco 'icebit' Cetica ; +; (c) 2019-2021 ; +; Released under GPLv3 ; +; https://github.com/ice-bit/vulcanos ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +GLOBAL kernel_loader +EXTERN kernel_main +[BITS 32] ; Ensure we are in protected mode + +section .text +kernel_loader: + mov esp, kernel_stack + KERNEL_STACK_SZ ; Define stack pointer + push eax ; Set multiboot header register + call kernel_main ; Call kernel's main function +.loop: + jmp .loop ; If the kernel returns, go into an endless loop + ; This will prevent the CPU to execure any non-kernel + ; instructions. + +KERNEL_STACK_SZ equ 4096 ; Stack size(4KiB) + +section .bss +align 4 +kernel_stack: + resb KERNEL_STACK_SZ ; Reserver 4KiB for kernel's stack \ No newline at end of file diff --git a/kernel/cpu/ports.asm b/kernel/cpu/ports.asm index 1652e34..9f494e2 100644 --- a/kernel/cpu/ports.asm +++ b/kernel/cpu/ports.asm @@ -1,21 +1,21 @@ -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; vulcanOS Kernel ; -; Developed by Marco 'icebit' Cetica ; -; (c) 2019-2021 ; -; Released under GPLv3 ; -; https://github.com/ice-bit/iceOS ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -global outb ; Output from port -global inb ; Input to port - -outb: - mov al, [esp + 8] - mov dx, [esp + 4] - out dx, al - ret - -inb: - mov dx, [esp + 4] - in al, dx - ret +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; vulcanOS Kernel ; +; Developed by Marco 'icebit' Cetica ; +; (c) 2019-2021 ; +; Released under GPLv3 ; +; https://github.com/ice-bit/vulcanos ; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +global outb ; Output from port +global inb ; Input to port + +outb: + mov al, [esp + 8] + mov dx, [esp + 4] + out dx, al + ret + +inb: + mov dx, [esp + 4] + in al, dx + ret diff --git a/kernel/drivers/Makefile b/kernel/drivers/Makefile index 24cd3ff..da29a61 100644 --- a/kernel/drivers/Makefile +++ b/kernel/drivers/Makefile @@ -1,11 +1,11 @@ -OBJS = tty.o gdt.o idt.o isr.o timer.o keyboard.o \ - fs.o cpuid.o - -CC = i686-elf-gcc # cross-compiler -CFLAGS = -m32 -fno-stack-protector -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -ffreestanding -Wall -Wextra -Werror -g -c - - -all:${OBJS} - -%.o: %.c - $(CC) $(CFLAGS) $< -o $@ +OBJS = tty.o gdt.o idt.o isr.o timer.o keyboard.o \ + fs.o cpuid.o + +CC = i686-elf-gcc # cross-compiler +CFLAGS = -m32 -fno-stack-protector -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -ffreestanding -Wall -Wextra -Werror -g -c + + +all:${OBJS} + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ diff --git a/kernel/drivers/cpuid.c b/kernel/drivers/cpuid.c index 921ccab..cbb9e33 100644 --- a/kernel/drivers/cpuid.c +++ b/kernel/drivers/cpuid.c @@ -1,195 +1,195 @@ -#include "cpuid.h" -#include "../libc/string.h" -#define INTEL_MAGIC_NUMBER 0x756e6547 -#define AMD_MAGIC_NUMBER 0x68747541 -#define UNRECOGNIZED_CPU 0xBADFF - -static cpuid_t get_cpuid(icpuid_t cpu); -static icpuid_t detect_cpu(void); -static icpuid_t intel_cpu(void); -static icpuid_t amd_cpu(void); -static icpuid_t generic_cpu(void); - -icpuid_t detect_cpu(void) { - uint32_t ebx, null; - icpuid_t i_cpu; - - cpuid(0, null, ebx, null, null); - - // Select CPU brand - switch(ebx) { - case INTEL_MAGIC_NUMBER: - i_cpu = intel_cpu(); - break; - case AMD_MAGIC_NUMBER: - i_cpu = amd_cpu(); - break; - default: - i_cpu = generic_cpu(); - break; - } - - return i_cpu; -} - -icpuid_t intel_cpu(void) { - uint32_t eax, ebx, null; - icpuid_t icpu; - - // Fill the structure - cpuid(1, eax, ebx, null, null); - icpu.model = (eax >> 4) & 0xF; - icpu.family = (eax >> 8) & 0xF; - icpu.type = (eax >> 12) & 0xF; - icpu.brand = INTEL_MAGIC_NUMBER; - icpu.stepping = eax & 0xF; - icpu.reserved = eax >> 14; - - return icpu; -} - -icpuid_t amd_cpu(void) { - uint32_t eax, null; - icpuid_t icpu; - - // Fill the structure - cpuid(1, eax, null, null, null); - icpu.model = (eax >> 4) & 0xF; - icpu.family = (eax >> 8) & 0xF; - icpu.stepping = eax & 0xF; - icpu.reserved = eax >> 12; - icpu.brand = AMD_MAGIC_NUMBER; - - return icpu; -} - -icpuid_t generic_cpu(void) { - icpuid_t icpu; - - icpu.brand = UNRECOGNIZED_CPU; // Magic number for unknown CPUs - - return icpu; -} - -cpuid_t get_cpuid(icpuid_t cpu) { - cpuid_t cpuid; - uint8_t model[64]; - - // Recognize CPU brand - if(cpu.brand == AMD_MAGIC_NUMBER) { - switch(cpu.family) { - case 4: - strcpy(model, (uint8_t*)"486 model "); // Set model name - strcat(model, (void*)cpu.model); // Set model version - cpuid.model = model; - break; - case 5: - switch(cpu.model) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - strcpy(model, (uint8_t*)"K6 model "); // Set model name - strcat(model, (void*)cpu.model); // Set model version - cpuid.model = model; - break; - case 8: - strcpy(model, (uint8_t*)"K6-2 model "); // Set model name - strcat(model, (void*)cpu.model); // Set model version - cpuid.model = model; - break; - case 9: - strcpy(model, (uint8_t*)"K6-III model "); // Set model name - strcat(model, (void*)cpu.model); // Set model version - cpuid.model = model; - break; - default: - strcpy(model, (uint8_t*)"K5/K6 model "); // Set model name - strcat(model, (void*)cpu.model); // Set model version - cpuid.model = model; - break; - } - break; - case 6: - switch(cpu.model) { - case 1: - case 2: - case 3: - cpuid.model = (uint8_t*)"Duron model 3"; - break; - case 4: - strcpy(model, (uint8_t*)"Athlon model "); - strcat(model, (void*)cpu.model); - cpuid.model = model; - break; - case 6: - cpuid.model = (uint8_t*)"Athlon MP/Mobile Athlon Model 6"; - break; - case 7: - cpuid.model = (uint8_t*)"Mobile Duron Model 7"; - break; - default: - strcpy(model, (uint8_t*)"Duron/Athlon model "); - strcat(model, (void*)cpu.model); - cpuid.model = model; - break; - } - break; - } - } else if(cpu.brand == INTEL_MAGIC_NUMBER) { - switch(cpu.type) { - case 0: - cpuid.type =(uint8_t*)"Original OEM"; - break; - case 1: - cpuid.type = (uint8_t*)"Overdrive"; - break; - case 2: - cpuid.type = (uint8_t*)"Dual-capable"; - break; - case 3: - cpuid.type = (uint8_t*)"Reserved"; - break; - } - - switch(cpu.family) { - case 3: - cpuid.family = (uint8_t*)"i386"; - break; - case 4: - cpuid.family = (uint8_t*)"i486"; - break; - case 5: - cpuid.family = (uint8_t*)"Pentium II Model 5/Xeon/Celeron"; - break; - case 6: - cpuid.family = (uint8_t*)"Pentium Pro"; - break; - case 15: - cpuid.family = (uint8_t*)"Pentium 4"; - break; - } - } else if(cpu.brand == UNRECOGNIZED_CPU) - cpuid.family = (uint8_t*)"Generic (x86) CPU"; - - return cpuid; -} - -uint8_t *get_cpu_type() { - icpuid_t icpu = detect_cpu(); // Detect CPU brand(Intel, AMD or generic x86) - cpuid_t cpu_type = get_cpuid(icpu); - - return (uint8_t*)cpu_type.type; -} - -uint8_t *get_cpu_family() { - icpuid_t icpu = detect_cpu(); // Detect CPU brand(Intel, AMD or generic x86) - cpuid_t cpu_family = get_cpuid(icpu); - - return (uint8_t*)cpu_family.family; - -} +#include "cpuid.h" +#include "../libc/string.h" +#define INTEL_MAGIC_NUMBER 0x756e6547 +#define AMD_MAGIC_NUMBER 0x68747541 +#define UNRECOGNIZED_CPU 0xBADFF + +static cpuid_t get_cpuid(icpuid_t cpu); +static icpuid_t detect_cpu(void); +static icpuid_t intel_cpu(void); +static icpuid_t amd_cpu(void); +static icpuid_t generic_cpu(void); + +icpuid_t detect_cpu(void) { + uint32_t ebx, null; + icpuid_t i_cpu; + + cpuid(0, null, ebx, null, null); + + // Select CPU brand + switch(ebx) { + case INTEL_MAGIC_NUMBER: + i_cpu = intel_cpu(); + break; + case AMD_MAGIC_NUMBER: + i_cpu = amd_cpu(); + break; + default: + i_cpu = generic_cpu(); + break; + } + + return i_cpu; +} + +icpuid_t intel_cpu(void) { + uint32_t eax, ebx, null; + icpuid_t icpu; + + // Fill the structure + cpuid(1, eax, ebx, null, null); + icpu.model = (eax >> 4) & 0xF; + icpu.family = (eax >> 8) & 0xF; + icpu.type = (eax >> 12) & 0xF; + icpu.brand = INTEL_MAGIC_NUMBER; + icpu.stepping = eax & 0xF; + icpu.reserved = eax >> 14; + + return icpu; +} + +icpuid_t amd_cpu(void) { + uint32_t eax, null; + icpuid_t icpu; + + // Fill the structure + cpuid(1, eax, null, null, null); + icpu.model = (eax >> 4) & 0xF; + icpu.family = (eax >> 8) & 0xF; + icpu.stepping = eax & 0xF; + icpu.reserved = eax >> 12; + icpu.brand = AMD_MAGIC_NUMBER; + + return icpu; +} + +icpuid_t generic_cpu(void) { + icpuid_t icpu; + + icpu.brand = UNRECOGNIZED_CPU; // Magic number for unknown CPUs + + return icpu; +} + +cpuid_t get_cpuid(icpuid_t cpu) { + cpuid_t cpuid; + uint8_t model[64]; + + // Recognize CPU brand + if(cpu.brand == AMD_MAGIC_NUMBER) { + switch(cpu.family) { + case 4: + strcpy(model, (uint8_t*)"486 model "); // Set model name + strcat(model, (void*)cpu.model); // Set model version + cpuid.model = model; + break; + case 5: + switch(cpu.model) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + strcpy(model, (uint8_t*)"K6 model "); // Set model name + strcat(model, (void*)cpu.model); // Set model version + cpuid.model = model; + break; + case 8: + strcpy(model, (uint8_t*)"K6-2 model "); // Set model name + strcat(model, (void*)cpu.model); // Set model version + cpuid.model = model; + break; + case 9: + strcpy(model, (uint8_t*)"K6-III model "); // Set model name + strcat(model, (void*)cpu.model); // Set model version + cpuid.model = model; + break; + default: + strcpy(model, (uint8_t*)"K5/K6 model "); // Set model name + strcat(model, (void*)cpu.model); // Set model version + cpuid.model = model; + break; + } + break; + case 6: + switch(cpu.model) { + case 1: + case 2: + case 3: + cpuid.model = (uint8_t*)"Duron model 3"; + break; + case 4: + strcpy(model, (uint8_t*)"Athlon model "); + strcat(model, (void*)cpu.model); + cpuid.model = model; + break; + case 6: + cpuid.model = (uint8_t*)"Athlon MP/Mobile Athlon Model 6"; + break; + case 7: + cpuid.model = (uint8_t*)"Mobile Duron Model 7"; + break; + default: + strcpy(model, (uint8_t*)"Duron/Athlon model "); + strcat(model, (void*)cpu.model); + cpuid.model = model; + break; + } + break; + } + } else if(cpu.brand == INTEL_MAGIC_NUMBER) { + switch(cpu.type) { + case 0: + cpuid.type =(uint8_t*)"Original OEM"; + break; + case 1: + cpuid.type = (uint8_t*)"Overdrive"; + break; + case 2: + cpuid.type = (uint8_t*)"Dual-capable"; + break; + case 3: + cpuid.type = (uint8_t*)"Reserved"; + break; + } + + switch(cpu.family) { + case 3: + cpuid.family = (uint8_t*)"i386"; + break; + case 4: + cpuid.family = (uint8_t*)"i486"; + break; + case 5: + cpuid.family = (uint8_t*)"Pentium II Model 5/Xeon/Celeron"; + break; + case 6: + cpuid.family = (uint8_t*)"Pentium Pro"; + break; + case 15: + cpuid.family = (uint8_t*)"Pentium 4"; + break; + } + } else if(cpu.brand == UNRECOGNIZED_CPU) + cpuid.family = (uint8_t*)"Generic (x86) CPU"; + + return cpuid; +} + +uint8_t *get_cpu_type() { + icpuid_t icpu = detect_cpu(); // Detect CPU brand(Intel, AMD or generic x86) + cpuid_t cpu_type = get_cpuid(icpu); + + return (uint8_t*)cpu_type.type; +} + +uint8_t *get_cpu_family() { + icpuid_t icpu = detect_cpu(); // Detect CPU brand(Intel, AMD or generic x86) + cpuid_t cpu_family = get_cpuid(icpu); + + return (uint8_t*)cpu_family.family; + +} diff --git a/kernel/drivers/cpuid.h b/kernel/drivers/cpuid.h index ab11068..4198821 100644 --- a/kernel/drivers/cpuid.h +++ b/kernel/drivers/cpuid.h @@ -1,36 +1,36 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef CPUID_H -#define CPUID_H - -#include -#define cpuid(in, a, b, c, d) __asm__("cpuid": "=a" (a), "=b"(b), "=d" (d) : "a" (in)); - -typedef struct { - uint32_t model; - uint32_t family; - uint32_t type; - uint32_t brand; - uint32_t stepping; - uint32_t reserved; -} icpuid_t; - -typedef struct { - uint8_t *model; - uint8_t *family; - uint8_t *type; - uint8_t *brand; - uint8_t *stepping; - uint8_t *reserved; -} cpuid_t; - -// return type and family processor -uint8_t *get_cpu_type(); -uint8_t *get_cpu_family(); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef CPUID_H +#define CPUID_H + +#include +#define cpuid(in, a, b, c, d) __asm__("cpuid": "=a" (a), "=b"(b), "=d" (d) : "a" (in)); + +typedef struct { + uint32_t model; + uint32_t family; + uint32_t type; + uint32_t brand; + uint32_t stepping; + uint32_t reserved; +} icpuid_t; + +typedef struct { + uint8_t *model; + uint8_t *family; + uint8_t *type; + uint8_t *brand; + uint8_t *stepping; + uint8_t *reserved; +} cpuid_t; + +// return type and family processor +uint8_t *get_cpu_type(); +uint8_t *get_cpu_family(); + +#endif diff --git a/kernel/drivers/fs.c b/kernel/drivers/fs.c index 7a49a6a..3ceb824 100644 --- a/kernel/drivers/fs.c +++ b/kernel/drivers/fs.c @@ -1,47 +1,47 @@ -#include "fs.h" - -fs_node_t *fs_root = 0; // Initialize the root of the filesystem - -uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - // Check if inode got a read callback from the kernel - if(node->read != 0) - return node->read(node, offset, size, buffer); - else - return 0; -} - -uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - // Check if inode got a write callback from the kernel - if(node->write != 0) - return node->write(node, offset, size, buffer); - else - return 0; -} - -void open_fs(fs_node_t *node) { - // Check if inode got a open callback from the kernel - if(node->open != 0) - return node->open(node); -} - -void close_fs(fs_node_t *node) { - // Check if inode got a close callback from the kernel - if(node->close != 0) - return node->close(node); -} - -struct dirent *readdir_fs(fs_node_t *node, uint32_t index) { - // Read dir content(only if file descriptor is FS_DIRECTORY) - if((node->flags&0x7) == FS_DIRECTORY && node->readdir != 0) - return node->readdir(node, index); - else - return 0; -} - -fs_node_t *finddir_fs(fs_node_t *node, char *name) { - // Check if an inode is a directory - if((node->flags&0x7) == FS_DIRECTORY && node->finddir != 0) - return node->finddir(node, name); - else - return 0; +#include "fs.h" + +fs_node_t *fs_root = 0; // Initialize the root of the filesystem + +uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + // Check if inode got a read callback from the kernel + if(node->read != 0) + return node->read(node, offset, size, buffer); + else + return 0; +} + +uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + // Check if inode got a write callback from the kernel + if(node->write != 0) + return node->write(node, offset, size, buffer); + else + return 0; +} + +void open_fs(fs_node_t *node) { + // Check if inode got a open callback from the kernel + if(node->open != 0) + return node->open(node); +} + +void close_fs(fs_node_t *node) { + // Check if inode got a close callback from the kernel + if(node->close != 0) + return node->close(node); +} + +struct dirent *readdir_fs(fs_node_t *node, uint32_t index) { + // Read dir content(only if file descriptor is FS_DIRECTORY) + if((node->flags&0x7) == FS_DIRECTORY && node->readdir != 0) + return node->readdir(node, index); + else + return 0; +} + +fs_node_t *finddir_fs(fs_node_t *node, char *name) { + // Check if an inode is a directory + if((node->flags&0x7) == FS_DIRECTORY && node->finddir != 0) + return node->finddir(node, name); + else + return 0; } \ No newline at end of file diff --git a/kernel/drivers/fs.h b/kernel/drivers/fs.h index cc5385d..5af137e 100644 --- a/kernel/drivers/fs.h +++ b/kernel/drivers/fs.h @@ -1,84 +1,84 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef FS_H -#define FS_H - -#include -/* This Virtual File System(VFS) is a simplified version of - * standard UNIX VFS where all files comes organized in a graph - * of nodes. Keeping in mind the concept of "everything is a file" we can - * store a file, a directory, a serial device or anything else just by adding - * a new node to the data structure. - * And this is a list of common operations: - * - Open: Initialize a new node as a file descriptor - * - Close: CLose a node - * - Read: return the content of a node - * - Write: set content to node - * - Readdir: Return directory content - * - Finddir: Given a specific name find the corresponding child node.*/ - -// Define some standard node types -#define FS_FILE 0x01 -#define FS_DIRECTORY 0x02 -#define FS_CHARDEVICE 0x03 -#define FS_BLOCKDEVICE 0x04 -#define FS_PIPE 0x05 -#define FS_SYMLINK 0x06 -#define FS_MOUNTPOINT 0x08 - -struct fs_node; - -/* Define some callbacks to be called when read/write/open/close - * operations are called */ -typedef uint32_t (*read_type_t)(struct fs_node*, uint32_t, uint32_t, uint8_t*); -typedef uint32_t (*write_type_t)(struct fs_node*, uint32_t, uint32_t, uint8_t*); -typedef void (*open_type_t)(struct fs_node*); -typedef void (*close_type_t)(struct fs_node*); -typedef struct dirent*(*readdir_type_t)(struct fs_node*, uint32_t); -typedef struct fs_node*(*finddir_type_t)(struct fs_node*, char *name); - -// This define the structure of a node -typedef struct fs_node { - uint8_t name[128]; // File name - uint32_t mask; // Permission mask - uint32_t uid; // Owning user - uint32_t gid; // Owning group - uint32_t flags; // Node type - uint32_t inode; // used by file systems to identify files - uint32_t length; // Length of the file, in bytes. - uint32_t impl; - // Callback section - read_type_t read; - write_type_t write; - open_type_t open; - close_type_t close; - readdir_type_t readdir; - finddir_type_t finddir; - struct fs_node *ptr; // Used by mountpoints and symlinks -} fs_node_t; - -struct dirent { - uint8_t name[120]; // File name - uint32_t ino; // POSIX standard requires inode number; -}; - -// Filesystem root -extern fs_node_t *fs_root; - -/* Write/Read/Open/Close operations - * NOTE: those functions are NOT like the Callback - * functions; the first one deals with inodes while - * the second one deals with file descriptors. */ -uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); -uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); -void open_fs(fs_node_t *node); -void close_fs(fs_node_t *node); -struct dirent *readdir_fs(fs_node_t *node, uint32_t index); -fs_node_t *finddir_fs(fs_node_t *node, char *name); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef FS_H +#define FS_H + +#include +/* This Virtual File System(VFS) is a simplified version of + * standard UNIX VFS where all files comes organized in a graph + * of nodes. Keeping in mind the concept of "everything is a file" we can + * store a file, a directory, a serial device or anything else just by adding + * a new node to the data structure. + * And this is a list of common operations: + * - Open: Initialize a new node as a file descriptor + * - Close: CLose a node + * - Read: return the content of a node + * - Write: set content to node + * - Readdir: Return directory content + * - Finddir: Given a specific name find the corresponding child node.*/ + +// Define some standard node types +#define FS_FILE 0x01 +#define FS_DIRECTORY 0x02 +#define FS_CHARDEVICE 0x03 +#define FS_BLOCKDEVICE 0x04 +#define FS_PIPE 0x05 +#define FS_SYMLINK 0x06 +#define FS_MOUNTPOINT 0x08 + +struct fs_node; + +/* Define some callbacks to be called when read/write/open/close + * operations are called */ +typedef uint32_t (*read_type_t)(struct fs_node*, uint32_t, uint32_t, uint8_t*); +typedef uint32_t (*write_type_t)(struct fs_node*, uint32_t, uint32_t, uint8_t*); +typedef void (*open_type_t)(struct fs_node*); +typedef void (*close_type_t)(struct fs_node*); +typedef struct dirent*(*readdir_type_t)(struct fs_node*, uint32_t); +typedef struct fs_node*(*finddir_type_t)(struct fs_node*, char *name); + +// This define the structure of a node +typedef struct fs_node { + uint8_t name[128]; // File name + uint32_t mask; // Permission mask + uint32_t uid; // Owning user + uint32_t gid; // Owning group + uint32_t flags; // Node type + uint32_t inode; // used by file systems to identify files + uint32_t length; // Length of the file, in bytes. + uint32_t impl; + // Callback section + read_type_t read; + write_type_t write; + open_type_t open; + close_type_t close; + readdir_type_t readdir; + finddir_type_t finddir; + struct fs_node *ptr; // Used by mountpoints and symlinks +} fs_node_t; + +struct dirent { + uint8_t name[120]; // File name + uint32_t ino; // POSIX standard requires inode number; +}; + +// Filesystem root +extern fs_node_t *fs_root; + +/* Write/Read/Open/Close operations + * NOTE: those functions are NOT like the Callback + * functions; the first one deals with inodes while + * the second one deals with file descriptors. */ +uint32_t read_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +uint32_t write_fs(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +void open_fs(fs_node_t *node); +void close_fs(fs_node_t *node); +struct dirent *readdir_fs(fs_node_t *node, uint32_t index); +fs_node_t *finddir_fs(fs_node_t *node, char *name); + +#endif diff --git a/kernel/drivers/gdt.c b/kernel/drivers/gdt.c index c675d4b..ab40ac6 100644 --- a/kernel/drivers/gdt.c +++ b/kernel/drivers/gdt.c @@ -1,103 +1,103 @@ -#include "gdt.h" - -// Internal method -extern void gdt_flush(uint32_t); // Defined on cpu/gdt.asm -static gdt_entry_t construct_null_entry(); -static gdt_entry_t construct_entry(gdt_access_t access); -static void init_gdt(); - -gdt_entry_t gdt_entries[5]; -gdt_ptr_t gdt_ptr; - - -// This method will be called by the kernel -void gdt_setup() { - init_gdt(); -} - -static void init_gdt() { - gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; - gdt_ptr.base = (uint32_t)&gdt_entries; - - gdt_entry_t null_segment = construct_null_entry(); - gdt_entry_t kernel_mode_code_segment = construct_entry( - (struct gdt_access){ - .type = GDT_CODE_TYPE_EXEC_READ, - .dt = GDT_CODE_AND_DATA_DESCRIPTOR, - .dpl = GDT_RING0, - .p = GDT_SEGMENT_PRESENT - } - ); - gdt_entry_t kernel_mode_data_segment = construct_entry( - (struct gdt_access){ - .type = GDT_DATA_TYPE_READ_WRITE, - .dt = GDT_CODE_AND_DATA_DESCRIPTOR, - .dpl = GDT_RING0, - .p = GDT_SEGMENT_PRESENT - } - ); - gdt_entry_t user_mode_code_segment = construct_entry( - (struct gdt_access){ - .type = GDT_CODE_TYPE_EXEC_READ, - .dt = GDT_CODE_AND_DATA_DESCRIPTOR, - .dpl = GDT_RING3, - .p = GDT_SEGMENT_PRESENT - } - ); - gdt_entry_t user_mode_data_segment = construct_entry( - (struct gdt_access){ - .type = GDT_DATA_TYPE_READ_WRITE, - .dt = GDT_CODE_AND_DATA_DESCRIPTOR, - .dpl = GDT_RING3, - .p = GDT_SEGMENT_PRESENT - } - ); - - gdt_entries[0] = null_segment; - gdt_entries[1] = kernel_mode_code_segment; - gdt_entries[2] = kernel_mode_data_segment; - gdt_entries[3] = user_mode_code_segment; - gdt_entries[4] = user_mode_data_segment; - - gdt_flush((uint32_t)&gdt_ptr); -} - -static gdt_entry_t construct_entry(gdt_access_t access) { - gdt_entry_t entry = (struct gdt_entry_struct) { - .base_low = GDT_BASE & 0xFFFF, - .base_middle = (GDT_BASE >> 16) & 0xFF, - .base_high = (GDT_BASE >> 24) & 0xFF, - .limit_low = (GDT_LIMIT & 0xFFFF), - .access = access, - .granularity = (struct gdt_granularity) { - .g = GDT_GRANULARITY_4K, - .d = GDT_OPERAND_SIZE_32, - .zero = 0, - .seglen = GDT_SEGMENT_LENGTH - } - }; - return entry; -} - -// The only difference is in the access -static gdt_entry_t construct_null_entry() { - gdt_entry_t null_entry = (struct gdt_entry_struct) { - .base_low = 0, - .base_middle = 0, - .base_high = 0, - .limit_low = 0, - .access = (struct gdt_access) { - .p = 0, - .dpl = 0, - .dt = 0, - .type = 0 - }, - .granularity = (struct gdt_granularity) { - .g = 0, - .d = 0, - .zero = 0, - .seglen = 0 - } - }; - return null_entry; +#include "gdt.h" + +// Internal method +extern void gdt_flush(uint32_t); // Defined on cpu/gdt.asm +static gdt_entry_t construct_null_entry(); +static gdt_entry_t construct_entry(gdt_access_t access); +static void init_gdt(); + +gdt_entry_t gdt_entries[5]; +gdt_ptr_t gdt_ptr; + + +// This method will be called by the kernel +void gdt_setup() { + init_gdt(); +} + +static void init_gdt() { + gdt_ptr.limit = (sizeof(gdt_entry_t) * 5) - 1; + gdt_ptr.base = (uint32_t)&gdt_entries; + + gdt_entry_t null_segment = construct_null_entry(); + gdt_entry_t kernel_mode_code_segment = construct_entry( + (struct gdt_access){ + .type = GDT_CODE_TYPE_EXEC_READ, + .dt = GDT_CODE_AND_DATA_DESCRIPTOR, + .dpl = GDT_RING0, + .p = GDT_SEGMENT_PRESENT + } + ); + gdt_entry_t kernel_mode_data_segment = construct_entry( + (struct gdt_access){ + .type = GDT_DATA_TYPE_READ_WRITE, + .dt = GDT_CODE_AND_DATA_DESCRIPTOR, + .dpl = GDT_RING0, + .p = GDT_SEGMENT_PRESENT + } + ); + gdt_entry_t user_mode_code_segment = construct_entry( + (struct gdt_access){ + .type = GDT_CODE_TYPE_EXEC_READ, + .dt = GDT_CODE_AND_DATA_DESCRIPTOR, + .dpl = GDT_RING3, + .p = GDT_SEGMENT_PRESENT + } + ); + gdt_entry_t user_mode_data_segment = construct_entry( + (struct gdt_access){ + .type = GDT_DATA_TYPE_READ_WRITE, + .dt = GDT_CODE_AND_DATA_DESCRIPTOR, + .dpl = GDT_RING3, + .p = GDT_SEGMENT_PRESENT + } + ); + + gdt_entries[0] = null_segment; + gdt_entries[1] = kernel_mode_code_segment; + gdt_entries[2] = kernel_mode_data_segment; + gdt_entries[3] = user_mode_code_segment; + gdt_entries[4] = user_mode_data_segment; + + gdt_flush((uint32_t)&gdt_ptr); +} + +static gdt_entry_t construct_entry(gdt_access_t access) { + gdt_entry_t entry = (struct gdt_entry_struct) { + .base_low = GDT_BASE & 0xFFFF, + .base_middle = (GDT_BASE >> 16) & 0xFF, + .base_high = (GDT_BASE >> 24) & 0xFF, + .limit_low = (GDT_LIMIT & 0xFFFF), + .access = access, + .granularity = (struct gdt_granularity) { + .g = GDT_GRANULARITY_4K, + .d = GDT_OPERAND_SIZE_32, + .zero = 0, + .seglen = GDT_SEGMENT_LENGTH + } + }; + return entry; +} + +// The only difference is in the access +static gdt_entry_t construct_null_entry() { + gdt_entry_t null_entry = (struct gdt_entry_struct) { + .base_low = 0, + .base_middle = 0, + .base_high = 0, + .limit_low = 0, + .access = (struct gdt_access) { + .p = 0, + .dpl = 0, + .dt = 0, + .type = 0 + }, + .granularity = (struct gdt_granularity) { + .g = 0, + .d = 0, + .zero = 0, + .seglen = 0 + } + }; + return null_entry; } \ No newline at end of file diff --git a/kernel/drivers/gdt.h b/kernel/drivers/gdt.h index d105985..a7fa647 100644 --- a/kernel/drivers/gdt.h +++ b/kernel/drivers/gdt.h @@ -1,139 +1,139 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _GDT_H_ -#define _GDT_H_ - -#include -/* - * First a bit of theory: - * GDT(Global Descriptor Table) is a complex data structure used in x86 systems - * to define memory areas. - * Technically speaking GDT is formed by an array of 8-bytes segment descriptors, - * the first descriptor of the GDT is always a NULL one and CANNOT be used to allocate - * memory; so we need at least two descriptors(plus the null descriptor) to successfully allocate - * data on our memory. - * In x86 architecture there're two methods to provide virtual memory: Segmentation and Paging: - * With the first one every memory access is done within his own segment, so each address(of a process) - * is added to the segment's base address and checked against the segment's length. - * With paging, however, the address space is split into blocks(usually of 4KiB) called pages. - * Each page can be mapped to physical memory or it can be unmapped(to create virtual memory). - * Segmentation is a built-in functionality of x86 architecture, so to get around this we need to - * define our own GDT. A cool thing segmentation can do for us is to set Ring Level: - * a privilege level to allow our process to run in a 'unprivileged' mode(called user mode, ring 3) - * and to allow drivers(or kernel related stuff) to run in a 'supervisor-mode'(called kernel mode, ring 0). - * Usually bootloader(such as GRUB) sets up GDT for us, the problem is that we cannot known where it is or - * if it is has been overwritten during some other tasks. So it's a good idea to implement - * a new GDT ourself. - */ - -/* Those values were taken from Intel's developer manual */ - -// GDT fields -#define GDT_BASE 0x00000000 -#define GDT_LIMIT 0xFFFFFFFF -// GDT granularity -#define GDT_SEGMENT_LENGTH 0xF -#define GDT_OPERAND_SIZE_16 0 -#define GDT_OPERAND_SIZE_32 1 -#define GDT_GRANULARITY_1K 0 -#define GDT_GRANULARITY_4K 1 -// GDT access type fields -#define GDT_DATA_TYPE_READ_ONLY 0x0 -#define GDT_DATA_TYPE_READ_ONLY_ACCESSED 0x1 -#define GDT_DATA_TYPE_READ_WRITE 0x2 -#define GDT_DATA_TYPE_READ_WRITE_ACCESSED 0x3 -#define GDT_DATA_TYPE_READ_ONLY_EXPAND_DOWN 0x4 -#define GDT_DATA_TYPE_READ_ONLY_EXPAND_DOWN_ACCESSED 0x5 -#define GDT_DATA_TYPE_READ_WRITE_EXPAND_DOWN 0x6 -#define GDT_DATA_TYPE_READ_WRITE_EXPAND_DOWN_ACCESSED 0x7 -#define GDT_DATA_TYPE_EXEC_ONLY 0x8 -#define GDT_CODE_TYPE_EXEC_ONLY_ACCESSED 0x9 -#define GDT_CODE_TYPE_EXEC_READ 0xA -#define GDT_CODE_TYPE_EXEC_READ_ACCESSED 0xB -#define GDT_CODE_TYPE_EXEC_CONFORMING 0xC -#define GDT_CODE_TYPE_EXEC_CONFORMING_ACCESSED 0xD -#define GDT_CODE_TYPE_EXEC_READ_CONFORMING 0xE -#define GDT_CODE_TYPE_EXEC_READ_CONFORMING_ACCESSED 0xF -// Descriptor type fields -#define GDT_SYSTEM_DESCRIPTOR 0 -#define GDT_CODE_AND_DATA_DESCRIPTOR 1 -// GDT Ring number -#define GDT_RING0 0 -#define GDT_RING1 1 -#define GDT_RING2 2 -#define GDT_RING3 3 -// 'Present' field -#define GDT_SEGMENT_NOT_PRESENT 0 -#define GDT_SEGMENT_PRESENT 1 - - -/* Global Descriptor Table (GDT) implementation */ -/* gdt_access is used to access portion of the GDT - * | 0 - 3 | 4 | 3 - 6 | 7 | - * | Type | DT | DPL | P | - * Type: Which type - * DT: descriptor type - * DPL: Kernel ring(0-3) - * P: is segment present? (bool) - */ -struct gdt_access { - uint8_t type: 4; // 4 Bits - uint8_t dt: 1; // 1 Bit - uint8_t dpl: 2; // 2 Bits - uint8_t p: 1; // 1 Bits -}__attribute__((packed)); -typedef struct gdt_access gdt_access_t; - -/* gdt_granularity is used to get portion of GDT entry - * | 0 - 3 | 4 | 5 | 6 | 7 | - * | seglen | 0 | D | G | - * seglen: segment length - * 0: Always zero - * D: Operand size (0 = 16 bit, 1 = 32 bit) - * G: granularity (0 = 1 Byte, 1 = 4KiB) - */ -struct gdt_granularity { - uint8_t seglen: 4; - uint8_t zero: 2; - uint8_t d: 1; - uint8_t g: 1; -}__attribute__((packed)); -typedef struct gdt_granularity gdt_gran_t; - -/* gdt_entry_struct contains the value of a single GDT entry - * Each slice is 64 bits. - * | 0 - 15 | 16 - 31 | 32 - 39 | 40 - 47 | 48 - 55 | 56 - 63 | - * | lim low| base low|base mid | access | gran | base hg | - * lim low: Lower 16 bits of the limit - * base low: Lower 16 bits of the base - * base mid: Next 8 bits of the base - * access: access flag, e.g. which ring this segment can be used in. - * gran. -*/ -struct gdt_entry_struct { - uint16_t limit_low; - uint16_t base_low; - uint8_t base_middle; - gdt_access_t access; - gdt_gran_t granularity; - uint8_t base_high; -}__attribute__((packed)); -typedef struct gdt_entry_struct gdt_entry_t; - -/* Also we have to define a pointer to the data structure - * This is needed to locate it later */ -struct gdt_ptr { - uint16_t limit; - uint32_t base; -}__attribute__((packed)); -typedef struct gdt_ptr gdt_ptr_t; - -/* GDT Kernel API */ -void gdt_setup(); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _GDT_H_ +#define _GDT_H_ + +#include +/* + * First a bit of theory: + * GDT(Global Descriptor Table) is a complex data structure used in x86 systems + * to define memory areas. + * Technically speaking GDT is formed by an array of 8-bytes segment descriptors, + * the first descriptor of the GDT is always a NULL one and CANNOT be used to allocate + * memory; so we need at least two descriptors(plus the null descriptor) to successfully allocate + * data on our memory. + * In x86 architecture there're two methods to provide virtual memory: Segmentation and Paging: + * With the first one every memory access is done within his own segment, so each address(of a process) + * is added to the segment's base address and checked against the segment's length. + * With paging, however, the address space is split into blocks(usually of 4KiB) called pages. + * Each page can be mapped to physical memory or it can be unmapped(to create virtual memory). + * Segmentation is a built-in functionality of x86 architecture, so to get around this we need to + * define our own GDT. A cool thing segmentation can do for us is to set Ring Level: + * a privilege level to allow our process to run in a 'unprivileged' mode(called user mode, ring 3) + * and to allow drivers(or kernel related stuff) to run in a 'supervisor-mode'(called kernel mode, ring 0). + * Usually bootloader(such as GRUB) sets up GDT for us, the problem is that we cannot known where it is or + * if it is has been overwritten during some other tasks. So it's a good idea to implement + * a new GDT ourself. + */ + +/* Those values were taken from Intel's developer manual */ + +// GDT fields +#define GDT_BASE 0x00000000 +#define GDT_LIMIT 0xFFFFFFFF +// GDT granularity +#define GDT_SEGMENT_LENGTH 0xF +#define GDT_OPERAND_SIZE_16 0 +#define GDT_OPERAND_SIZE_32 1 +#define GDT_GRANULARITY_1K 0 +#define GDT_GRANULARITY_4K 1 +// GDT access type fields +#define GDT_DATA_TYPE_READ_ONLY 0x0 +#define GDT_DATA_TYPE_READ_ONLY_ACCESSED 0x1 +#define GDT_DATA_TYPE_READ_WRITE 0x2 +#define GDT_DATA_TYPE_READ_WRITE_ACCESSED 0x3 +#define GDT_DATA_TYPE_READ_ONLY_EXPAND_DOWN 0x4 +#define GDT_DATA_TYPE_READ_ONLY_EXPAND_DOWN_ACCESSED 0x5 +#define GDT_DATA_TYPE_READ_WRITE_EXPAND_DOWN 0x6 +#define GDT_DATA_TYPE_READ_WRITE_EXPAND_DOWN_ACCESSED 0x7 +#define GDT_DATA_TYPE_EXEC_ONLY 0x8 +#define GDT_CODE_TYPE_EXEC_ONLY_ACCESSED 0x9 +#define GDT_CODE_TYPE_EXEC_READ 0xA +#define GDT_CODE_TYPE_EXEC_READ_ACCESSED 0xB +#define GDT_CODE_TYPE_EXEC_CONFORMING 0xC +#define GDT_CODE_TYPE_EXEC_CONFORMING_ACCESSED 0xD +#define GDT_CODE_TYPE_EXEC_READ_CONFORMING 0xE +#define GDT_CODE_TYPE_EXEC_READ_CONFORMING_ACCESSED 0xF +// Descriptor type fields +#define GDT_SYSTEM_DESCRIPTOR 0 +#define GDT_CODE_AND_DATA_DESCRIPTOR 1 +// GDT Ring number +#define GDT_RING0 0 +#define GDT_RING1 1 +#define GDT_RING2 2 +#define GDT_RING3 3 +// 'Present' field +#define GDT_SEGMENT_NOT_PRESENT 0 +#define GDT_SEGMENT_PRESENT 1 + + +/* Global Descriptor Table (GDT) implementation */ +/* gdt_access is used to access portion of the GDT + * | 0 - 3 | 4 | 3 - 6 | 7 | + * | Type | DT | DPL | P | + * Type: Which type + * DT: descriptor type + * DPL: Kernel ring(0-3) + * P: is segment present? (bool) + */ +struct gdt_access { + uint8_t type: 4; // 4 Bits + uint8_t dt: 1; // 1 Bit + uint8_t dpl: 2; // 2 Bits + uint8_t p: 1; // 1 Bits +}__attribute__((packed)); +typedef struct gdt_access gdt_access_t; + +/* gdt_granularity is used to get portion of GDT entry + * | 0 - 3 | 4 | 5 | 6 | 7 | + * | seglen | 0 | D | G | + * seglen: segment length + * 0: Always zero + * D: Operand size (0 = 16 bit, 1 = 32 bit) + * G: granularity (0 = 1 Byte, 1 = 4KiB) + */ +struct gdt_granularity { + uint8_t seglen: 4; + uint8_t zero: 2; + uint8_t d: 1; + uint8_t g: 1; +}__attribute__((packed)); +typedef struct gdt_granularity gdt_gran_t; + +/* gdt_entry_struct contains the value of a single GDT entry + * Each slice is 64 bits. + * | 0 - 15 | 16 - 31 | 32 - 39 | 40 - 47 | 48 - 55 | 56 - 63 | + * | lim low| base low|base mid | access | gran | base hg | + * lim low: Lower 16 bits of the limit + * base low: Lower 16 bits of the base + * base mid: Next 8 bits of the base + * access: access flag, e.g. which ring this segment can be used in. + * gran. +*/ +struct gdt_entry_struct { + uint16_t limit_low; + uint16_t base_low; + uint8_t base_middle; + gdt_access_t access; + gdt_gran_t granularity; + uint8_t base_high; +}__attribute__((packed)); +typedef struct gdt_entry_struct gdt_entry_t; + +/* Also we have to define a pointer to the data structure + * This is needed to locate it later */ +struct gdt_ptr { + uint16_t limit; + uint32_t base; +}__attribute__((packed)); +typedef struct gdt_ptr gdt_ptr_t; + +/* GDT Kernel API */ +void gdt_setup(); + +#endif diff --git a/kernel/drivers/idt.c b/kernel/drivers/idt.c index 4ca3936..ee5033c 100644 --- a/kernel/drivers/idt.c +++ b/kernel/drivers/idt.c @@ -1,122 +1,122 @@ -#include "idt.h" -#include "../libc/string.h" -#include "ports.h" - -// Internal method -extern void idt_flush(idt_ptr_t*); // defined on cpu/idt.asm -static void init_idt(); -static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags); -static void pic_remap(uint8_t offset1, uint8_t offset2); - -idt_entry_t idt_entries[256]; // 256 interrupts -idt_ptr_t idt_ptr; - -// This method will be called by the kernel -void idt_setup() { - init_idt(); -} - -static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags) { - idt_entries[idx] = (struct idt_entry) { - .base_low = (uint32_t)base & 0xFFFF, - .base_high = ((uint32_t)base >> 16) & 0xFFFF, - .seg_sel = selector, - .flags = flags - }; -} - -static void init_idt() { - idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1; - idt_ptr.base = idt_entries; - - memset(&idt_entries, 0, sizeof(idt_entry_t) * 256); - - idt_flags_t flags = { - .reserved = IDT_FLAG_RESERVED, // Always 0x0E - .dpl = 0, - .p = 1 - }; - // Remap IDT with ISRs - idt_set_gate(0, isr0, 0x08, flags); - idt_set_gate(1, isr1, 0x08, flags); - idt_set_gate(2, isr2, 0x08, flags); - idt_set_gate(3, isr3, 0x08, flags); - idt_set_gate(4, isr4, 0x08, flags); - idt_set_gate(5, isr5, 0x08, flags); - idt_set_gate(6, isr6, 0x08, flags); - idt_set_gate(7, isr7, 0x08, flags); - idt_set_gate(8, isr8, 0x08, flags); - idt_set_gate(9, isr9, 0x08, flags); - idt_set_gate(10, isr10, 0x08, flags); - idt_set_gate(11, isr11, 0x08, flags); - idt_set_gate(12, isr12, 0x08, flags); - idt_set_gate(13, isr13, 0x08, flags); - idt_set_gate(14, isr14, 0x08, flags); - idt_set_gate(15, isr15, 0x08, flags); - idt_set_gate(16, isr16, 0x08, flags); - idt_set_gate(17, isr17, 0x08, flags); - idt_set_gate(18, isr18, 0x08, flags); - idt_set_gate(19, isr19, 0x08, flags); - idt_set_gate(20, isr20, 0x08, flags); - idt_set_gate(21, isr21, 0x08, flags); - idt_set_gate(22, isr22, 0x08, flags); - idt_set_gate(23, isr23, 0x08, flags); - idt_set_gate(24, isr24, 0x08, flags); - idt_set_gate(25, isr25, 0x08, flags); - idt_set_gate(26, isr26, 0x08, flags); - idt_set_gate(27, isr27, 0x08, flags); - idt_set_gate(28, isr28, 0x08, flags); - idt_set_gate(29, isr29, 0x08, flags); - idt_set_gate(30, isr30, 0x08, flags); - idt_set_gate(31, isr31, 0x08, flags); - - // Remap PIC - pic_remap(PIC1_START_INTERRUPT, PIC2_START_INTERRUPT); - - // Also remap 15 entries for IRQs - idt_set_gate(32, irq0, 0x08, flags); - idt_set_gate(33, irq1, 0x08, flags); - idt_set_gate(34, irq2, 0x08, flags); - idt_set_gate(35, irq3, 0x08, flags); - idt_set_gate(36, irq4, 0x08, flags); - idt_set_gate(37, irq5, 0x08, flags); - idt_set_gate(38, irq6, 0x08, flags); - idt_set_gate(39, irq7, 0x08, flags); - idt_set_gate(40, irq8, 0x08, flags); - idt_set_gate(41, irq9, 0x08, flags); - idt_set_gate(42, irq10, 0x08, flags); - idt_set_gate(43, irq11, 0x08, flags); - idt_set_gate(44, irq12, 0x08, flags); - idt_set_gate(45, irq13, 0x08, flags); - idt_set_gate(46, irq14, 0x08, flags); - idt_set_gate(47, irq15, 0x08, flags); - - idt_flush(&idt_ptr); - - // Finally enable hardware interrupts with an assembly instruction - __asm__ __volatile__ ("sti"); -} - -// Taken from: http://wiki.osdev.org/8259_PIC -static void pic_remap(uint8_t offset1, uint8_t offset2) { - uint8_t a1, a2; - - a1 = inb(PIC1_DATA); // Save masks - a2 = inb(PIC2_DATA); - - outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); // Start init sequence - outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4); - - outb(PIC1_DATA, offset1); - outb(PIC2_DATA, offset2); - - outb(PIC1_DATA, 4); // Tell master PIC that there is a slave PIC at IRQ2 - outb(PIC1_DATA, 2); // Tell salve PIC it's cascade identity - - outb(PIC1_DATA, ICW4_8086); - outb(PIC2_DATA, ICW4_8086); - - // Restore saved masks - outb(PIC1_DATA, a1); - outb(PIC2_DATA, a2); +#include "idt.h" +#include "../libc/string.h" +#include "ports.h" + +// Internal method +extern void idt_flush(idt_ptr_t*); // defined on cpu/idt.asm +static void init_idt(); +static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags); +static void pic_remap(uint8_t offset1, uint8_t offset2); + +idt_entry_t idt_entries[256]; // 256 interrupts +idt_ptr_t idt_ptr; + +// This method will be called by the kernel +void idt_setup() { + init_idt(); +} + +static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags) { + idt_entries[idx] = (struct idt_entry) { + .base_low = (uint32_t)base & 0xFFFF, + .base_high = ((uint32_t)base >> 16) & 0xFFFF, + .seg_sel = selector, + .flags = flags + }; +} + +static void init_idt() { + idt_ptr.limit = sizeof(idt_entry_t) * 256 - 1; + idt_ptr.base = idt_entries; + + memset(&idt_entries, 0, sizeof(idt_entry_t) * 256); + + idt_flags_t flags = { + .reserved = IDT_FLAG_RESERVED, // Always 0x0E + .dpl = 0, + .p = 1 + }; + // Remap IDT with ISRs + idt_set_gate(0, isr0, 0x08, flags); + idt_set_gate(1, isr1, 0x08, flags); + idt_set_gate(2, isr2, 0x08, flags); + idt_set_gate(3, isr3, 0x08, flags); + idt_set_gate(4, isr4, 0x08, flags); + idt_set_gate(5, isr5, 0x08, flags); + idt_set_gate(6, isr6, 0x08, flags); + idt_set_gate(7, isr7, 0x08, flags); + idt_set_gate(8, isr8, 0x08, flags); + idt_set_gate(9, isr9, 0x08, flags); + idt_set_gate(10, isr10, 0x08, flags); + idt_set_gate(11, isr11, 0x08, flags); + idt_set_gate(12, isr12, 0x08, flags); + idt_set_gate(13, isr13, 0x08, flags); + idt_set_gate(14, isr14, 0x08, flags); + idt_set_gate(15, isr15, 0x08, flags); + idt_set_gate(16, isr16, 0x08, flags); + idt_set_gate(17, isr17, 0x08, flags); + idt_set_gate(18, isr18, 0x08, flags); + idt_set_gate(19, isr19, 0x08, flags); + idt_set_gate(20, isr20, 0x08, flags); + idt_set_gate(21, isr21, 0x08, flags); + idt_set_gate(22, isr22, 0x08, flags); + idt_set_gate(23, isr23, 0x08, flags); + idt_set_gate(24, isr24, 0x08, flags); + idt_set_gate(25, isr25, 0x08, flags); + idt_set_gate(26, isr26, 0x08, flags); + idt_set_gate(27, isr27, 0x08, flags); + idt_set_gate(28, isr28, 0x08, flags); + idt_set_gate(29, isr29, 0x08, flags); + idt_set_gate(30, isr30, 0x08, flags); + idt_set_gate(31, isr31, 0x08, flags); + + // Remap PIC + pic_remap(PIC1_START_INTERRUPT, PIC2_START_INTERRUPT); + + // Also remap 15 entries for IRQs + idt_set_gate(32, irq0, 0x08, flags); + idt_set_gate(33, irq1, 0x08, flags); + idt_set_gate(34, irq2, 0x08, flags); + idt_set_gate(35, irq3, 0x08, flags); + idt_set_gate(36, irq4, 0x08, flags); + idt_set_gate(37, irq5, 0x08, flags); + idt_set_gate(38, irq6, 0x08, flags); + idt_set_gate(39, irq7, 0x08, flags); + idt_set_gate(40, irq8, 0x08, flags); + idt_set_gate(41, irq9, 0x08, flags); + idt_set_gate(42, irq10, 0x08, flags); + idt_set_gate(43, irq11, 0x08, flags); + idt_set_gate(44, irq12, 0x08, flags); + idt_set_gate(45, irq13, 0x08, flags); + idt_set_gate(46, irq14, 0x08, flags); + idt_set_gate(47, irq15, 0x08, flags); + + idt_flush(&idt_ptr); + + // Finally enable hardware interrupts with an assembly instruction + __asm__ __volatile__ ("sti"); +} + +// Taken from: http://wiki.osdev.org/8259_PIC +static void pic_remap(uint8_t offset1, uint8_t offset2) { + uint8_t a1, a2; + + a1 = inb(PIC1_DATA); // Save masks + a2 = inb(PIC2_DATA); + + outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); // Start init sequence + outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4); + + outb(PIC1_DATA, offset1); + outb(PIC2_DATA, offset2); + + outb(PIC1_DATA, 4); // Tell master PIC that there is a slave PIC at IRQ2 + outb(PIC1_DATA, 2); // Tell salve PIC it's cascade identity + + outb(PIC1_DATA, ICW4_8086); + outb(PIC2_DATA, ICW4_8086); + + // Restore saved masks + outb(PIC1_DATA, a1); + outb(PIC2_DATA, a2); } \ No newline at end of file diff --git a/kernel/drivers/idt.h b/kernel/drivers/idt.h index 0bd042f..dff263f 100644 --- a/kernel/drivers/idt.h +++ b/kernel/drivers/idt.h @@ -1,144 +1,144 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _IDT_H_ -#define _IDT_H_ - -#include -/* - * First a bit of theory: - * Sometimes you want to interrupt the processor from what it is currently doing - * and force it to do something more "critical", such as a timer update or a keyboard interrupt - * request(IRQ) fires. The processor, then, will handle those IRQs activating an - * interrupt handler(ISR, Interrupt Service Routines). In order to know where to find those - * ISRs, the CPU will use the IDT. So we can say that the Interrupt Description Table - * is another data structure(organized the same way as the GDT) that will provide a list - * of interrupts handlers(ISRs) to the CPU. - */ - -// Reserved bits in IDT entries -#define IDT_FLAG_RESERVED 0x0E - -// PIC -#define PIC1 0x20 // I/O address for master PIC -#define PIC2 0xA0 // I/O address for slave PIC -#define PIC1_COMMAND PIC1 -#define PIC1_DATA (PIC1+1) -#define PIC2_COMMAND PIC2 -#define PIC2_DATA (PIC2+1) -#define PIC1_START_INTERRUPT 0x20 // Master PIC after remapping -#define PIC2_START_INTERRUPT 0x28 // Slave PIC after remapping -#define PIC_EOI 0x20 // End of interrupt -#define ICW1_ICW4 0x01 -#define ICW1_SINGLE 0x02 -#define ICW1_INTERVAL4 0x04 -#define ICW1_LEVEL 0x08 -#define ICW1_INIT 0x10 -#define ICW4_8086 0x01 // 8086/88 (MCS-80/85) mode -#define ICW4_AUTO 0x02 -#define ICW4_BUF_SLAVE 0x08 -#define ICW4_BUF_MASTER 0x0C -#define ICW4_SFNM 0x10 - -/* Interrupt Descriptor Table */ -/* idt_flags contains access flag of a single IDT entry - * | 0 - 4 | 5 - 6 | 7 | - * | res | dpl | p | - * res: always 0x0E - * dpl: ring num (0 - 3) - * p: segment present (bool) -*/ -struct idt_flags { - uint8_t reserved: 5; - uint8_t dpl: 2; - uint8_t p: 1; -}__attribute__((packed)); -typedef struct idt_flags idt_flags_t; - - -/* idt_entry contains the value of an IDT entry - * Each entry is 64 bits(like GDT entry) - * | 0 - 15 | 16 - 31 | 32 - 39 | 40 - 47 | 48 - 63 | - * | b low | seg sel | res | flags | b high | - * b low: Lower 16 bits of the base - * seg sel: Segment selector for code segment - * res: always 0 - * flags: idt_flags struct - * b high: Higher 16 bits of the base -*/ -struct idt_entry { - uint16_t base_low; - uint16_t seg_sel; - uint8_t reserved; - idt_flags_t flags; - uint16_t base_high; -}__attribute__((packed)); -typedef struct idt_entry idt_entry_t; - -/* Also we have to define a pointer to the data structure - * This is needed to locate it later */ -struct idt_ptr { - uint16_t limit; - idt_entry_t *base; -}__attribute__((packed)); -typedef struct idt_ptr idt_ptr_t; - -/* IDT Kernel API */ -void idt_setup(); - -// ISRs method declaration -extern void isr0(); -extern void isr1(); -extern void isr2(); -extern void isr3(); -extern void isr4(); -extern void isr5(); -extern void isr6(); -extern void isr7(); -extern void isr8(); -extern void isr9(); -extern void isr10(); -extern void isr11(); -extern void isr12(); -extern void isr13(); -extern void isr14(); -extern void isr15(); -extern void isr16(); -extern void isr17(); -extern void isr18(); -extern void isr19(); -extern void isr20(); -extern void isr21(); -extern void isr22(); -extern void isr23(); -extern void isr24(); -extern void isr25(); -extern void isr26(); -extern void isr27(); -extern void isr28(); -extern void isr29(); -extern void isr30(); -extern void isr31(); - -extern void irq0(); -extern void irq1(); -extern void irq2(); -extern void irq3(); -extern void irq4(); -extern void irq5(); -extern void irq6(); -extern void irq7(); -extern void irq8(); -extern void irq9(); -extern void irq10(); -extern void irq11(); -extern void irq12(); -extern void irq13(); -extern void irq14(); -extern void irq15(); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _IDT_H_ +#define _IDT_H_ + +#include +/* + * First a bit of theory: + * Sometimes you want to interrupt the processor from what it is currently doing + * and force it to do something more "critical", such as a timer update or a keyboard interrupt + * request(IRQ) fires. The processor, then, will handle those IRQs activating an + * interrupt handler(ISR, Interrupt Service Routines). In order to know where to find those + * ISRs, the CPU will use the IDT. So we can say that the Interrupt Description Table + * is another data structure(organized the same way as the GDT) that will provide a list + * of interrupts handlers(ISRs) to the CPU. + */ + +// Reserved bits in IDT entries +#define IDT_FLAG_RESERVED 0x0E + +// PIC +#define PIC1 0x20 // I/O address for master PIC +#define PIC2 0xA0 // I/O address for slave PIC +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1+1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2+1) +#define PIC1_START_INTERRUPT 0x20 // Master PIC after remapping +#define PIC2_START_INTERRUPT 0x28 // Slave PIC after remapping +#define PIC_EOI 0x20 // End of interrupt +#define ICW1_ICW4 0x01 +#define ICW1_SINGLE 0x02 +#define ICW1_INTERVAL4 0x04 +#define ICW1_LEVEL 0x08 +#define ICW1_INIT 0x10 +#define ICW4_8086 0x01 // 8086/88 (MCS-80/85) mode +#define ICW4_AUTO 0x02 +#define ICW4_BUF_SLAVE 0x08 +#define ICW4_BUF_MASTER 0x0C +#define ICW4_SFNM 0x10 + +/* Interrupt Descriptor Table */ +/* idt_flags contains access flag of a single IDT entry + * | 0 - 4 | 5 - 6 | 7 | + * | res | dpl | p | + * res: always 0x0E + * dpl: ring num (0 - 3) + * p: segment present (bool) +*/ +struct idt_flags { + uint8_t reserved: 5; + uint8_t dpl: 2; + uint8_t p: 1; +}__attribute__((packed)); +typedef struct idt_flags idt_flags_t; + + +/* idt_entry contains the value of an IDT entry + * Each entry is 64 bits(like GDT entry) + * | 0 - 15 | 16 - 31 | 32 - 39 | 40 - 47 | 48 - 63 | + * | b low | seg sel | res | flags | b high | + * b low: Lower 16 bits of the base + * seg sel: Segment selector for code segment + * res: always 0 + * flags: idt_flags struct + * b high: Higher 16 bits of the base +*/ +struct idt_entry { + uint16_t base_low; + uint16_t seg_sel; + uint8_t reserved; + idt_flags_t flags; + uint16_t base_high; +}__attribute__((packed)); +typedef struct idt_entry idt_entry_t; + +/* Also we have to define a pointer to the data structure + * This is needed to locate it later */ +struct idt_ptr { + uint16_t limit; + idt_entry_t *base; +}__attribute__((packed)); +typedef struct idt_ptr idt_ptr_t; + +/* IDT Kernel API */ +void idt_setup(); + +// ISRs method declaration +extern void isr0(); +extern void isr1(); +extern void isr2(); +extern void isr3(); +extern void isr4(); +extern void isr5(); +extern void isr6(); +extern void isr7(); +extern void isr8(); +extern void isr9(); +extern void isr10(); +extern void isr11(); +extern void isr12(); +extern void isr13(); +extern void isr14(); +extern void isr15(); +extern void isr16(); +extern void isr17(); +extern void isr18(); +extern void isr19(); +extern void isr20(); +extern void isr21(); +extern void isr22(); +extern void isr23(); +extern void isr24(); +extern void isr25(); +extern void isr26(); +extern void isr27(); +extern void isr28(); +extern void isr29(); +extern void isr30(); +extern void isr31(); + +extern void irq0(); +extern void irq1(); +extern void irq2(); +extern void irq3(); +extern void irq4(); +extern void irq5(); +extern void irq6(); +extern void irq7(); +extern void irq8(); +extern void irq9(); +extern void irq10(); +extern void irq11(); +extern void irq12(); +extern void irq13(); +extern void irq14(); +extern void irq15(); + +#endif diff --git a/kernel/drivers/initrd.c b/kernel/drivers/initrd.c index c168398..488856c 100644 --- a/kernel/drivers/initrd.c +++ b/kernel/drivers/initrd.c @@ -1,56 +1,56 @@ -#include "initrd.h" - -// Declare various things -initrd_header_t *initrd_header; // Header -initrd_file_header_t *file_header; // List of headers -fs_node_t *initrd_root; // Directory root node -fs_node_t *initrd_dev; // Directory dev node(/dev) -fs_node_t *root_nodes; // List of file nodes -uint32_t nroot_nodes; - -struct dirent dirent; - -fs_node_t *init_ramdisk(uint32_t multiboot_location) { - // Initialize main and file headers - initrd_header = (initrd_header_t*)multiboot_location; - file_header = (initrd_file_header_t*)(multiboot_location+sizeof(initrd_header_t)); - // Initialize root directory - initrd_root = (fs_node_t*) - -} - -static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { - initrd_file_header_t header = file_header[node->inode]; - if(offset > header.length) - return 0; - if(offset+size > header.length) - size = header.length-offset; - memcpy(buffer, (uint8_t*) (header.offset+offset), size); - return size; -} - -static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index) { - if(node == initrd_root && index == 0) { - strcpy(dirent.name, "dev"); - dirent.name[3] = 0; // Add null terminator to the string - dirent.ino = 0; - return &dirent; - } - - if(index-1 >= &root_nodes) - return 0; - strcpy(dirent.name, root_nodes[index-1].name); - dirent.name[strlen(root_nodes[index-1].name)] = 0; // Add null terminator - dirent.ino = root_nodes[index-1].inode; - return &dirent; -} - -static fs_node_t *initrd_finddir(fs_node_t *node, uint8_t *name) { - if(node == initrd_root && !strcmp(name, "dev")) - return initrd_dev; - - for(uint32_t i = 0; i < nroot_nodes; i++) - if(!strcmp(name, root_nodes[i].name)) - return &root_nodes[i]; - return 0; +#include "initrd.h" + +// Declare various things +initrd_header_t *initrd_header; // Header +initrd_file_header_t *file_header; // List of headers +fs_node_t *initrd_root; // Directory root node +fs_node_t *initrd_dev; // Directory dev node(/dev) +fs_node_t *root_nodes; // List of file nodes +uint32_t nroot_nodes; + +struct dirent dirent; + +fs_node_t *init_ramdisk(uint32_t multiboot_location) { + // Initialize main and file headers + initrd_header = (initrd_header_t*)multiboot_location; + file_header = (initrd_file_header_t*)(multiboot_location+sizeof(initrd_header_t)); + // Initialize root directory + initrd_root = (fs_node_t*) + +} + +static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) { + initrd_file_header_t header = file_header[node->inode]; + if(offset > header.length) + return 0; + if(offset+size > header.length) + size = header.length-offset; + memcpy(buffer, (uint8_t*) (header.offset+offset), size); + return size; +} + +static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index) { + if(node == initrd_root && index == 0) { + strcpy(dirent.name, "dev"); + dirent.name[3] = 0; // Add null terminator to the string + dirent.ino = 0; + return &dirent; + } + + if(index-1 >= &root_nodes) + return 0; + strcpy(dirent.name, root_nodes[index-1].name); + dirent.name[strlen(root_nodes[index-1].name)] = 0; // Add null terminator + dirent.ino = root_nodes[index-1].inode; + return &dirent; +} + +static fs_node_t *initrd_finddir(fs_node_t *node, uint8_t *name) { + if(node == initrd_root && !strcmp(name, "dev")) + return initrd_dev; + + for(uint32_t i = 0; i < nroot_nodes; i++) + if(!strcmp(name, root_nodes[i].name)) + return &root_nodes[i]; + return 0; } \ No newline at end of file diff --git a/kernel/drivers/initrd.h b/kernel/drivers/initrd.h index 83fb7a9..80fd6c1 100644 --- a/kernel/drivers/initrd.h +++ b/kernel/drivers/initrd.h @@ -1,36 +1,36 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef INITRD_H -#define INITRD_H -/* Ramdisk is a file system that is loaded along with the kernel - * and it usually contains configuration files or file system drivers. - * It is used BEFORE partitions are being mounted*/ - -#include -#include "../libc/string.h" -#include "fs.h" - -typedef struct { - uint32_t nfiles; // Number of files in the ramdisk -} initrd_header_t; - -typedef struct { - uint8_t magic; // Magic number for error checking - int8_t name[64]; // Filename - uint32_t offset; - uint32_t length; // Length of the file -} initrd_file_header_t; - -// Function to initialize initrd, we'll pass the multiboot -// module as parameter -fs_node_t *init_ramdisk(uint32_t multiboot_location); -static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); -static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index); -static fs_node_t *initrd_finddir(fs_node_t *node, uint8_t *name); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef INITRD_H +#define INITRD_H +/* Ramdisk is a file system that is loaded along with the kernel + * and it usually contains configuration files or file system drivers. + * It is used BEFORE partitions are being mounted*/ + +#include +#include "../libc/string.h" +#include "fs.h" + +typedef struct { + uint32_t nfiles; // Number of files in the ramdisk +} initrd_header_t; + +typedef struct { + uint8_t magic; // Magic number for error checking + int8_t name[64]; // Filename + uint32_t offset; + uint32_t length; // Length of the file +} initrd_file_header_t; + +// Function to initialize initrd, we'll pass the multiboot +// module as parameter +fs_node_t *init_ramdisk(uint32_t multiboot_location); +static uint32_t initrd_read(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer); +static struct dirent *initrd_readdir(fs_node_t *node, uint32_t index); +static fs_node_t *initrd_finddir(fs_node_t *node, uint8_t *name); + +#endif diff --git a/kernel/drivers/isr.c b/kernel/drivers/isr.c index f65e7b6..a8ba5fb 100644 --- a/kernel/drivers/isr.c +++ b/kernel/drivers/isr.c @@ -1,87 +1,87 @@ -#include -#include "isr.h" -#include "tty.h" -#include "../libc/string.h" -#include "ports.h" - -#define PIC1 0x20 // I/O address for master PIC -#define PIC2 0xA0 // I/O address for slave PIC -#define PIC1_COMMAND PIC1 -#define PIC1_DATA (PIC1+1) -#define PIC2_COMMAND PIC2 -#define PIC2_DATA (PIC2+1) -#define PIC_EOI 0x20 // End Of Interrupt command - - -// List of messages for known interrupts -uint8_t *interrupts_messages[] = { - (uint8_t*)"Division by Zero", // 0 - (uint8_t*)"Debug", - (uint8_t*)"Non-maskable interrupt", - (uint8_t*)"Breakpoint", - (uint8_t*)"Detected overflow", - (uint8_t*)"Out-of-bounds", // 5 - (uint8_t*)"Invalid opcode", - (uint8_t*)"No coprocessor", - (uint8_t*)"Double fault", - (uint8_t*)"Coprocessor segment overrun", - (uint8_t*)"Bad TSS", // 10 - (uint8_t*)"Segment not present", - (uint8_t*)"Stack fault", - (uint8_t*)"General protection fault", - (uint8_t*)"Page fault", - (uint8_t*)"Unknown interrupt", // 15 - (uint8_t*)"Coprocessor fault", - (uint8_t*)"Alignment check", - (uint8_t*)"Machine check", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved", - (uint8_t*)"Reserved" -}; - -isr_t interrupt_handler[256]; - -void isr_handler(registers_t regs) { - if(interrupt_handler[regs.int_num] != 0) { - isr_t handler = interrupt_handler[regs.int_num]; - handler(regs); - } else { - uint8_t *buf = (uint8_t*)"\nReceived interrupt: "; - kprint_c((uint8_t*)buf,strlen(buf), LIGHT_BROWN, BLACK); - kprint_c(interrupts_messages[(uint8_t)regs.int_num], - strlen(interrupts_messages[(uint8_t)regs.int_num]), - WHITE, - BLACK - ); - } -} - -void ack_irq(uint32_t int_num) { - // Send and End Of Interrupt(EOF) at the PICs. - if(int_num >= 40) - outb(PIC2_COMMAND, PIC_EOI); // Send reset signal to slave - outb(PIC1_COMMAND, PIC_EOI); // In any case, reset the master -} - -void irq_handler(registers_t regs) { - ack_irq(regs.int_num); - - if(interrupt_handler[regs.int_num] != 0) { - isr_t handler = interrupt_handler[regs.int_num]; - handler(regs); - } -} - -void register_interrupt_handler(uint8_t n, isr_t handler) { - interrupt_handler[n] = handler; +#include +#include "isr.h" +#include "tty.h" +#include "../libc/string.h" +#include "ports.h" + +#define PIC1 0x20 // I/O address for master PIC +#define PIC2 0xA0 // I/O address for slave PIC +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1+1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2+1) +#define PIC_EOI 0x20 // End Of Interrupt command + + +// List of messages for known interrupts +uint8_t *interrupts_messages[] = { + (uint8_t*)"Division by Zero", // 0 + (uint8_t*)"Debug", + (uint8_t*)"Non-maskable interrupt", + (uint8_t*)"Breakpoint", + (uint8_t*)"Detected overflow", + (uint8_t*)"Out-of-bounds", // 5 + (uint8_t*)"Invalid opcode", + (uint8_t*)"No coprocessor", + (uint8_t*)"Double fault", + (uint8_t*)"Coprocessor segment overrun", + (uint8_t*)"Bad TSS", // 10 + (uint8_t*)"Segment not present", + (uint8_t*)"Stack fault", + (uint8_t*)"General protection fault", + (uint8_t*)"Page fault", + (uint8_t*)"Unknown interrupt", // 15 + (uint8_t*)"Coprocessor fault", + (uint8_t*)"Alignment check", + (uint8_t*)"Machine check", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved", + (uint8_t*)"Reserved" +}; + +isr_t interrupt_handler[256]; + +void isr_handler(registers_t regs) { + if(interrupt_handler[regs.int_num] != 0) { + isr_t handler = interrupt_handler[regs.int_num]; + handler(regs); + } else { + uint8_t *buf = (uint8_t*)"\nReceived interrupt: "; + kprint_c((uint8_t*)buf,strlen(buf), LIGHT_BROWN, BLACK); + kprint_c(interrupts_messages[(uint8_t)regs.int_num], + strlen(interrupts_messages[(uint8_t)regs.int_num]), + WHITE, + BLACK + ); + } +} + +void ack_irq(uint32_t int_num) { + // Send and End Of Interrupt(EOF) at the PICs. + if(int_num >= 40) + outb(PIC2_COMMAND, PIC_EOI); // Send reset signal to slave + outb(PIC1_COMMAND, PIC_EOI); // In any case, reset the master +} + +void irq_handler(registers_t regs) { + ack_irq(regs.int_num); + + if(interrupt_handler[regs.int_num] != 0) { + isr_t handler = interrupt_handler[regs.int_num]; + handler(regs); + } +} + +void register_interrupt_handler(uint8_t n, isr_t handler) { + interrupt_handler[n] = handler; } \ No newline at end of file diff --git a/kernel/drivers/isr.h b/kernel/drivers/isr.h index 68c8dc9..b3fb47f 100644 --- a/kernel/drivers/isr.h +++ b/kernel/drivers/isr.h @@ -1,72 +1,72 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _ISR_H_ -#define _ISR_H_ - -#include - -/* - * When we implement ISRs we have to keep in mind that the first 32 interrupts(and so the - * first 32 ISRs) are reserved by the CPU to signal the kernel about critical actions, - * such as divide-by-zero or a stack overflow/buffer overflow. - * - * Below ther's a list of the first, reserved, interrupts...and yeah, we have to implement - * all of them by ourself(btw in Assembly) :D - * - * 0 - Division by zero exception - * 1 - Debug exception - * 2 - Non maskable interrupt - * 3 - Breakpoint exception - * 4 - Into detected overflow - * 5 - Out of bounds exception - * 6 - Invalid opcode exception - * 7 - No coprocessor exception - * 8 - Double fault (pushes an error code) - * 9 - Coprocessor segment overrun - * 10 - Bad TSS (pushes an error code) - * 11 - Segment not present (pushes an error code) - * 12 - Stack fault (pushes an error code) - * 13 - General protection fault (pushes an error code) - * 14 - Page fault (pushes an error code) - * 15 - Unknown interrupt exception - * 16 - Coprocessor fault - * 17 - Alignment check exception - * 18 - Machine check exception - * 19-31 - Reserved */ - -#define IRQ0 32 -#define IRQ1 33 -#define IRQ2 34 -#define IRQ3 35 -#define IRQ4 36 -#define IRQ5 37 -#define IRQ6 38 -#define IRQ7 39 -#define IRQ8 40 -#define IRQ9 41 -#define IRQ10 42 -#define IRQ11 43 -#define IRQ12 44 -#define IRQ13 45 -#define IRQ14 46 -#define IRQ15 47 - -typedef struct registers { - uint32_t ds; // Data segment - uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed with pusha - uint32_t int_num, err_code; // Interrupt number and error code - uint32_t eip, cs, eflags, usereap, ss; // Pushed by CPU -} registers_t; - -typedef void (*isr_t)(registers_t); - -void ack_irq(uint32_t int_num); -void register_interrupt_handler(uint8_t n, isr_t handler); - - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _ISR_H_ +#define _ISR_H_ + +#include + +/* + * When we implement ISRs we have to keep in mind that the first 32 interrupts(and so the + * first 32 ISRs) are reserved by the CPU to signal the kernel about critical actions, + * such as divide-by-zero or a stack overflow/buffer overflow. + * + * Below ther's a list of the first, reserved, interrupts...and yeah, we have to implement + * all of them by ourself(btw in Assembly) :D + * + * 0 - Division by zero exception + * 1 - Debug exception + * 2 - Non maskable interrupt + * 3 - Breakpoint exception + * 4 - Into detected overflow + * 5 - Out of bounds exception + * 6 - Invalid opcode exception + * 7 - No coprocessor exception + * 8 - Double fault (pushes an error code) + * 9 - Coprocessor segment overrun + * 10 - Bad TSS (pushes an error code) + * 11 - Segment not present (pushes an error code) + * 12 - Stack fault (pushes an error code) + * 13 - General protection fault (pushes an error code) + * 14 - Page fault (pushes an error code) + * 15 - Unknown interrupt exception + * 16 - Coprocessor fault + * 17 - Alignment check exception + * 18 - Machine check exception + * 19-31 - Reserved */ + +#define IRQ0 32 +#define IRQ1 33 +#define IRQ2 34 +#define IRQ3 35 +#define IRQ4 36 +#define IRQ5 37 +#define IRQ6 38 +#define IRQ7 39 +#define IRQ8 40 +#define IRQ9 41 +#define IRQ10 42 +#define IRQ11 43 +#define IRQ12 44 +#define IRQ13 45 +#define IRQ14 46 +#define IRQ15 47 + +typedef struct registers { + uint32_t ds; // Data segment + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed with pusha + uint32_t int_num, err_code; // Interrupt number and error code + uint32_t eip, cs, eflags, usereap, ss; // Pushed by CPU +} registers_t; + +typedef void (*isr_t)(registers_t); + +void ack_irq(uint32_t int_num); +void register_interrupt_handler(uint8_t n, isr_t handler); + + +#endif diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c index 8915afe..3f3f0a0 100644 --- a/kernel/drivers/keyboard.c +++ b/kernel/drivers/keyboard.c @@ -1,118 +1,118 @@ -/* The keyboard driver works with a device called PS/2: to talk with this - * controller we can use serial communication(e.g. ports.h). The actual flow of - * data is made with "commands", each command is one byte and the keyboard's - * controller can send two type of response: - * ACK(Acknowledge): to acknowledge the previous command - * Resend: to resend the previous command due to an error. - * We have also to wait between the command, the data and the response of - * the PS/2 controller. - * This device should not exists anymore in any modern computer - * motherboard; however the CPU(or the motherboard?) should be able to - * simulate it even if we're using some USB keyboard. - * Apart of that the keyboard will be listen on IRQ1(33), - * so we have to register an ISR for that. -*/ - -#include "keyboard.h" -#include "isr.h" -#include "ports.h" -#include "tty.h" -#include "../userspace/shell.h" -#include "../libc/stdio.h" - -static void keyboard_callback(); - -/* Keyboard scan codes map , layout is: standard US keyboard */ -uint8_t keyboard_scan_codes[] = { - 0, (uint8_t)27, (uint8_t)'1', (uint8_t)'2', (uint8_t)'3', (uint8_t)'4', (uint8_t)'5', (uint8_t)'6', (uint8_t)'7', (uint8_t)'8', - (uint8_t)'0', (uint8_t)'0', (uint8_t)'-', (uint8_t)'=', (uint8_t)'\b', - (uint8_t)'\t', - (uint8_t)'q', (uint8_t)'w', (uint8_t)'e', (uint8_t)'r', - (uint8_t)'t', (uint8_t)'y', (uint8_t)'u', (uint8_t)'i', (uint8_t)'o', (uint8_t)'p', (uint8_t)'[', (uint8_t)']', (uint8_t)'\n', - 0, - (uint8_t)'a', (uint8_t)'s', (uint8_t)'d', (uint8_t)'f', (uint8_t)'g', (uint8_t)'h', (uint8_t)'j', (uint8_t)'k', (uint8_t)'l', (uint8_t)';', - (uint8_t)'\'', (uint8_t)'`', 0, - (uint8_t)'\\', (uint8_t)'z', (uint8_t)'x', (uint8_t)'c', (uint8_t)'v', (uint8_t)'b', (uint8_t)'n', - (uint8_t)'m', (uint8_t)',', (uint8_t)'.', (uint8_t)'/', 0, - (uint8_t)'*', - - 0, // Alt - (uint8_t)' ', // Spacebar - 0, // Caps lock - 0, // 59 - F1 key - 0, // 59 - F1 key - 0, 0, 0, 0, 0, 0, 0, 0, - 0, // F10 - 0, // 69 - Num lock - 0, // Scroll lock - 0, // Home key - 0, // Up arrow - 0, // Page up - (uint8_t)'-', - 0, // Left arrow - 0, - 0, // Right arrow - (uint8_t)'+', - 0, // 79 End key - 0, // Down arrow - 0, // Page down - 0, // Insert key - 0, // Delete key - 0, 0, 0, - 0, // F11 key - 0, // F12 key - 0 // Others key are undefined -}; - -uint8_t command[512]; // Max length of a single command -uint8_t temp[512]; -uint32_t cmd_index = 0; -uint32_t shiftdown = 0; - -void clear() { - for(uint16_t i = 0; i < 512; i++) - command[i] = 0; -} - -void clear_tmp(void) { - for(uint16_t i = 0; i < 512; i++) - command[i] = 0; -} - -static void keyboard_callback() { - uint8_t scan_code = inb(KB_DATA_PORT); // Read from keyboard - uint8_t keycode = keyboard_scan_codes[scan_code]; // Get ASCII value - - if(scan_code & 0x80) { - if(scan_code == 0xAA || scan_code == 0x86) - shiftdown = 0; - } else { - // Handle backspace - if(keycode == 0x08) { - if(cmd_index <= 0) // If at start of the prompt - return; // Do not delete it. - cmd_index--; // Otherwise go back - - for(uint32_t i = 0; i < cmd_index; ++i) - temp[i] = command[i]; - clear(); - for(uint32_t i = 0; i < cmd_index; ++i) - command[i] = temp[i]; - clear_tmp(); - backspace(); - } else if(keycode == 0x0A) { // Handle Enter - processCommand(command); - cmd_index = 0; - clear(); - init_prompt(); - } else { - printf("%c", keycode); - command[cmd_index] = keycode; - cmd_index++; - } - } -} - -void init_keyboard() { - register_interrupt_handler(IRQ1, &keyboard_callback); -} +/* The keyboard driver works with a device called PS/2: to talk with this + * controller we can use serial communication(e.g. ports.h). The actual flow of + * data is made with "commands", each command is one byte and the keyboard's + * controller can send two type of response: + * ACK(Acknowledge): to acknowledge the previous command + * Resend: to resend the previous command due to an error. + * We have also to wait between the command, the data and the response of + * the PS/2 controller. + * This device should not exists anymore in any modern computer + * motherboard; however the CPU(or the motherboard?) should be able to + * simulate it even if we're using some USB keyboard. + * Apart of that the keyboard will be listen on IRQ1(33), + * so we have to register an ISR for that. +*/ + +#include "keyboard.h" +#include "isr.h" +#include "ports.h" +#include "tty.h" +#include "../userspace/shell.h" +#include "../libc/stdio.h" + +static void keyboard_callback(); + +/* Keyboard scan codes map , layout is: standard US keyboard */ +uint8_t keyboard_scan_codes[] = { + 0, (uint8_t)27, (uint8_t)'1', (uint8_t)'2', (uint8_t)'3', (uint8_t)'4', (uint8_t)'5', (uint8_t)'6', (uint8_t)'7', (uint8_t)'8', + (uint8_t)'0', (uint8_t)'0', (uint8_t)'-', (uint8_t)'=', (uint8_t)'\b', + (uint8_t)'\t', + (uint8_t)'q', (uint8_t)'w', (uint8_t)'e', (uint8_t)'r', + (uint8_t)'t', (uint8_t)'y', (uint8_t)'u', (uint8_t)'i', (uint8_t)'o', (uint8_t)'p', (uint8_t)'[', (uint8_t)']', (uint8_t)'\n', + 0, + (uint8_t)'a', (uint8_t)'s', (uint8_t)'d', (uint8_t)'f', (uint8_t)'g', (uint8_t)'h', (uint8_t)'j', (uint8_t)'k', (uint8_t)'l', (uint8_t)';', + (uint8_t)'\'', (uint8_t)'`', 0, + (uint8_t)'\\', (uint8_t)'z', (uint8_t)'x', (uint8_t)'c', (uint8_t)'v', (uint8_t)'b', (uint8_t)'n', + (uint8_t)'m', (uint8_t)',', (uint8_t)'.', (uint8_t)'/', 0, + (uint8_t)'*', + + 0, // Alt + (uint8_t)' ', // Spacebar + 0, // Caps lock + 0, // 59 - F1 key + 0, // 59 - F1 key + 0, 0, 0, 0, 0, 0, 0, 0, + 0, // F10 + 0, // 69 - Num lock + 0, // Scroll lock + 0, // Home key + 0, // Up arrow + 0, // Page up + (uint8_t)'-', + 0, // Left arrow + 0, + 0, // Right arrow + (uint8_t)'+', + 0, // 79 End key + 0, // Down arrow + 0, // Page down + 0, // Insert key + 0, // Delete key + 0, 0, 0, + 0, // F11 key + 0, // F12 key + 0 // Others key are undefined +}; + +uint8_t command[512]; // Max length of a single command +uint8_t temp[512]; +uint32_t cmd_index = 0; +uint32_t shiftdown = 0; + +void clear() { + for(uint16_t i = 0; i < 512; i++) + command[i] = 0; +} + +void clear_tmp(void) { + for(uint16_t i = 0; i < 512; i++) + command[i] = 0; +} + +static void keyboard_callback() { + uint8_t scan_code = inb(KB_DATA_PORT); // Read from keyboard + uint8_t keycode = keyboard_scan_codes[scan_code]; // Get ASCII value + + if(scan_code & 0x80) { + if(scan_code == 0xAA || scan_code == 0x86) + shiftdown = 0; + } else { + // Handle backspace + if(keycode == 0x08) { + if(cmd_index <= 0) // If at start of the prompt + return; // Do not delete it. + cmd_index--; // Otherwise go back + + for(uint32_t i = 0; i < cmd_index; ++i) + temp[i] = command[i]; + clear(); + for(uint32_t i = 0; i < cmd_index; ++i) + command[i] = temp[i]; + clear_tmp(); + backspace(); + } else if(keycode == 0x0A) { // Handle Enter + processCommand(command); + cmd_index = 0; + clear(); + init_prompt(); + } else { + printf("%c", keycode); + command[cmd_index] = keycode; + cmd_index++; + } + } +} + +void init_keyboard() { + register_interrupt_handler(IRQ1, &keyboard_callback); +} diff --git a/kernel/drivers/keyboard.h b/kernel/drivers/keyboard.h index 63cec50..882e0d8 100644 --- a/kernel/drivers/keyboard.h +++ b/kernel/drivers/keyboard.h @@ -1,17 +1,17 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _KEYBOARD_H_ -#define _KEYBOARD_H_ - -#include - -#define KB_DATA_PORT 0x60 // Keyboard serial port - -void init_keyboard(); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _KEYBOARD_H_ +#define _KEYBOARD_H_ + +#include + +#define KB_DATA_PORT 0x60 // Keyboard serial port + +void init_keyboard(); + +#endif diff --git a/kernel/drivers/ports.h b/kernel/drivers/ports.h index 4b697d8..2dc7f6d 100644 --- a/kernel/drivers/ports.h +++ b/kernel/drivers/ports.h @@ -1,27 +1,27 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _PORTS_H -#define _PORTS_H - -#include - -/* outb: - * Redirect data to port(high level interface for ports.asm) - * @param port: Output port to send data to. - * @param data: The actual data to send to port -*/ -void outb(uint16_t port, uint16_t data); - -/* inb: - * Fetch data from a port, return a char - * @param port: Input port to read data from. -*/ -uint8_t inb(uint16_t port); - - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _PORTS_H +#define _PORTS_H + +#include + +/* outb: + * Redirect data to port(high level interface for ports.asm) + * @param port: Output port to send data to. + * @param data: The actual data to send to port +*/ +void outb(uint16_t port, uint16_t data); + +/* inb: + * Fetch data from a port, return a char + * @param port: Input port to read data from. +*/ +uint8_t inb(uint16_t port); + + +#endif diff --git a/kernel/drivers/timer.c b/kernel/drivers/timer.c index 553e45b..c1d6209 100644 --- a/kernel/drivers/timer.c +++ b/kernel/drivers/timer.c @@ -1,39 +1,39 @@ -#include "timer.h" -#include "isr.h" -#include "tty.h" -#include "../libc/string.h" -#include "ports.h" - -// Start tick at zero -uint32_t tick = 0; -static void timer_callback(registers_t regs) { - tick++; - /* uint8_t buf[8]; - itoa(tick, buf, 10); - kprint((uint8_t*)"Time: "); - uitoa(tick, buf, 10); - kprint((uint8_t*)buf); - kprint((uint8_t*)"\n");*/ - // Cast to void unused parameter - UNUSED_PAR(regs); -} - -void init_timer(uint32_t frequency) { - // Register a new ISR for IRQ0 - register_interrupt_handler(IRQ0, &timer_callback); - - /* As mentioned before, we'll send to PIT a value to divide for - * his system clock(1.1931 MHz). We have to keep in mind that - * this value must fit into a 16 bits variable */ - uint32_t divisor = 1193180 / frequency; - - // Send command to the right port - outb(0x43, 0x36); - // The two divisor has to be sent byte-wise, to do this we split them in two parts - uint8_t low = (uint8_t)(divisor & 0xFF); - uint8_t high = (uint8_t)((divisor >> 8) & 0xFF); - - // Send the frequency divisor - outb(0x40, low); - outb(0x40, high); -} +#include "timer.h" +#include "isr.h" +#include "tty.h" +#include "../libc/string.h" +#include "ports.h" + +// Start tick at zero +uint32_t tick = 0; +static void timer_callback(registers_t regs) { + tick++; + /* uint8_t buf[8]; + itoa(tick, buf, 10); + kprint((uint8_t*)"Time: "); + uitoa(tick, buf, 10); + kprint((uint8_t*)buf); + kprint((uint8_t*)"\n");*/ + // Cast to void unused parameter + UNUSED_PAR(regs); +} + +void init_timer(uint32_t frequency) { + // Register a new ISR for IRQ0 + register_interrupt_handler(IRQ0, &timer_callback); + + /* As mentioned before, we'll send to PIT a value to divide for + * his system clock(1.1931 MHz). We have to keep in mind that + * this value must fit into a 16 bits variable */ + uint32_t divisor = 1193180 / frequency; + + // Send command to the right port + outb(0x43, 0x36); + // The two divisor has to be sent byte-wise, to do this we split them in two parts + uint8_t low = (uint8_t)(divisor & 0xFF); + uint8_t high = (uint8_t)((divisor >> 8) & 0xFF); + + // Send the frequency divisor + outb(0x40, low); + outb(0x40, high); +} diff --git a/kernel/drivers/timer.h b/kernel/drivers/timer.h index ad3e556..0208907 100644 --- a/kernel/drivers/timer.h +++ b/kernel/drivers/timer.h @@ -1,41 +1,41 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _TIMER_H_ -#define _TIMER_H_ - -#include -/* - * The PIT(Programmable Interval Timer) is a chip that consist of an oscillator - * It's connected to IRQ0 and it can be configure at a user-defined rate - * between 10.Hz to 1.1931 MHz. The PIT is the primary method used to implement - * a system clock and for implement multitasking. - * The PIT's internal clock(~1.1931 MHz) is fed through a frequency divider that - * modulate the final signal. This chip has 3 channel, each with his own - * frequency divider: - * Channel 0: The most useful, it's output is connected to IRQ0 - * Channel 1: It were used to control refresh rates on DRAM(RAMs with capacitors) - * Channel 2: Controls the PC speakers. - * - * In our case, we will use only channel 0. - * So we have to set up PIT at a frequency 'f', so it interrupts us at regular - * intervals. We'll set the frequency to 100Hz(once every 10 ms); to do this - * we'll send the PIT a divisor that will be divided for it's input frequency. - * E.g. -> divisor = 1193180 Hz(1.1931MHz) / 100 Hz - * - * Apart of that, the PIT has 4 registers: 0x40-0x42(data ports) and 0x43(command port) - */ - -void init_timer(uint32_t frequency); -extern uint32_t tick; -/* Since regs parameter(from timer_callback) will be unused - * GCC(with -Werror flag) will throw an error, so we can avoid this - * using the following macro - */ -#define UNUSED_PAR(x) (void)(x) - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include +/* + * The PIT(Programmable Interval Timer) is a chip that consist of an oscillator + * It's connected to IRQ0 and it can be configure at a user-defined rate + * between 10.Hz to 1.1931 MHz. The PIT is the primary method used to implement + * a system clock and for implement multitasking. + * The PIT's internal clock(~1.1931 MHz) is fed through a frequency divider that + * modulate the final signal. This chip has 3 channel, each with his own + * frequency divider: + * Channel 0: The most useful, it's output is connected to IRQ0 + * Channel 1: It were used to control refresh rates on DRAM(RAMs with capacitors) + * Channel 2: Controls the PC speakers. + * + * In our case, we will use only channel 0. + * So we have to set up PIT at a frequency 'f', so it interrupts us at regular + * intervals. We'll set the frequency to 100Hz(once every 10 ms); to do this + * we'll send the PIT a divisor that will be divided for it's input frequency. + * E.g. -> divisor = 1193180 Hz(1.1931MHz) / 100 Hz + * + * Apart of that, the PIT has 4 registers: 0x40-0x42(data ports) and 0x43(command port) + */ + +void init_timer(uint32_t frequency); +extern uint32_t tick; +/* Since regs parameter(from timer_callback) will be unused + * GCC(with -Werror flag) will throw an error, so we can avoid this + * using the following macro + */ +#define UNUSED_PAR(x) (void)(x) + +#endif diff --git a/kernel/drivers/tty.c b/kernel/drivers/tty.c index 0257b7b..ec688df 100644 --- a/kernel/drivers/tty.c +++ b/kernel/drivers/tty.c @@ -1,153 +1,153 @@ -#include "tty.h" -#include "../libc/string.h" -#include "ports.h" - -#define VGA_PTR ((uint8_t*) VIDEO_MEM_ADDR) // Pointer to frame buffer -// Also define a 2 byte pointer because cells are 16 bits wide -#define UVGA_PTR ((uint16_t *)VIDEO_MEM_ADDR) -#define STRINGIZE(x) #x -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) - -static uint32_t fb_col = 1; // X -static uint32_t fb_row = 0; // Y - -void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg) { - uint8_t *fb = VGA_PTR; - fb[i*2] = c; - fb[i*2 + 1] = ((bg & 0x0F) << 4) | (fg & 0x0F); -} - -void move_cursor(uint16_t pos) { - outb(VGA_CMD_PORT, VGA_HIGH_BYTE); - outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF)); - outb(VGA_CMD_PORT, VGA_LOW_BYTE); - outb(VGA_DATA_PORT, pos & 0x00FF); -} - -void cursor_adv() { // TODO: specify number of adv. with a parameter - if(fb_col < VGA_WIDTH - 1) - fb_col++; - else - newline(); - - move_cursor(fb_col + (fb_row * VGA_WIDTH)); -} - -void cursor_prev() { - if(fb_col == 0) { - if(fb_row == 0) - return; // If first row do not do anything - fb_col = VGA_WIDTH - 1; - fb_row--; - } else - fb_col--; - move_cursor(fb_col + (fb_row * VGA_WIDTH)); -} - -void backspace() { - uint16_t pos; - uint8_t c = ' '; - - fb_col--; - pos = fb_col + (fb_row * VGA_WIDTH); - write_cell(pos, c, WHITE, BLACK); -} - -void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg) { - uint16_t pos; - for(uint32_t i = 0; i < len; i++) { - uint8_t c = buf[i]; - if(c == '\n' || c == '\r') - newline(); - else if(c == '\t') - tab(); - else { - pos = fb_col + (fb_row * VGA_WIDTH); - write_cell(pos, (uint8_t)c, fg, bg); - cursor_adv(); - } - } -} - -void kprint(uint8_t *buf) { - kprint_c(buf, strlen(buf), WHITE, BLACK); -} - -void kprint_dec(uint32_t num) { - if(num == 0) { - uint8_t *buf = (uint8_t*)'0'; - kprint_c(buf, strlen(buf), WHITE, BLACK);; - return; - } - int32_t acc = num; - uint8_t c[32]; - int32_t i = 0; - while(acc > 0) { - c[i] = '0' + acc%10; - acc /= 10; - i++; - } - c[i] = 0; - uint8_t c2[32]; - c2[i--] = 0; - uint32_t j = 0; - while(i >= 0) - c2[i--] = c[j++]; - kprint(c2); -} - -void init_prompt() { - uint8_t user[64], hostname[64]; -#ifdef DEFAULT_USER - strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER)); -#else - #error "-DDEFAULT_USER flag not set" -#endif - -#ifdef DEFAULT_HOSTNAME - strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME)); -#else - #error "-DDEFAULT_HOSTNAME flag not set" -#endif - - newline(); - kprint_c(user, strlen(user), LIGHT_CYAN, BLACK); - kprint_c((uint8_t*)"@", 1, LIGHT_RED, BLACK); - kprint_c(hostname, strlen(hostname), LIGHT_MAGENTA, BLACK); - kprint_c((uint8_t*)" #> ", 4, LIGHT_BLUE, BLACK); -} - -void clear_prompt() { - fb_col = 1; - fb_row = 0; - - for(uint32_t i = 0; i < (VGA_WIDTH * VGA_HEIGHT); i++) - write_cell(i, ' ', WHITE, BLACK); - move_cursor(0); -} - -void clear_row(uint8_t row) { - for(size_t i = 0; i < VGA_WIDTH; i++) - write_cell((row*VGA_WIDTH)+i, ' ', WHITE, BLACK); -} - -void scroll() { - uint16_t *fb = UVGA_PTR; - memmove(fb, fb+VGA_WIDTH, VGA_WIDTH*2*(VGA_HEIGHT*2-1)); - clear_row(VGA_HEIGHT - 1); -} - -void newline() { - if(fb_row < VGA_HEIGHT - 1) // If there's at least one cell add it - fb_row++; - else // Otherwise scroll framebuffer - scroll(); - - fb_col = 1; - move_cursor(fb_col + (fb_row * VGA_WIDTH)); -} - -void tab() { - for(uint8_t i = 0; i < 4; i++) - cursor_adv(); // Increment cursor 4 times -} +#include "tty.h" +#include "../libc/string.h" +#include "ports.h" + +#define VGA_PTR ((uint8_t*) VIDEO_MEM_ADDR) // Pointer to frame buffer +// Also define a 2 byte pointer because cells are 16 bits wide +#define UVGA_PTR ((uint16_t *)VIDEO_MEM_ADDR) +#define STRINGIZE(x) #x +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) + +static uint32_t fb_col = 1; // X +static uint32_t fb_row = 0; // Y + +void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg) { + uint8_t *fb = VGA_PTR; + fb[i*2] = c; + fb[i*2 + 1] = ((bg & 0x0F) << 4) | (fg & 0x0F); +} + +void move_cursor(uint16_t pos) { + outb(VGA_CMD_PORT, VGA_HIGH_BYTE); + outb(VGA_DATA_PORT, ((pos >> 8) & 0x00FF)); + outb(VGA_CMD_PORT, VGA_LOW_BYTE); + outb(VGA_DATA_PORT, pos & 0x00FF); +} + +void cursor_adv() { // TODO: specify number of adv. with a parameter + if(fb_col < VGA_WIDTH - 1) + fb_col++; + else + newline(); + + move_cursor(fb_col + (fb_row * VGA_WIDTH)); +} + +void cursor_prev() { + if(fb_col == 0) { + if(fb_row == 0) + return; // If first row do not do anything + fb_col = VGA_WIDTH - 1; + fb_row--; + } else + fb_col--; + move_cursor(fb_col + (fb_row * VGA_WIDTH)); +} + +void backspace() { + uint16_t pos; + uint8_t c = ' '; + + fb_col--; + pos = fb_col + (fb_row * VGA_WIDTH); + write_cell(pos, c, WHITE, BLACK); +} + +void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg) { + uint16_t pos; + for(uint32_t i = 0; i < len; i++) { + uint8_t c = buf[i]; + if(c == '\n' || c == '\r') + newline(); + else if(c == '\t') + tab(); + else { + pos = fb_col + (fb_row * VGA_WIDTH); + write_cell(pos, (uint8_t)c, fg, bg); + cursor_adv(); + } + } +} + +void kprint(uint8_t *buf) { + kprint_c(buf, strlen(buf), WHITE, BLACK); +} + +void kprint_dec(uint32_t num) { + if(num == 0) { + uint8_t *buf = (uint8_t*)'0'; + kprint_c(buf, strlen(buf), WHITE, BLACK);; + return; + } + int32_t acc = num; + uint8_t c[32]; + int32_t i = 0; + while(acc > 0) { + c[i] = '0' + acc%10; + acc /= 10; + i++; + } + c[i] = 0; + uint8_t c2[32]; + c2[i--] = 0; + uint32_t j = 0; + while(i >= 0) + c2[i--] = c[j++]; + kprint(c2); +} + +void init_prompt() { + uint8_t user[64], hostname[64]; +#ifdef DEFAULT_USER + strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER)); +#else + #error "-DDEFAULT_USER flag not set" +#endif + +#ifdef DEFAULT_HOSTNAME + strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME)); +#else + #error "-DDEFAULT_HOSTNAME flag not set" +#endif + + newline(); + kprint_c(user, strlen(user), LIGHT_CYAN, BLACK); + kprint_c((uint8_t*)"@", 1, LIGHT_RED, BLACK); + kprint_c(hostname, strlen(hostname), LIGHT_MAGENTA, BLACK); + kprint_c((uint8_t*)" #> ", 4, LIGHT_BLUE, BLACK); +} + +void clear_prompt() { + fb_col = 1; + fb_row = 0; + + for(uint32_t i = 0; i < (VGA_WIDTH * VGA_HEIGHT); i++) + write_cell(i, ' ', WHITE, BLACK); + move_cursor(0); +} + +void clear_row(uint8_t row) { + for(size_t i = 0; i < VGA_WIDTH; i++) + write_cell((row*VGA_WIDTH)+i, ' ', WHITE, BLACK); +} + +void scroll() { + uint16_t *fb = UVGA_PTR; + memmove(fb, fb+VGA_WIDTH, VGA_WIDTH*2*(VGA_HEIGHT*2-1)); + clear_row(VGA_HEIGHT - 1); +} + +void newline() { + if(fb_row < VGA_HEIGHT - 1) // If there's at least one cell add it + fb_row++; + else // Otherwise scroll framebuffer + scroll(); + + fb_col = 1; + move_cursor(fb_col + (fb_row * VGA_WIDTH)); +} + +void tab() { + for(uint8_t i = 0; i < 4; i++) + cursor_adv(); // Increment cursor 4 times +} diff --git a/kernel/drivers/tty.h b/kernel/drivers/tty.h index 9aec33a..1b0f267 100644 --- a/kernel/drivers/tty.h +++ b/kernel/drivers/tty.h @@ -1,63 +1,63 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _TTY_H_ -#define _TTY_H_ - -#include - -// TODO: write something about Frame Buffer - -// VGA colors -enum TTY_COLORS { - BLACK, // 0 - BLUE, - GREEN, - CYAN, - RED, - MAGENTA, - BROWN, - LIGHT_GREY, - DARK_GREY, - LIGHT_BLUE, - LIGHT_GREEN, - LIGHT_CYAN, - LIGHT_RED, - LIGHT_MAGENTA, - LIGHT_BROWN, - WHITE // 15 -}; - -/* Framebuffer properties */ -#define VIDEO_MEM_ADDR 0x000B8000 // frame buffer address -#define VGA_WIDTH 80 -#define VGA_HEIGHT 25 - -/* VGA I/O ports */ -#define VGA_CMD_PORT 0x3D4 -#define VGA_DATA_PORT 0x3D5 - -/* VGA I/O ports commands */ -#define VGA_HIGH_BYTE 14 -#define VGA_LOW_BYTE 15 - -/* Kernel's VGA API */ -void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg); -void move_cursor(uint16_t pos); -void cursor_adv(); -void backspace(); -void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg); -void kprint(uint8_t *buf); -void kprint_dec(uint32_t num); -void init_prompt(); -void clear_prompt(); -void clear_row(uint8_t row); -void scroll(); // Scroll one row -void newline(); -void tab(); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _TTY_H_ +#define _TTY_H_ + +#include + +// TODO: write something about Frame Buffer + +// VGA colors +enum TTY_COLORS { + BLACK, // 0 + BLUE, + GREEN, + CYAN, + RED, + MAGENTA, + BROWN, + LIGHT_GREY, + DARK_GREY, + LIGHT_BLUE, + LIGHT_GREEN, + LIGHT_CYAN, + LIGHT_RED, + LIGHT_MAGENTA, + LIGHT_BROWN, + WHITE // 15 +}; + +/* Framebuffer properties */ +#define VIDEO_MEM_ADDR 0x000B8000 // frame buffer address +#define VGA_WIDTH 80 +#define VGA_HEIGHT 25 + +/* VGA I/O ports */ +#define VGA_CMD_PORT 0x3D4 +#define VGA_DATA_PORT 0x3D5 + +/* VGA I/O ports commands */ +#define VGA_HIGH_BYTE 14 +#define VGA_LOW_BYTE 15 + +/* Kernel's VGA API */ +void write_cell(int16_t i, uint8_t c, uint8_t fg, uint8_t bg); +void move_cursor(uint16_t pos); +void cursor_adv(); +void backspace(); +void kprint_c(uint8_t *buf, uint32_t len, uint8_t fg, uint8_t bg); +void kprint(uint8_t *buf); +void kprint_dec(uint32_t num); +void init_prompt(); +void clear_prompt(); +void clear_row(uint8_t row); +void scroll(); // Scroll one row +void newline(); +void tab(); + +#endif diff --git a/kernel/kernel_main.c b/kernel/kernel_main.c index f927ddd..597a9dd 100644 --- a/kernel/kernel_main.c +++ b/kernel/kernel_main.c @@ -1,79 +1,79 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#include "drivers/tty.h" -#include "drivers/gdt.h" -#include "drivers/idt.h" -#include "drivers/timer.h" -#include "drivers/keyboard.h" -#include "mem/paging.h" -#include "mem/kheap.h" -#include "mem/multiboot.h" -#include "userspace/shell.h" -#include "libc/stdio.h" -#include "libc/panic.h" - -#include - -#define PRTOK printf("\n["); printf_color(" OK ", LIGHT_GREEN, BLACK); printf("]"); // Ugly hack to print "[ OK ]" -#define PRTAT printf("\n["); printf_color(" ** ", LIGHT_BROWN, BLACK); printf("]"); // Ugly hack to print "[ * ]" -#define PRTER printf("\n["); printf_color(" ERR ", LIGHT_RED, BLACK); printf("]"); // Ugly hack to print "[ ER ]" - - -void kernel_main(unsigned long magic, uint32_t addr) { - // First of all, check if we're booted by a Multiboot-compliant boot loader - if(magic != MULTIBOOT2_BOOTLOADER_MAGIC) { - PRTER - printf(" - Invalid magic number: %x\n", (unsigned)magic); - PANIC("Invalid multiboot magic number"); - } - - if(addr & 7) { - PRTER - printf(" - Unaligned mbi: %x\n", addr); - PANIC("Unaligned multiboot MBI"); - } - - - printf("Loading kernel, wait please..."); - - gdt_setup(); // Setup Global Descriptor Table - PRTOK - printf(" - Loaded GDT"); - - idt_setup(); // Setup Interrupt Descriptor Table - PRTOK - printf(" - Loaded IDT"); - - init_timer(1); // Initialize PIT driver - PRTOK - printf(" - Loaded PIT"); - - init_keyboard(); // Initialize keyboard driver - PRTOK - printf(" - Loaded PS/2 driver"); - - init_paging(); // Initialize paging - PRTOK - printf(" - Loaded Paging"); - - PRTAT - printf(" - Testing heap...\t"); - - uint32_t x = kmalloc(32), y = kmalloc(32); - printf("x: %x, y: %x", x, y); - kfree((void*)y); - uint32_t z = kmalloc(8); - printf(", z: %x", z); // If z is equal to y, heap's anti-fragmentation algorithm works - ASSERT(z == y); - kfree((void*)z), kfree((void*)x); - - PRTOK - printf(" - Heap works!"); - - init_prompt(); // Initialize frame buffer -} +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#include "drivers/tty.h" +#include "drivers/gdt.h" +#include "drivers/idt.h" +#include "drivers/timer.h" +#include "drivers/keyboard.h" +#include "mem/paging.h" +#include "mem/kheap.h" +#include "mem/multiboot.h" +#include "userspace/shell.h" +#include "libc/stdio.h" +#include "libc/panic.h" + +#include + +#define PRTOK printf("\n["); printf_color(" OK ", LIGHT_GREEN, BLACK); printf("]"); // Ugly hack to print "[ OK ]" +#define PRTAT printf("\n["); printf_color(" ** ", LIGHT_BROWN, BLACK); printf("]"); // Ugly hack to print "[ * ]" +#define PRTER printf("\n["); printf_color(" ERR ", LIGHT_RED, BLACK); printf("]"); // Ugly hack to print "[ ER ]" + + +void kernel_main(unsigned long magic, uint32_t addr) { + // First of all, check if we're booted by a Multiboot-compliant boot loader + if(magic != MULTIBOOT2_BOOTLOADER_MAGIC) { + PRTER + printf(" - Invalid magic number: %x\n", (unsigned)magic); + PANIC("Invalid multiboot magic number"); + } + + if(addr & 7) { + PRTER + printf(" - Unaligned mbi: %x\n", addr); + PANIC("Unaligned multiboot MBI"); + } + + + printf("Loading kernel, wait please..."); + + gdt_setup(); // Setup Global Descriptor Table + PRTOK + printf(" - Loaded GDT"); + + idt_setup(); // Setup Interrupt Descriptor Table + PRTOK + printf(" - Loaded IDT"); + + init_timer(1); // Initialize PIT driver + PRTOK + printf(" - Loaded PIT"); + + init_keyboard(); // Initialize keyboard driver + PRTOK + printf(" - Loaded PS/2 driver"); + + init_paging(); // Initialize paging + PRTOK + printf(" - Loaded Paging"); + + PRTAT + printf(" - Testing heap...\t"); + + uint32_t x = kmalloc(32), y = kmalloc(32); + printf("x: %x, y: %x", x, y); + kfree((void*)y); + uint32_t z = kmalloc(8); + printf(", z: %x", z); // If z is equal to y, heap's anti-fragmentation algorithm works + ASSERT(z == y); + kfree((void*)z), kfree((void*)x); + + PRTOK + printf(" - Heap works!"); + + init_prompt(); // Initialize frame buffer +} diff --git a/kernel/libc/Makefile b/kernel/libc/Makefile index 31b2a1d..4b5621a 100644 --- a/kernel/libc/Makefile +++ b/kernel/libc/Makefile @@ -1,11 +1,11 @@ -OBJS = stdio.o string.o panic.o time.o -VER := $(shell git rev-parse --short HEAD) - -CC = i686-elf-gcc # cross-compiler -CFLAGS = -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c - - -all:${OBJS} - -%.o: %.c - $(CC) $(CFLAGS) $< -o $@ +OBJS = stdio.o string.o panic.o time.o +VER := $(shell git rev-parse --short HEAD) + +CC = i686-elf-gcc # cross-compiler +CFLAGS = -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c + + +all:${OBJS} + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ diff --git a/kernel/libc/panic.c b/kernel/libc/panic.c index d1153e1..4370e4d 100644 --- a/kernel/libc/panic.c +++ b/kernel/libc/panic.c @@ -1,51 +1,51 @@ -#include "panic.h" -#include "../drivers/cpuid.h" -#include "../libc/stdio.h" -#include "../libc/string.h" - -#define KINFO printf("["); printf_color(" I ", LIGHT_RED, BLACK); printf("]: "); -#define STRINGIZE(x) #x -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) - - -// We panic when we find a critical error, this function is called by assert macro -extern void panic(const char *message, const char *file, uint32_t line) { - uint8_t version[64]; -#ifdef VULCAN_VERSION - strcpy(version, (uint8_t*)STRINGIZE_VALUE_OF(VULCAN_VERSION)); -#else - #error "-DVULCAN_VERSION flag not set" -#endif - printf_color("=============================================\n", LIGHT_MAGENTA, BLACK); - printf_color(" .:: KERNEL PANIC ::. \n", LIGHT_RED, BLACK); - printf_color("Reason: ", LIGHT_BROWN, BLACK); - printf("'%s' at '%s':%d\n", message, file, line); - KINFO - printf_color("Disabling interrupts\n", LIGHT_GREEN, BLACK); - asm volatile("cli"); // Disable interrupts - KINFO - printf_color("Dropping you into an endless loop\n", LIGHT_GREEN, BLACK); - KINFO - printf_color("Your are on your own now...good luck.\n", LIGHT_GREEN, BLACK); - KINFO - printf_color("VulcanOS version: ", LIGHT_GREEN, BLACK); - printf_color((char*)version, LIGHT_CYAN, BLACK); - printf_color("\n\t\t (c) 2019-2021 Marco Cetica", LIGHT_BROWN, BLACK); - printf_color("\n=============================================\n", LIGHT_MAGENTA, BLACK); - for(;;); -} - -// Check for assertion failed, this function is called by assert macro -extern void panic_assert(const char *file, uint32_t line, const char *desc) { - asm volatile("cli"); // Disable interrupts - - kprint((uint8_t*)"ASSERTION-FAILED("); - kprint((uint8_t*)desc); - kprint((uint8_t*)") at "); - kprint((uint8_t*)file); - kprint((uint8_t*)":"); - kprint_dec(line); - kprint((uint8_t*)"\n"); - // Now hang on forever - for(;;); -} +#include "panic.h" +#include "../drivers/cpuid.h" +#include "../libc/stdio.h" +#include "../libc/string.h" + +#define KINFO printf("["); printf_color(" I ", LIGHT_RED, BLACK); printf("]: "); +#define STRINGIZE(x) #x +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) + + +// We panic when we find a critical error, this function is called by assert macro +extern void panic(const char *message, const char *file, uint32_t line) { + uint8_t version[64]; +#ifdef VULCAN_VERSION + strcpy(version, (uint8_t*)STRINGIZE_VALUE_OF(VULCAN_VERSION)); +#else + #error "-DVULCAN_VERSION flag not set" +#endif + printf_color("=============================================\n", LIGHT_MAGENTA, BLACK); + printf_color(" .:: KERNEL PANIC ::. \n", LIGHT_RED, BLACK); + printf_color("Reason: ", LIGHT_BROWN, BLACK); + printf("'%s' at '%s':%d\n", message, file, line); + KINFO + printf_color("Disabling interrupts\n", LIGHT_GREEN, BLACK); + asm volatile("cli"); // Disable interrupts + KINFO + printf_color("Dropping you into an endless loop\n", LIGHT_GREEN, BLACK); + KINFO + printf_color("Your are on your own now...good luck.\n", LIGHT_GREEN, BLACK); + KINFO + printf_color("VulcanOS version: ", LIGHT_GREEN, BLACK); + printf_color((char*)version, LIGHT_CYAN, BLACK); + printf_color("\n\t\t (c) 2019-2021 Marco Cetica", LIGHT_BROWN, BLACK); + printf_color("\n=============================================\n", LIGHT_MAGENTA, BLACK); + for(;;); +} + +// Check for assertion failed, this function is called by assert macro +extern void panic_assert(const char *file, uint32_t line, const char *desc) { + asm volatile("cli"); // Disable interrupts + + kprint((uint8_t*)"ASSERTION-FAILED("); + kprint((uint8_t*)desc); + kprint((uint8_t*)") at "); + kprint((uint8_t*)file); + kprint((uint8_t*)":"); + kprint_dec(line); + kprint((uint8_t*)"\n"); + // Now hang on forever + for(;;); +} diff --git a/kernel/libc/panic.h b/kernel/libc/panic.h index 61a0da9..7123395 100644 --- a/kernel/libc/panic.h +++ b/kernel/libc/panic.h @@ -1,20 +1,20 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef PANIC_H -#define PANIC_H - -#include -#include "../drivers/tty.h" - -#define PANIC(msg) panic(msg, __FILE__, __LINE__); -#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b)) - -extern void panic(const char *message, const char *file, uint32_t line); -extern void panic_assert(const char *file, uint32_t line, const char *desc); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef PANIC_H +#define PANIC_H + +#include +#include "../drivers/tty.h" + +#define PANIC(msg) panic(msg, __FILE__, __LINE__); +#define ASSERT(b) ((b) ? (void)0 : panic_assert(__FILE__, __LINE__, #b)) + +extern void panic(const char *message, const char *file, uint32_t line); +extern void panic_assert(const char *file, uint32_t line, const char *desc); + +#endif diff --git a/kernel/libc/stdio.c b/kernel/libc/stdio.c index e1d9225..2173385 100644 --- a/kernel/libc/stdio.c +++ b/kernel/libc/stdio.c @@ -1,59 +1,59 @@ -#include "stdio.h" -#include "string.h" -#include "../drivers/tty.h" - -int printf(const char *format, ...) { - uint8_t buf[20],c,*s; - int val; - int32_t uval; - va_list ap; - va_start(ap, format); - - for(size_t i = 0; i < strlen((uint8_t*)format); i++) { - if(format[i] == '%') { - i++; - while(format[i] == ' ') - i++; - - switch(format[i]) { - case 'i': - val = va_arg(ap, int); - itoa(val, buf, 10); - kprint(buf); - break; - case 'x': - uval = va_arg(ap, uint32_t); - uitoa(uval, buf, 16); - kprint(buf); - break; - case 'd': - uval = va_arg(ap, uint32_t); - uitoa(uval, buf, 10); - kprint(buf); - break; - case 'c': - c = (uint8_t)va_arg(ap, uint32_t); - kprint_c(&c, 1, WHITE, BLACK); - break; - case 's': - s = va_arg(ap, uint8_t*); - kprint(s); - break; - default: - kprint_c((uint8_t*)format+i, 1, WHITE, BLACK); - } - } else - kprint_c((uint8_t*)format+i, 1, WHITE, BLACK); - } - va_end(ap); - return 0; -} - -int printf_color(const char *format, uint8_t fg, uint8_t bg) { - kprint_c((uint8_t*)format, strlen((uint8_t*)format), fg, bg); - return 0; -} - -void puts(const char *buf) { - printf("%s\n", buf); -} +#include "stdio.h" +#include "string.h" +#include "../drivers/tty.h" + +int printf(const char *format, ...) { + uint8_t buf[20],c,*s; + int val; + int32_t uval; + va_list ap; + va_start(ap, format); + + for(size_t i = 0; i < strlen((uint8_t*)format); i++) { + if(format[i] == '%') { + i++; + while(format[i] == ' ') + i++; + + switch(format[i]) { + case 'i': + val = va_arg(ap, int); + itoa(val, buf, 10); + kprint(buf); + break; + case 'x': + uval = va_arg(ap, uint32_t); + uitoa(uval, buf, 16); + kprint(buf); + break; + case 'd': + uval = va_arg(ap, uint32_t); + uitoa(uval, buf, 10); + kprint(buf); + break; + case 'c': + c = (uint8_t)va_arg(ap, uint32_t); + kprint_c(&c, 1, WHITE, BLACK); + break; + case 's': + s = va_arg(ap, uint8_t*); + kprint(s); + break; + default: + kprint_c((uint8_t*)format+i, 1, WHITE, BLACK); + } + } else + kprint_c((uint8_t*)format+i, 1, WHITE, BLACK); + } + va_end(ap); + return 0; +} + +int printf_color(const char *format, uint8_t fg, uint8_t bg) { + kprint_c((uint8_t*)format, strlen((uint8_t*)format), fg, bg); + return 0; +} + +void puts(const char *buf) { + printf("%s\n", buf); +} diff --git a/kernel/libc/stdio.h b/kernel/libc/stdio.h index ee7f5f2..0533171 100644 --- a/kernel/libc/stdio.h +++ b/kernel/libc/stdio.h @@ -1,19 +1,19 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _STDIO_H_ -#define _STDIO_H_ - -#include -#include -#include - -int printf(const char *format, ...); -int printf_color(const char *format, uint8_t fg, uint8_t bg); // Only for string for now -void puts(const char *buf); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _STDIO_H_ +#define _STDIO_H_ + +#include +#include +#include + +int printf(const char *format, ...); +int printf_color(const char *format, uint8_t fg, uint8_t bg); // Only for string for now +void puts(const char *buf); + +#endif diff --git a/kernel/libc/string.c b/kernel/libc/string.c index 0a30117..c5c506c 100644 --- a/kernel/libc/string.c +++ b/kernel/libc/string.c @@ -1,150 +1,150 @@ -#include "string.h" - -// C library implementation - -int32_t strcmp(const uint8_t *s1, const uint8_t *s2) { - while ((*s1) && (*s1 == *s2)) { - s1++; - s2++; - } - return (*(uint8_t*)s1 - *(uint8_t*)s2); -} -uint8_t *itoa(int32_t val, uint8_t *buf, uint32_t radix) { - uint32_t i = 0; - uint32_t start = i; - - if(val < 0 && radix == 10) { - buf[i++] = '-'; - start = i; - } - - if(radix == 10) { - buf[i++] = '0'; - buf[i++] = 'x'; - start = i; - } - - int x = val; - do { - int a = x % radix; - if(a < 10) - buf[i++] = a + '0'; - else - buf[i++]= a + 'a' - 10; - } while(x /= radix); - - uint8_t *s = buf+start; - uint8_t *e = buf+(i-1); - - while(s < e) { - uint8_t t = *s; - *s = *e; - *e = t; - i++; - e--; - } - buf[i] = 0; - return buf; -} - -uint8_t *uitoa(uint32_t val, uint8_t *buf, uint32_t radix) { - uint32_t i = 0; - uint32_t start = i; - uint32_t x = val; - - if(radix == 16) { - buf[i++] = '0'; - buf[i++] = 'x'; - start = i; - } - - do { - uint32_t a = x % radix; - if(a < 10) - buf[i++] = a + '0'; - else - buf[i++] = a + 'a' - 10; - } while(x /= radix); - - uint8_t *s = buf+start; - uint8_t *e = buf+(i-1); - - while(s < e) { - uint8_t t = *s; - *s = *e; - *e = t; - s++; - e--; - } - - buf[i] = 0; - return buf; -} - -size_t strlen(const uint8_t *buf) { - uint32_t i = 0; - while(buf[i] != 0) - i++; - return i; -} - -uint8_t *strcpy(uint8_t *dst, const uint8_t *src) { - uint8_t *dst_p = dst; - while((*dst++ = *src++)); - - return dst_p; -} - -void strcat(void *dest, const void *src) { - uint8_t *end = (uint8_t*)dest + strlen(dest); - memcpy((uint8_t*)end, (uint8_t*)src, strlen((uint8_t*)src)); - end += strlen((uint8_t*)src); - *end = '\0'; -} - -/* Worst memset implementation - * i could find on the net. - * however it works so... */ -void *memset(void *s, uint32_t c, size_t n) { - char *mem = (char*)s; - - for(size_t i = 0; i < n; i++) - mem[i] = (uint8_t)c; - - return s; -} - -void *memcpy(void *dst, void const *src, uint32_t n) { - uint8_t *ret = dst; - uint8_t *p = dst; - const uint8_t *q = src; - - while(n--) - *p++ = *q++; - - return ret; -} - -void *memmove(void *dst, const void *src, size_t len) { - char *dstmem = (char*)dst; - char *srcmem = (char*)src; - - for(size_t i = 0; i < len; i++) - dstmem[i] = srcmem[i]; - - return dstmem; -} - -void strupper(uint8_t *str) { - for(unsigned int i = 0; i < strlen(str); i++) { - if(str[i] == 'a' && str[i] < 'z') - str[i] &= 0x4F; - } -} - -void strlower(uint8_t *str) { - for(unsigned int i = 0; i < strlen(str); i++) { - if(str[i] == 'A' && str[i] < 'Z') - str[i] |= 0x60; - } -} +#include "string.h" + +// C library implementation + +int32_t strcmp(const uint8_t *s1, const uint8_t *s2) { + while ((*s1) && (*s1 == *s2)) { + s1++; + s2++; + } + return (*(uint8_t*)s1 - *(uint8_t*)s2); +} +uint8_t *itoa(int32_t val, uint8_t *buf, uint32_t radix) { + uint32_t i = 0; + uint32_t start = i; + + if(val < 0 && radix == 10) { + buf[i++] = '-'; + start = i; + } + + if(radix == 10) { + buf[i++] = '0'; + buf[i++] = 'x'; + start = i; + } + + int x = val; + do { + int a = x % radix; + if(a < 10) + buf[i++] = a + '0'; + else + buf[i++]= a + 'a' - 10; + } while(x /= radix); + + uint8_t *s = buf+start; + uint8_t *e = buf+(i-1); + + while(s < e) { + uint8_t t = *s; + *s = *e; + *e = t; + i++; + e--; + } + buf[i] = 0; + return buf; +} + +uint8_t *uitoa(uint32_t val, uint8_t *buf, uint32_t radix) { + uint32_t i = 0; + uint32_t start = i; + uint32_t x = val; + + if(radix == 16) { + buf[i++] = '0'; + buf[i++] = 'x'; + start = i; + } + + do { + uint32_t a = x % radix; + if(a < 10) + buf[i++] = a + '0'; + else + buf[i++] = a + 'a' - 10; + } while(x /= radix); + + uint8_t *s = buf+start; + uint8_t *e = buf+(i-1); + + while(s < e) { + uint8_t t = *s; + *s = *e; + *e = t; + s++; + e--; + } + + buf[i] = 0; + return buf; +} + +size_t strlen(const uint8_t *buf) { + uint32_t i = 0; + while(buf[i] != 0) + i++; + return i; +} + +uint8_t *strcpy(uint8_t *dst, const uint8_t *src) { + uint8_t *dst_p = dst; + while((*dst++ = *src++)); + + return dst_p; +} + +void strcat(void *dest, const void *src) { + uint8_t *end = (uint8_t*)dest + strlen(dest); + memcpy((uint8_t*)end, (uint8_t*)src, strlen((uint8_t*)src)); + end += strlen((uint8_t*)src); + *end = '\0'; +} + +/* Worst memset implementation + * i could find on the net. + * however it works so... */ +void *memset(void *s, uint32_t c, size_t n) { + char *mem = (char*)s; + + for(size_t i = 0; i < n; i++) + mem[i] = (uint8_t)c; + + return s; +} + +void *memcpy(void *dst, void const *src, uint32_t n) { + uint8_t *ret = dst; + uint8_t *p = dst; + const uint8_t *q = src; + + while(n--) + *p++ = *q++; + + return ret; +} + +void *memmove(void *dst, const void *src, size_t len) { + char *dstmem = (char*)dst; + char *srcmem = (char*)src; + + for(size_t i = 0; i < len; i++) + dstmem[i] = srcmem[i]; + + return dstmem; +} + +void strupper(uint8_t *str) { + for(unsigned int i = 0; i < strlen(str); i++) { + if(str[i] == 'a' && str[i] < 'z') + str[i] &= 0x4F; + } +} + +void strlower(uint8_t *str) { + for(unsigned int i = 0; i < strlen(str); i++) { + if(str[i] == 'A' && str[i] < 'Z') + str[i] |= 0x60; + } +} diff --git a/kernel/libc/string.h b/kernel/libc/string.h index fc50891..13d8378 100644 --- a/kernel/libc/string.h +++ b/kernel/libc/string.h @@ -1,26 +1,26 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _STRING_H_ -#define _STRING_H_ - -#include // For uinx_t -#include // For size_t - -int32_t strcmp(const uint8_t *s1, const uint8_t *s2); -uint8_t *itoa(int32_t val, uint8_t *buf, uint32_t radix); -uint8_t *uitoa(uint32_t val, uint8_t *buf, uint32_t radix); -size_t strlen(const uint8_t *buf); -uint8_t *strcpy(uint8_t *dst, const uint8_t *src); -void strcat(void *dest, const void *src); -void *memset(void *s, uint32_t c, size_t n); -void *memmove(void *dst, const void *src, size_t len); -void *memcpy(void *dst, void const *src, uint32_t n); -void strupper(uint8_t *str); -void strlower(uint8_t *str); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef _STRING_H_ +#define _STRING_H_ + +#include // For uinx_t +#include // For size_t + +int32_t strcmp(const uint8_t *s1, const uint8_t *s2); +uint8_t *itoa(int32_t val, uint8_t *buf, uint32_t radix); +uint8_t *uitoa(uint32_t val, uint8_t *buf, uint32_t radix); +size_t strlen(const uint8_t *buf); +uint8_t *strcpy(uint8_t *dst, const uint8_t *src); +void strcat(void *dest, const void *src); +void *memset(void *s, uint32_t c, size_t n); +void *memmove(void *dst, const void *src, size_t len); +void *memcpy(void *dst, void const *src, uint32_t n); +void strupper(uint8_t *str); +void strlower(uint8_t *str); + +#endif diff --git a/kernel/libc/time.c b/kernel/libc/time.c index a92994c..4bf653b 100644 --- a/kernel/libc/time.c +++ b/kernel/libc/time.c @@ -1,38 +1,38 @@ -#include "time.h" -#include "../drivers/ports.h" - -// Check whether CMOS is updated or not -static uint8_t is_cmos_updated() { - outb(CMOS_ADDRESS, 0x0A); - - return (inb(CMOS_DATA) & 0x80); -} - -// Get CMOS register's status -static uint8_t reg_status(int32_t reg) { - outb(CMOS_ADDRESS, reg); - - return inb(CMOS_DATA); -} - - -time_t cmos_reader() { - while(is_cmos_updated()); // Wait until the CMOS is being updated - - time_t tm; - - tm.second = BCD_CONVERTER(reg_status(TIME_R_SECOND)); - tm.minute = BCD_CONVERTER(reg_status(TIME_R_MINUTE)); - tm.hour = BCD_CONVERTER(reg_status(TIME_R_HOUR)); - tm.day = BCD_CONVERTER(reg_status(TIME_R_DAY)); - tm.month = BCD_CONVERTER(reg_status(TIME_R_MONTH)); - tm.year = BCD_CONVERTER(reg_status(TIME_R_YEAR)); - - return tm; -} - -uint32_t get_time(uint32_t field) { - while(is_cmos_updated()); // Wait the CMOS is being updated - - return BCD_CONVERTER(reg_status(field)); -} +#include "time.h" +#include "../drivers/ports.h" + +// Check whether CMOS is updated or not +static uint8_t is_cmos_updated() { + outb(CMOS_ADDRESS, 0x0A); + + return (inb(CMOS_DATA) & 0x80); +} + +// Get CMOS register's status +static uint8_t reg_status(int32_t reg) { + outb(CMOS_ADDRESS, reg); + + return inb(CMOS_DATA); +} + + +time_t cmos_reader() { + while(is_cmos_updated()); // Wait until the CMOS is being updated + + time_t tm; + + tm.second = BCD_CONVERTER(reg_status(TIME_R_SECOND)); + tm.minute = BCD_CONVERTER(reg_status(TIME_R_MINUTE)); + tm.hour = BCD_CONVERTER(reg_status(TIME_R_HOUR)); + tm.day = BCD_CONVERTER(reg_status(TIME_R_DAY)); + tm.month = BCD_CONVERTER(reg_status(TIME_R_MONTH)); + tm.year = BCD_CONVERTER(reg_status(TIME_R_YEAR)); + + return tm; +} + +uint32_t get_time(uint32_t field) { + while(is_cmos_updated()); // Wait the CMOS is being updated + + return BCD_CONVERTER(reg_status(field)); +} diff --git a/kernel/libc/time.h b/kernel/libc/time.h index 2c284a4..ac838bd 100644 --- a/kernel/libc/time.h +++ b/kernel/libc/time.h @@ -1,42 +1,42 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -/* Get time reading the RTC(real time clock) CMOS on the motherboard */ -#ifndef TIME_H -#define TIME_H - -#include - -// Define RTC field registers -#define TIME_R_YEAR 0x09 -#define TIME_R_MONTH 0x08 -#define TIME_R_DAY 0x07 -#define TIME_R_HOUR 0x06 -#define TIME_R_MINUTE 0x05 -#define TIME_R_SECOND 0x04 -//#define TIME_R_CENTURY 0x32 - -// Define RTC address -#define CMOS_ADDRESS 0x70 -#define CMOS_DATA 0x71 - -// Convert BCD encoed values to binary -#define BCD_CONVERTER(n) ((n / 16) * 10 + (n & 0xF)) - -typedef struct { - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t day; - uint8_t month; - uint8_t year; -} time_t; - -time_t cmos_reader(); -uint32_t get_time(uint32_t field); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +/* Get time reading the RTC(real time clock) CMOS on the motherboard */ +#ifndef TIME_H +#define TIME_H + +#include + +// Define RTC field registers +#define TIME_R_YEAR 0x09 +#define TIME_R_MONTH 0x08 +#define TIME_R_DAY 0x07 +#define TIME_R_HOUR 0x06 +#define TIME_R_MINUTE 0x05 +#define TIME_R_SECOND 0x04 +//#define TIME_R_CENTURY 0x32 + +// Define RTC address +#define CMOS_ADDRESS 0x70 +#define CMOS_DATA 0x71 + +// Convert BCD encoed values to binary +#define BCD_CONVERTER(n) ((n / 16) * 10 + (n & 0xF)) + +typedef struct { + uint8_t second; + uint8_t minute; + uint8_t hour; + uint8_t day; + uint8_t month; + uint8_t year; +} time_t; + +time_t cmos_reader(); +uint32_t get_time(uint32_t field); + +#endif diff --git a/kernel/mem/Makefile b/kernel/mem/Makefile index ba06a1c..73b9ae4 100644 --- a/kernel/mem/Makefile +++ b/kernel/mem/Makefile @@ -1,9 +1,9 @@ -OBJS = paging.o kheap.o ordered_array.o - -CC = i686-elf-gcc # cross-compiler -CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c - -all:${OBJS} - -%.o: %.c +OBJS = paging.o kheap.o ordered_array.o + +CC = i686-elf-gcc # cross-compiler +CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c + +all:${OBJS} + +%.o: %.c ${CC} ${CFLAGS} $< -o $@ \ No newline at end of file diff --git a/kernel/mem/kheap.c b/kernel/mem/kheap.c index 122654f..7095d08 100644 --- a/kernel/mem/kheap.c +++ b/kernel/mem/kheap.c @@ -1,329 +1,329 @@ -#include "kheap.h" -#include "paging.h" -#include "../libc/panic.h" - -extern uint32_t end; -uint32_t placement_addr = (uint32_t)&end; -extern page_directory_t *kernel_directory; -heap_t *kheap = 0; - -uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys) { - if(kheap != 0) { - void *addr = alloc(sz, (uint8_t)align, kheap); - if(phys != 0) { - page_t *page = get_page((uint32_t)addr, 0, kernel_directory); - *phys = page->fr*0x1000 + ((uint32_t)addr&0xFFF); - } - return (uint32_t)addr; - } else { - if(align == 1 && (placement_addr & 0xFFFFF000)) { - placement_addr &= 0xFFFFF000; - placement_addr += 0x1000; - } - if(phys) - *phys = placement_addr; - uint32_t tmp = placement_addr; - placement_addr += sz; - return tmp; - } -} - -void kfree(void *p) { - free(p, kheap); -} - -uint32_t kmalloc_a(uint32_t sz) { - return kmalloc_int(sz, 1, 0); -} - -uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) { - return kmalloc_int(sz, 0, phys); -} - -uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys) { - return kmalloc_int(sz, 1, phys); -} - -uint32_t kmalloc(uint32_t sz) { - return kmalloc_int(sz, 0, 0); -} - -static void expand(uint32_t new_size, heap_t *heap) { - // First check if new size is greater than older one - ASSERT(new_size > heap->end_address - heap->start_address); - - // Get nearest page boundary - if((new_size&0xFFFFF000) != 0) { - new_size &= 0xFFFFF000; - new_size += 0x1000; - } - // Check if new size is not greater than maximum size - ASSERT(heap->start_address+new_size <= heap->max_address); - - uint32_t old_size = heap->end_address - heap->start_address; - - uint32_t it = old_size; - while(it < new_size) { - alloc_frame(get_page(heap->start_address+it, 1, kernel_directory), - (heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1); - it += 0x1000; // Page size - } - heap->end_address = heap->start_address+new_size; -} - -static uint32_t contract(uint32_t new_size, heap_t *heap) { - ASSERT(new_size < heap->end_address-heap->start_address); - - if(new_size&0x1000) { - new_size &= 0x1000; - new_size += 0x1000; - } - - if(new_size < HEAP_MIN_SIZE) - new_size = HEAP_MIN_SIZE; - - uint32_t old_size = heap->end_address - heap->start_address; - uint32_t it = old_size - 0x1000; - while(new_size < it) { - free_frame(get_page(heap->start_address+it, 0, kernel_directory)); - it -= 0x1000; - } - - heap->end_address = heap->start_address + new_size; - return new_size; -} - -static uint32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) { - uint32_t it = 0; - - // Find smallest hole that fit our request - while(it < heap->index.size) { - header_t *head = (header_t*)lookup_ordered_array(it, &heap->index); - if(page_align > 0) { - // page must be aligned? - uint32_t location = (uint32_t)head; - uint32_t offset = 0; - if(((location+sizeof(header_t)) & 0xFFFFF000) != 0) - offset = 0x1000 - (location+sizeof(header_t))%0x1000; - uint32_t hole_size = (uint32_t)head->size - offset; - // Check if we can fit this page in that hole - if(hole_size >= (uint32_t)size) - break; - } else if(head->size >= size) - break; - it++; - } - - // If we didn't find anything - if(it == heap->index.size) - return -1; - else - return it; -} - -static uint8_t header_t_less_than(void *a, void *b) { - return (((header_t*)a)->size < ((header_t*)b)->size)?1:0; -} - -heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, uint8_t supervisor, uint8_t readonly) { - heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t)); - - ASSERT(start%0x1000 == 0); - ASSERT(end_addr%0x1000 == 0); - - // Initialize the index - heap->index = place_ordered_array((void*)start, HEAP_INDEX_SIZE, &header_t_less_than); - // Shift start address to the right - start += sizeof(type_t) * HEAP_INDEX_SIZE; - - // Check if start address is page-aligned - if ((start & 0xFFFFF000) != 0) { - start &= 0xFFFFF000; - start += 0x1000; - } - // Store vars into heap - heap->start_address = start; - heap->end_address = end_addr; - heap->max_address = max; - heap->supervisor = supervisor; - heap->readonly = readonly; - - header_t *hole = (header_t*)start; - hole->size = end_addr - start; - hole->magic = HEAP_MAGIC; - hole->is_hole = 1; - insert_ordered_array((void*)hole, &heap->index); - - return heap; -} - -void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) { - uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t); - // Find smallest hole suitable - uint32_t it = find_smallest_hole(new_size, page_align, heap); - - if((int32_t)it == -1) { - uint32_t old_len = heap->end_address - heap->start_address; - uint32_t old_end_addr = heap->end_address; - - // Allocate more space - expand(old_len+new_size, heap); - uint32_t new_len = heap->end_address - heap->start_address; - - it = 0; - uint32_t idx = -1; uint32_t value = 0x0; - while(it < heap->index.size) { - uint32_t tmp = (uint32_t)lookup_ordered_array(it, &heap->index); - if(tmp > value) { - value = tmp; - idx = it; - } - it++; - } - - // If no headers has been found, add a new one - if((int32_t)idx == -1) { - header_t *head = (header_t*)old_end_addr; - head->magic = HEAP_MAGIC; - head->size = new_len - old_len; - head->is_hole = 1; - - footer_t *foot = (footer_t*)(old_end_addr + head->size - sizeof(footer_t)); - foot->magic = HEAP_MAGIC; - foot->header = head; - insert_ordered_array((void*)head, &heap->index); - } else { - header_t *head = lookup_ordered_array(idx, &heap->index); - head->size += new_len - old_len; - // Update the footer - footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t)); - foot->header = head; - foot->magic = HEAP_MAGIC; - } - // Now we have enough space, so recall this function again - return alloc(size, page_align, heap); - } - - header_t *origin_hole_head = (header_t*)lookup_ordered_array(it, &heap->index); - uint32_t origin_hole_p = (uint32_t)origin_hole_head; - uint32_t origin_hole_s = origin_hole_head->size; - // Check if we should split the hole into two parts - if(origin_hole_s-new_size < sizeof(header_t)+sizeof(footer_t)) { - // Increase the requested size to the size of the hole we found - size += origin_hole_s-new_size; - new_size = origin_hole_s; - } - - // Check if we need to page-align data - if(page_align && origin_hole_p&0xFFFFF000) { - uint32_t new_loc = origin_hole_p + 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t); - header_t *hole_header = (header_t*)origin_hole_p; - hole_header->size = 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t); - hole_header->magic = HEAP_MAGIC; - hole_header->is_hole = 1; - footer_t *hole_footer = (footer_t*)((uint32_t)new_loc - sizeof(header_t)); - hole_footer->magic = HEAP_MAGIC; - hole_footer->header = hole_header; - origin_hole_p = new_loc; - origin_hole_s = origin_hole_s - hole_header->size; - } else - remove_ordered_array(it, &heap->index); // Remove hole, since we don't need it anymore - - // Rewrite original header - header_t *block_head = (header_t*)origin_hole_p; - block_head->magic = HEAP_MAGIC; - block_head->is_hole = 0; - block_head->size = new_size; - // and the footer - footer_t *block_foot = (footer_t*)(origin_hole_p + sizeof(header_t) + size); - block_foot->magic = HEAP_MAGIC; - block_foot->header = block_head; - - // Check if we need to write a new hole after the allocated block - if(origin_hole_s - new_size > 0) { - header_t *hole_head = (header_t*)(origin_hole_p + sizeof(header_t) + size + sizeof(footer_t)); - hole_head->magic = HEAP_MAGIC; - hole_head->is_hole = 1; - hole_head->size = origin_hole_s - new_size; - footer_t *hole_foot = (footer_t*)((uint32_t)hole_head + origin_hole_s - new_size - sizeof(footer_t)); - if((uint32_t)hole_foot < heap->end_address) { - hole_foot->magic = HEAP_MAGIC; - hole_foot->header = hole_head; - } - // Add new hole to the data structure - insert_ordered_array((void*)hole_head, &heap->index); - } - - // Return the block header - return (void*)((uint32_t)block_head+sizeof(header_t)); -} - -void free(void *p, heap_t *heap) { - // Check null pointers - if(p == 0) - return; - - // Retrieve data - header_t *head = (header_t*)((uint32_t)p - sizeof(header_t)); - footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t)); - - ASSERT(head->magic == HEAP_MAGIC); - ASSERT(foot->magic == HEAP_MAGIC); - - head->is_hole = 1; // Make this a hole - int8_t add_to_free_hole = 1; // Add this header to free holes - - // Left unify - footer_t *test_foot = (footer_t*)((uint32_t)head - sizeof(footer_t)); - if(test_foot->magic == HEAP_MAGIC && test_foot->header->is_hole == 1 ) { - uint32_t cache_s = head->size; // Store current size - head = test_foot->header; // Rewrite header into new one - foot->header = head; // Point footer to the new header - head->size += cache_s; // Increase size - add_to_free_hole = 0; // Header already in the structure. - } - - // Right unify - header_t *test_head = (header_t*)((uint32_t)foot + sizeof(footer_t)); - if(test_head->magic == HEAP_MAGIC && test_head->is_hole) { - head->size += test_head->size; // Increase size - test_foot = (footer_t*)((uint32_t)test_foot + test_head->size - sizeof(footer_t)); - foot = test_foot; - // Find and remove this header from the structure - uint32_t it = 0; - while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head)) - it++; - - // Check if we actually found something - ASSERT(it < heap->index.size); - - // Remove that item - remove_ordered_array(it, &heap->index); - } - - // If footer is located at the end, we can contract the heap - if((uint32_t)foot+sizeof(footer_t) == heap->end_address) { - uint32_t old_len = heap->end_address-heap->start_address; - uint32_t new_len = contract((uint32_t)head - heap->start_address, heap); - // Check dimensions after resizing - if(head->size - (old_len-new_len) > 0) { - // Dimensions is still a positive value, so we can resize - head->size -= old_len-new_len; - foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t)); - foot->magic = HEAP_MAGIC; - foot->header = head; - } else { - // Remove block from the structure - uint32_t it = 0; - while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head)) - it++; - // If we didn't find that block we haven't nothing to remove - if(it < heap->index.size) - remove_ordered_array(it, &heap->index); - } - } - - // If required by the user, add that block to the structure - if(add_to_free_hole == 1) - insert_ordered_array((void*)head, &heap->index); -} +#include "kheap.h" +#include "paging.h" +#include "../libc/panic.h" + +extern uint32_t end; +uint32_t placement_addr = (uint32_t)&end; +extern page_directory_t *kernel_directory; +heap_t *kheap = 0; + +uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys) { + if(kheap != 0) { + void *addr = alloc(sz, (uint8_t)align, kheap); + if(phys != 0) { + page_t *page = get_page((uint32_t)addr, 0, kernel_directory); + *phys = page->fr*0x1000 + ((uint32_t)addr&0xFFF); + } + return (uint32_t)addr; + } else { + if(align == 1 && (placement_addr & 0xFFFFF000)) { + placement_addr &= 0xFFFFF000; + placement_addr += 0x1000; + } + if(phys) + *phys = placement_addr; + uint32_t tmp = placement_addr; + placement_addr += sz; + return tmp; + } +} + +void kfree(void *p) { + free(p, kheap); +} + +uint32_t kmalloc_a(uint32_t sz) { + return kmalloc_int(sz, 1, 0); +} + +uint32_t kmalloc_p(uint32_t sz, uint32_t *phys) { + return kmalloc_int(sz, 0, phys); +} + +uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys) { + return kmalloc_int(sz, 1, phys); +} + +uint32_t kmalloc(uint32_t sz) { + return kmalloc_int(sz, 0, 0); +} + +static void expand(uint32_t new_size, heap_t *heap) { + // First check if new size is greater than older one + ASSERT(new_size > heap->end_address - heap->start_address); + + // Get nearest page boundary + if((new_size&0xFFFFF000) != 0) { + new_size &= 0xFFFFF000; + new_size += 0x1000; + } + // Check if new size is not greater than maximum size + ASSERT(heap->start_address+new_size <= heap->max_address); + + uint32_t old_size = heap->end_address - heap->start_address; + + uint32_t it = old_size; + while(it < new_size) { + alloc_frame(get_page(heap->start_address+it, 1, kernel_directory), + (heap->supervisor) ? 1 : 0, (heap->readonly) ? 0 : 1); + it += 0x1000; // Page size + } + heap->end_address = heap->start_address+new_size; +} + +static uint32_t contract(uint32_t new_size, heap_t *heap) { + ASSERT(new_size < heap->end_address-heap->start_address); + + if(new_size&0x1000) { + new_size &= 0x1000; + new_size += 0x1000; + } + + if(new_size < HEAP_MIN_SIZE) + new_size = HEAP_MIN_SIZE; + + uint32_t old_size = heap->end_address - heap->start_address; + uint32_t it = old_size - 0x1000; + while(new_size < it) { + free_frame(get_page(heap->start_address+it, 0, kernel_directory)); + it -= 0x1000; + } + + heap->end_address = heap->start_address + new_size; + return new_size; +} + +static uint32_t find_smallest_hole(uint32_t size, uint8_t page_align, heap_t *heap) { + uint32_t it = 0; + + // Find smallest hole that fit our request + while(it < heap->index.size) { + header_t *head = (header_t*)lookup_ordered_array(it, &heap->index); + if(page_align > 0) { + // page must be aligned? + uint32_t location = (uint32_t)head; + uint32_t offset = 0; + if(((location+sizeof(header_t)) & 0xFFFFF000) != 0) + offset = 0x1000 - (location+sizeof(header_t))%0x1000; + uint32_t hole_size = (uint32_t)head->size - offset; + // Check if we can fit this page in that hole + if(hole_size >= (uint32_t)size) + break; + } else if(head->size >= size) + break; + it++; + } + + // If we didn't find anything + if(it == heap->index.size) + return -1; + else + return it; +} + +static uint8_t header_t_less_than(void *a, void *b) { + return (((header_t*)a)->size < ((header_t*)b)->size)?1:0; +} + +heap_t *create_heap(uint32_t start, uint32_t end_addr, uint32_t max, uint8_t supervisor, uint8_t readonly) { + heap_t *heap = (heap_t*)kmalloc(sizeof(heap_t)); + + ASSERT(start%0x1000 == 0); + ASSERT(end_addr%0x1000 == 0); + + // Initialize the index + heap->index = place_ordered_array((void*)start, HEAP_INDEX_SIZE, &header_t_less_than); + // Shift start address to the right + start += sizeof(type_t) * HEAP_INDEX_SIZE; + + // Check if start address is page-aligned + if ((start & 0xFFFFF000) != 0) { + start &= 0xFFFFF000; + start += 0x1000; + } + // Store vars into heap + heap->start_address = start; + heap->end_address = end_addr; + heap->max_address = max; + heap->supervisor = supervisor; + heap->readonly = readonly; + + header_t *hole = (header_t*)start; + hole->size = end_addr - start; + hole->magic = HEAP_MAGIC; + hole->is_hole = 1; + insert_ordered_array((void*)hole, &heap->index); + + return heap; +} + +void *alloc(uint32_t size, uint8_t page_align, heap_t *heap) { + uint32_t new_size = size + sizeof(header_t) + sizeof(footer_t); + // Find smallest hole suitable + uint32_t it = find_smallest_hole(new_size, page_align, heap); + + if((int32_t)it == -1) { + uint32_t old_len = heap->end_address - heap->start_address; + uint32_t old_end_addr = heap->end_address; + + // Allocate more space + expand(old_len+new_size, heap); + uint32_t new_len = heap->end_address - heap->start_address; + + it = 0; + uint32_t idx = -1; uint32_t value = 0x0; + while(it < heap->index.size) { + uint32_t tmp = (uint32_t)lookup_ordered_array(it, &heap->index); + if(tmp > value) { + value = tmp; + idx = it; + } + it++; + } + + // If no headers has been found, add a new one + if((int32_t)idx == -1) { + header_t *head = (header_t*)old_end_addr; + head->magic = HEAP_MAGIC; + head->size = new_len - old_len; + head->is_hole = 1; + + footer_t *foot = (footer_t*)(old_end_addr + head->size - sizeof(footer_t)); + foot->magic = HEAP_MAGIC; + foot->header = head; + insert_ordered_array((void*)head, &heap->index); + } else { + header_t *head = lookup_ordered_array(idx, &heap->index); + head->size += new_len - old_len; + // Update the footer + footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t)); + foot->header = head; + foot->magic = HEAP_MAGIC; + } + // Now we have enough space, so recall this function again + return alloc(size, page_align, heap); + } + + header_t *origin_hole_head = (header_t*)lookup_ordered_array(it, &heap->index); + uint32_t origin_hole_p = (uint32_t)origin_hole_head; + uint32_t origin_hole_s = origin_hole_head->size; + // Check if we should split the hole into two parts + if(origin_hole_s-new_size < sizeof(header_t)+sizeof(footer_t)) { + // Increase the requested size to the size of the hole we found + size += origin_hole_s-new_size; + new_size = origin_hole_s; + } + + // Check if we need to page-align data + if(page_align && origin_hole_p&0xFFFFF000) { + uint32_t new_loc = origin_hole_p + 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t); + header_t *hole_header = (header_t*)origin_hole_p; + hole_header->size = 0x1000 - (origin_hole_p&0xFFF) - sizeof(header_t); + hole_header->magic = HEAP_MAGIC; + hole_header->is_hole = 1; + footer_t *hole_footer = (footer_t*)((uint32_t)new_loc - sizeof(header_t)); + hole_footer->magic = HEAP_MAGIC; + hole_footer->header = hole_header; + origin_hole_p = new_loc; + origin_hole_s = origin_hole_s - hole_header->size; + } else + remove_ordered_array(it, &heap->index); // Remove hole, since we don't need it anymore + + // Rewrite original header + header_t *block_head = (header_t*)origin_hole_p; + block_head->magic = HEAP_MAGIC; + block_head->is_hole = 0; + block_head->size = new_size; + // and the footer + footer_t *block_foot = (footer_t*)(origin_hole_p + sizeof(header_t) + size); + block_foot->magic = HEAP_MAGIC; + block_foot->header = block_head; + + // Check if we need to write a new hole after the allocated block + if(origin_hole_s - new_size > 0) { + header_t *hole_head = (header_t*)(origin_hole_p + sizeof(header_t) + size + sizeof(footer_t)); + hole_head->magic = HEAP_MAGIC; + hole_head->is_hole = 1; + hole_head->size = origin_hole_s - new_size; + footer_t *hole_foot = (footer_t*)((uint32_t)hole_head + origin_hole_s - new_size - sizeof(footer_t)); + if((uint32_t)hole_foot < heap->end_address) { + hole_foot->magic = HEAP_MAGIC; + hole_foot->header = hole_head; + } + // Add new hole to the data structure + insert_ordered_array((void*)hole_head, &heap->index); + } + + // Return the block header + return (void*)((uint32_t)block_head+sizeof(header_t)); +} + +void free(void *p, heap_t *heap) { + // Check null pointers + if(p == 0) + return; + + // Retrieve data + header_t *head = (header_t*)((uint32_t)p - sizeof(header_t)); + footer_t *foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t)); + + ASSERT(head->magic == HEAP_MAGIC); + ASSERT(foot->magic == HEAP_MAGIC); + + head->is_hole = 1; // Make this a hole + int8_t add_to_free_hole = 1; // Add this header to free holes + + // Left unify + footer_t *test_foot = (footer_t*)((uint32_t)head - sizeof(footer_t)); + if(test_foot->magic == HEAP_MAGIC && test_foot->header->is_hole == 1 ) { + uint32_t cache_s = head->size; // Store current size + head = test_foot->header; // Rewrite header into new one + foot->header = head; // Point footer to the new header + head->size += cache_s; // Increase size + add_to_free_hole = 0; // Header already in the structure. + } + + // Right unify + header_t *test_head = (header_t*)((uint32_t)foot + sizeof(footer_t)); + if(test_head->magic == HEAP_MAGIC && test_head->is_hole) { + head->size += test_head->size; // Increase size + test_foot = (footer_t*)((uint32_t)test_foot + test_head->size - sizeof(footer_t)); + foot = test_foot; + // Find and remove this header from the structure + uint32_t it = 0; + while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head)) + it++; + + // Check if we actually found something + ASSERT(it < heap->index.size); + + // Remove that item + remove_ordered_array(it, &heap->index); + } + + // If footer is located at the end, we can contract the heap + if((uint32_t)foot+sizeof(footer_t) == heap->end_address) { + uint32_t old_len = heap->end_address-heap->start_address; + uint32_t new_len = contract((uint32_t)head - heap->start_address, heap); + // Check dimensions after resizing + if(head->size - (old_len-new_len) > 0) { + // Dimensions is still a positive value, so we can resize + head->size -= old_len-new_len; + foot = (footer_t*)((uint32_t)head + head->size - sizeof(footer_t)); + foot->magic = HEAP_MAGIC; + foot->header = head; + } else { + // Remove block from the structure + uint32_t it = 0; + while((it < heap->index.size) && (lookup_ordered_array(it, &heap->index) != (void*)test_head)) + it++; + // If we didn't find that block we haven't nothing to remove + if(it < heap->index.size) + remove_ordered_array(it, &heap->index); + } + } + + // If required by the user, add that block to the structure + if(add_to_free_hole == 1) + insert_ordered_array((void*)head, &heap->index); +} diff --git a/kernel/mem/kheap.h b/kernel/mem/kheap.h index 570d1a0..ed28d8d 100644 --- a/kernel/mem/kheap.h +++ b/kernel/mem/kheap.h @@ -1,70 +1,70 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ - -/*** Heap implementation from James Molloy's tutorial: - http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/ - -/* This heap algorithm uses two different data structures: blocks and holes. - * Blocks: Contiguous areas of memory containing user data - * Holes: Special kind of blocks that are not in use, this is the result - * of free() operation. Those spaces lend to a common problem called "Fragmentation"; - * where malloc() cannot use those spaces anymore because they are too small for any - * kind of program. Any modern OS must have a solution to avoid this problem, but to keep - * things simple as possible i wont implement anything like that. - * Blocks/holes contains informations like the magic number(error checking), the type of - * chunk(hole or block) and the size, while the footer contains only a pointer to the header - * (and obviously an error checking flag). - */ -#ifndef KHEAP_H -#define KHEAP_H - -#define KHEAP_START 0xC0000000 -#define KHEAP_INITIAL_SIZE 0x100000 - -#define HEAP_INDEX_SIZE 0x20000 -#define HEAP_MAGIC 0x123890AB -#define HEAP_MIN_SIZE 0x70000 - -#include -#include "ordered_array.h" - -// Data structure for single hole/block -typedef struct { - uint32_t magic; // Magic number for error checking - uint8_t is_hole; // 1 if it's an hole, 0 for a block - uint32_t size; // Size of block -} header_t; - -typedef struct { - uint32_t magic; // Same as above - header_t *header; // Pointer to the header block -} footer_t; - -typedef struct { - ordered_array_t index; - uint32_t start_address; // Begin of allocated space - uint32_t end_address; // End of allocated space - uint32_t max_address; // Maximum size heap can be expanded to - uint8_t supervisor; - uint8_t readonly; -} heap_t; - -// Create a new heap -heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly); -// Allocates a contigious region of memory in size -void *alloc(uint32_t size, uint8_t page_align, heap_t *heap); -// Free a block allocated with alloc -void free(void *p, heap_t *heap); -uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys); -uint32_t kmalloc_a(uint32_t sz); -uint32_t kmalloc_p(uint32_t sz, uint32_t *phys); -uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys); -uint32_t kmalloc(uint32_t sz); -void kfree(void *p); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ + +/*** Heap implementation from James Molloy's tutorial: + http://www.jamesmolloy.co.uk/tutorial_html/7.-The%20Heap.html ***/ + +/* This heap algorithm uses two different data structures: blocks and holes. + * Blocks: Contiguous areas of memory containing user data + * Holes: Special kind of blocks that are not in use, this is the result + * of free() operation. Those spaces lend to a common problem called "Fragmentation"; + * where malloc() cannot use those spaces anymore because they are too small for any + * kind of program. Any modern OS must have a solution to avoid this problem, but to keep + * things simple as possible i wont implement anything like that. + * Blocks/holes contains informations like the magic number(error checking), the type of + * chunk(hole or block) and the size, while the footer contains only a pointer to the header + * (and obviously an error checking flag). + */ +#ifndef KHEAP_H +#define KHEAP_H + +#define KHEAP_START 0xC0000000 +#define KHEAP_INITIAL_SIZE 0x100000 + +#define HEAP_INDEX_SIZE 0x20000 +#define HEAP_MAGIC 0x123890AB +#define HEAP_MIN_SIZE 0x70000 + +#include +#include "ordered_array.h" + +// Data structure for single hole/block +typedef struct { + uint32_t magic; // Magic number for error checking + uint8_t is_hole; // 1 if it's an hole, 0 for a block + uint32_t size; // Size of block +} header_t; + +typedef struct { + uint32_t magic; // Same as above + header_t *header; // Pointer to the header block +} footer_t; + +typedef struct { + ordered_array_t index; + uint32_t start_address; // Begin of allocated space + uint32_t end_address; // End of allocated space + uint32_t max_address; // Maximum size heap can be expanded to + uint8_t supervisor; + uint8_t readonly; +} heap_t; + +// Create a new heap +heap_t *create_heap(uint32_t start, uint32_t end, uint32_t max, uint8_t supervisor, uint8_t readonly); +// Allocates a contigious region of memory in size +void *alloc(uint32_t size, uint8_t page_align, heap_t *heap); +// Free a block allocated with alloc +void free(void *p, heap_t *heap); +uint32_t kmalloc_int(uint32_t sz, int32_t align, uint32_t *phys); +uint32_t kmalloc_a(uint32_t sz); +uint32_t kmalloc_p(uint32_t sz, uint32_t *phys); +uint32_t kmalloc_ap(uint32_t sz, uint32_t *phys); +uint32_t kmalloc(uint32_t sz); +void kfree(void *p); + +#endif diff --git a/kernel/mem/multiboot.h b/kernel/mem/multiboot.h index 6169c96..5c31e0a 100644 --- a/kernel/mem/multiboot.h +++ b/kernel/mem/multiboot.h @@ -1,518 +1,518 @@ -/* multiboot2.h - Multiboot 2 header file. */ -/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY - * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef MULTIBOOT_HEADER -#define MULTIBOOT_HEADER 1 - -/* How many bytes from the start of the file we search for the header. */ -#define MULTIBOOT_SEARCH 32768 -#define MULTIBOOT_HEADER_ALIGN 8 - -/* The magic field should contain this. */ -#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 - -/* This should be in %eax. */ -#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 - -/* Alignment of multiboot modules. */ -#define MULTIBOOT_MOD_ALIGN 0x00001000 - -/* Alignment of the multiboot info structure. */ -#define MULTIBOOT_INFO_ALIGN 0x00000008 - -/* Flags set in the ’flags’ member of the multiboot header. */ - -#define MULTIBOOT_TAG_ALIGN 8 -#define MULTIBOOT_TAG_TYPE_END 0 -#define MULTIBOOT_TAG_TYPE_CMDLINE 1 -#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 -#define MULTIBOOT_TAG_TYPE_MODULE 3 -#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 -#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 -#define MULTIBOOT_TAG_TYPE_MMAP 6 -#define MULTIBOOT_TAG_TYPE_VBE 7 -#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 -#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 -#define MULTIBOOT_TAG_TYPE_APM 10 -#define MULTIBOOT_TAG_TYPE_EFI32 11 -#define MULTIBOOT_TAG_TYPE_EFI64 12 -#define MULTIBOOT_TAG_TYPE_SMBIOS 13 -#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 -#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 -#define MULTIBOOT_TAG_TYPE_NETWORK 16 -#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 -#define MULTIBOOT_TAG_TYPE_EFI_BS 18 -#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 -#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 -#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 - -#define MULTIBOOT_HEADER_TAG_END 0 -#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 -#define MULTIBOOT_HEADER_TAG_ADDRESS 2 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 -#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 -#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 -#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 -#define MULTIBOOT_HEADER_TAG_EFI_BS 7 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 -#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 -#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10 - -#define MULTIBOOT_ARCHITECTURE_I386 0 -#define MULTIBOOT_ARCHITECTURE_MIPS32 4 -#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 - -#define MULTIBOOT_LOAD_PREFERENCE_NONE 0 -#define MULTIBOOT_LOAD_PREFERENCE_LOW 1 -#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2 - -#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 -#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 - -#ifndef ASM_FILE - -typedef unsigned char multiboot_uint8_t; -typedef unsigned short multiboot_uint16_t; -typedef unsigned int multiboot_uint32_t; -typedef unsigned long long multiboot_uint64_t; - -struct multiboot_header -{ - /* Must be MULTIBOOT_MAGIC - see above. */ - multiboot_uint32_t magic; - - /* ISA */ - multiboot_uint32_t architecture; - - /* Total header length. */ - multiboot_uint32_t header_length; - - /* The above fields plus this one must equal 0 mod 2^32. */ - multiboot_uint32_t checksum; -}; - -struct multiboot_header_tag -{ - multiboot_uint16_t type; - multiboot_uint16_t flags; - multiboot_uint32_t size; -}; - -struct multiboot_header_tag_information_request -{ - multiboot_uint16_t type; - multiboot_uint16_t flags; - multiboot_uint32_t size; - multiboot_uint32_t requests[0]; -}; - -struct multiboot_header_tag_address -{ - multiboot_uint16_t type; - multiboot_uint16_t flags; - multiboot_uint32_t size; - multiboot_uint32_t header_addr; - multiboot_uint32_t load_addr; - multiboot_uint32_t load_end_addr; - multiboot_uint32_t bss_end_addr; -}; - -struct multiboot_header_tag_entry_address -{ - multiboot_uint16_t type; - multiboot_uint16_t flags; - multiboot_uint32_t size; - multiboot_uint32_t entry_addr; -}; - -struct multiboot_header_tag_console_flags -{ - multiboot_uint16_t type; - multiboot_uint16_t flags; - multiboot_uint32_t size; - multiboot_uint32_t console_flags; -}; - -struct multiboot_header_tag_framebuffer -{ - multiboot_uint16_t type; - multiboot_uint16_t flags; - multiboot_uint32_t size; - multiboot_uint32_t width; - multiboot_uint32_t height; - multiboot_uint32_t depth; -}; - -struct multiboot_header_tag_module_align -{ - multiboot_uint16_t type; - multiboot_uint16_t flags; - multiboot_uint32_t size; -}; - -/* The symbol table for a.out. */ -struct multiboot_aout_symbol_table -{ - multiboot_uint32_t tabsize; - multiboot_uint32_t strsize; - multiboot_uint32_t addr; - multiboot_uint32_t reserved; -}; -typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; - -/* The section header table for ELF. */ -struct multiboot_elf_section_header_table -{ - multiboot_uint32_t num; - multiboot_uint32_t size; - multiboot_uint32_t addr; - multiboot_uint32_t shndx; -}; -typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; - -struct multiboot_info -{ - /* Multiboot info version number */ - multiboot_uint32_t flags; - - /* Available memory from BIOS */ - multiboot_uint32_t mem_lower; - multiboot_uint32_t mem_upper; - - /* "root" partition */ - multiboot_uint32_t boot_device; - - /* Kernel command line */ - multiboot_uint32_t cmdline; - - /* Boot-Module list */ - multiboot_uint32_t mods_count; - multiboot_uint32_t mods_addr; - - union - { - multiboot_aout_symbol_table_t aout_sym; - multiboot_elf_section_header_table_t elf_sec; - } u; - - /* Memory Mapping buffer */ - multiboot_uint32_t mmap_length; - multiboot_uint32_t mmap_addr; - - /* Drive Info buffer */ - multiboot_uint32_t drives_length; - multiboot_uint32_t drives_addr; - - /* ROM configuration table */ - multiboot_uint32_t config_table; - - /* Boot Loader Name */ - multiboot_uint32_t boot_loader_name; - - /* APM table */ - multiboot_uint32_t apm_table; - - /* Video */ - multiboot_uint32_t vbe_control_info; - multiboot_uint32_t vbe_mode_info; - multiboot_uint16_t vbe_mode; - multiboot_uint16_t vbe_interface_seg; - multiboot_uint16_t vbe_interface_off; - multiboot_uint16_t vbe_interface_len; - - multiboot_uint64_t framebuffer_addr; - multiboot_uint32_t framebuffer_pitch; - multiboot_uint32_t framebuffer_width; - multiboot_uint32_t framebuffer_height; - multiboot_uint8_t framebuffer_bpp; -#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 -#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 -#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 - multiboot_uint8_t framebuffer_type; - union - { - struct - { - multiboot_uint32_t framebuffer_palette_addr; - multiboot_uint16_t framebuffer_palette_num_colors; - }; - struct - { - multiboot_uint8_t framebuffer_red_field_position; - multiboot_uint8_t framebuffer_red_mask_size; - multiboot_uint8_t framebuffer_green_field_position; - multiboot_uint8_t framebuffer_green_mask_size; - multiboot_uint8_t framebuffer_blue_field_position; - multiboot_uint8_t framebuffer_blue_mask_size; - }; - }; -}; -typedef struct multiboot_info multiboot_info_t; - - -struct multiboot_header_tag_relocatable -{ - multiboot_uint16_t type; - multiboot_uint16_t flags; - multiboot_uint32_t size; - multiboot_uint32_t min_addr; - multiboot_uint32_t max_addr; - multiboot_uint32_t align; - multiboot_uint32_t preference; -}; - -struct multiboot_color -{ - multiboot_uint8_t red; - multiboot_uint8_t green; - multiboot_uint8_t blue; -}; - -struct multiboot_mmap_entry -{ - multiboot_uint32_t size; - multiboot_uint64_t addr; - multiboot_uint64_t len; -#define MULTIBOOT_MEMORY_AVAILABLE 1 -#define MULTIBOOT_MEMORY_RESERVED 2 -#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 -#define MULTIBOOT_MEMORY_NVS 4 -#define MULTIBOOT_MEMORY_BADRAM 5 - multiboot_uint32_t type; - multiboot_uint32_t zero; -}; -typedef struct multiboot_mmap_entry multiboot_memory_map_t; - -struct multiboot_tag -{ - multiboot_uint32_t type; - multiboot_uint32_t size; -}; - -struct multiboot_tag_string -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - char string[0]; -}; - -struct multiboot_tag_module -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t mod_start; - multiboot_uint32_t mod_end; - char cmdline[0]; -}; - -struct multiboot_tag_basic_meminfo -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t mem_lower; - multiboot_uint32_t mem_upper; -}; - -struct multiboot_tag_bootdev -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t biosdev; - multiboot_uint32_t slice; - multiboot_uint32_t part; -}; - -struct multiboot_tag_mmap -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t entry_size; - multiboot_uint32_t entry_version; - struct multiboot_mmap_entry entries[0]; -}; - -struct multiboot_vbe_info_block -{ - multiboot_uint8_t external_specification[512]; -}; - -struct multiboot_vbe_mode_info_block -{ - multiboot_uint8_t external_specification[256]; -}; - -struct multiboot_tag_vbe -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - - multiboot_uint16_t vbe_mode; - multiboot_uint16_t vbe_interface_seg; - multiboot_uint16_t vbe_interface_off; - multiboot_uint16_t vbe_interface_len; - - struct multiboot_vbe_info_block vbe_control_info; - struct multiboot_vbe_mode_info_block vbe_mode_info; -}; - -struct multiboot_tag_framebuffer_common -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - - multiboot_uint64_t framebuffer_addr; - multiboot_uint32_t framebuffer_pitch; - multiboot_uint32_t framebuffer_width; - multiboot_uint32_t framebuffer_height; - multiboot_uint8_t framebuffer_bpp; -#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 -#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 -#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 - multiboot_uint8_t framebuffer_type; - multiboot_uint16_t reserved; -}; - -struct multiboot_tag_framebuffer -{ - struct multiboot_tag_framebuffer_common common; - - union - { - struct - { - multiboot_uint16_t framebuffer_palette_num_colors; - struct multiboot_color framebuffer_palette[0]; - }; - struct - { - multiboot_uint8_t framebuffer_red_field_position; - multiboot_uint8_t framebuffer_red_mask_size; - multiboot_uint8_t framebuffer_green_field_position; - multiboot_uint8_t framebuffer_green_mask_size; - multiboot_uint8_t framebuffer_blue_field_position; - multiboot_uint8_t framebuffer_blue_mask_size; - }; - }; -}; - -struct multiboot_tag_elf_sections -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t num; - multiboot_uint32_t entsize; - multiboot_uint32_t shndx; - char sections[0]; -}; - -struct multiboot_tag_apm -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint16_t version; - multiboot_uint16_t cseg; - multiboot_uint32_t offset; - multiboot_uint16_t cseg_16; - multiboot_uint16_t dseg; - multiboot_uint16_t flags; - multiboot_uint16_t cseg_len; - multiboot_uint16_t cseg_16_len; - multiboot_uint16_t dseg_len; -}; - -struct multiboot_tag_efi32 -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t pointer; -}; - -struct multiboot_tag_efi64 -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint64_t pointer; -}; - -struct multiboot_tag_smbios -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint8_t major; - multiboot_uint8_t minor; - multiboot_uint8_t reserved[6]; - multiboot_uint8_t tables[0]; -}; - -struct multiboot_tag_old_acpi -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint8_t rsdp[0]; -}; - -struct multiboot_tag_new_acpi -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint8_t rsdp[0]; -}; - -struct multiboot_tag_network -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint8_t dhcpack[0]; -}; - -struct multiboot_tag_efi_mmap -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t descr_size; - multiboot_uint32_t descr_vers; - multiboot_uint8_t efi_mmap[0]; -}; - -struct multiboot_tag_efi32_ih -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t pointer; -}; - -struct multiboot_tag_efi64_ih -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint64_t pointer; -}; - -struct multiboot_tag_load_base_addr -{ - multiboot_uint32_t type; - multiboot_uint32_t size; - multiboot_uint32_t load_base_addr; -}; - -#endif /* ! ASM_FILE */ - -#endif /* ! MULTIBOOT_HEADER */ +/* multiboot2.h - Multiboot 2 header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 32768 +#define MULTIBOOT_HEADER_ALIGN 8 + +/* The magic field should contain this. */ +#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6 + +/* This should be in %eax. */ +#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000008 + +/* Flags set in the ’flags’ member of the multiboot header. */ + +#define MULTIBOOT_TAG_ALIGN 8 +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 +#define MULTIBOOT_TAG_TYPE_EFI32 11 +#define MULTIBOOT_TAG_TYPE_EFI64 12 +#define MULTIBOOT_TAG_TYPE_SMBIOS 13 +#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 +#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 +#define MULTIBOOT_TAG_TYPE_NETWORK 16 +#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 +#define MULTIBOOT_TAG_TYPE_EFI_BS 18 +#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 +#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 +#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 + +#define MULTIBOOT_HEADER_TAG_END 0 +#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1 +#define MULTIBOOT_HEADER_TAG_ADDRESS 2 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3 +#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4 +#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5 +#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6 +#define MULTIBOOT_HEADER_TAG_EFI_BS 7 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8 +#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9 +#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10 + +#define MULTIBOOT_ARCHITECTURE_I386 0 +#define MULTIBOOT_ARCHITECTURE_MIPS32 4 +#define MULTIBOOT_HEADER_TAG_OPTIONAL 1 + +#define MULTIBOOT_LOAD_PREFERENCE_NONE 0 +#define MULTIBOOT_LOAD_PREFERENCE_LOW 1 +#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2 + +#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1 +#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* ISA */ + multiboot_uint32_t architecture; + + /* Total header length. */ + multiboot_uint32_t header_length; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; +}; + +struct multiboot_header_tag +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; +}; + +struct multiboot_header_tag_information_request +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t requests[0]; +}; + +struct multiboot_header_tag_address +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; +}; + +struct multiboot_header_tag_entry_address +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t entry_addr; +}; + +struct multiboot_header_tag_console_flags +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t console_flags; +}; + +struct multiboot_header_tag_framebuffer +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +struct multiboot_header_tag_module_align +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; +}; + +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table +{ + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table +{ + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +struct multiboot_info +{ + /* Multiboot info version number */ + multiboot_uint32_t flags; + + /* Available memory from BIOS */ + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; + + /* "root" partition */ + multiboot_uint32_t boot_device; + + /* Kernel command line */ + multiboot_uint32_t cmdline; + + /* Boot-Module list */ + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; + + union + { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; + + /* Drive Info buffer */ + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; + + /* ROM configuration table */ + multiboot_uint32_t config_table; + + /* Boot Loader Name */ + multiboot_uint32_t boot_loader_name; + + /* APM table */ + multiboot_uint32_t apm_table; + + /* Video */ + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + + +struct multiboot_header_tag_relocatable +{ + multiboot_uint16_t type; + multiboot_uint16_t flags; + multiboot_uint32_t size; + multiboot_uint32_t min_addr; + multiboot_uint32_t max_addr; + multiboot_uint32_t align; + multiboot_uint32_t preference; +}; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; + multiboot_uint32_t zero; +}; +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_tag +{ + multiboot_uint32_t type; + multiboot_uint32_t size; +}; + +struct multiboot_tag_string +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + char string[0]; +}; + +struct multiboot_tag_module +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + char cmdline[0]; +}; + +struct multiboot_tag_basic_meminfo +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; +}; + +struct multiboot_tag_bootdev +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t biosdev; + multiboot_uint32_t slice; + multiboot_uint32_t part; +}; + +struct multiboot_tag_mmap +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t entry_size; + multiboot_uint32_t entry_version; + struct multiboot_mmap_entry entries[0]; +}; + +struct multiboot_vbe_info_block +{ + multiboot_uint8_t external_specification[512]; +}; + +struct multiboot_vbe_mode_info_block +{ + multiboot_uint8_t external_specification[256]; +}; + +struct multiboot_tag_vbe +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + struct multiboot_vbe_info_block vbe_control_info; + struct multiboot_vbe_mode_info_block vbe_mode_info; +}; + +struct multiboot_tag_framebuffer_common +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + multiboot_uint16_t reserved; +}; + +struct multiboot_tag_framebuffer +{ + struct multiboot_tag_framebuffer_common common; + + union + { + struct + { + multiboot_uint16_t framebuffer_palette_num_colors; + struct multiboot_color framebuffer_palette[0]; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; + +struct multiboot_tag_elf_sections +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t num; + multiboot_uint32_t entsize; + multiboot_uint32_t shndx; + char sections[0]; +}; + +struct multiboot_tag_apm +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + +struct multiboot_tag_efi32 +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t pointer; +}; + +struct multiboot_tag_efi64 +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint64_t pointer; +}; + +struct multiboot_tag_smbios +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint8_t major; + multiboot_uint8_t minor; + multiboot_uint8_t reserved[6]; + multiboot_uint8_t tables[0]; +}; + +struct multiboot_tag_old_acpi +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint8_t rsdp[0]; +}; + +struct multiboot_tag_new_acpi +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint8_t rsdp[0]; +}; + +struct multiboot_tag_network +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint8_t dhcpack[0]; +}; + +struct multiboot_tag_efi_mmap +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t descr_size; + multiboot_uint32_t descr_vers; + multiboot_uint8_t efi_mmap[0]; +}; + +struct multiboot_tag_efi32_ih +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t pointer; +}; + +struct multiboot_tag_efi64_ih +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint64_t pointer; +}; + +struct multiboot_tag_load_base_addr +{ + multiboot_uint32_t type; + multiboot_uint32_t size; + multiboot_uint32_t load_base_addr; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ diff --git a/kernel/mem/ordered_array.c b/kernel/mem/ordered_array.c index 521e4d1..c576f92 100644 --- a/kernel/mem/ordered_array.c +++ b/kernel/mem/ordered_array.c @@ -1,66 +1,66 @@ -#include "ordered_array.h" -#include "kheap.h" -#include "../libc/panic.h" -#include "../libc/string.h" - -uint8_t standard_lessthan_predicate(type_t a, type_t b) { - if (a < b) - return 1; - else - return 0; -} - -ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than) { - ordered_array_t to_ret; - to_ret.array = (void*)kmalloc(max_size*sizeof(type_t)); - memset(to_ret.array, 0, max_size*sizeof(type_t)); - to_ret.size = 0; - to_ret.max_size = max_size; - to_ret.less_than = less_than; - return to_ret; -} - -ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than) { - ordered_array_t to_ret; - to_ret.array = (type_t*)addr; - memset(to_ret.array, 0, max_size*sizeof(type_t)); - to_ret.size = 0; - to_ret.max_size = max_size; - to_ret.less_than = less_than; - return to_ret; -} - -void destroy_ordered_array(ordered_array_t *array) { - kfree(array->array); -} - -void insert_ordered_array(type_t item, ordered_array_t *array) { - uint32_t it = 0; - while(it < array->size && array->less_than(array->array[it], item)) - it++; - if(it == array->size) - array->array[array->size++] = item; - else { - type_t tmp = array->array[it]; - array->array[it] = item; - while(it < array->size) { - it++; - type_t tmp2 = array->array[it]; - array->array[it] = tmp; - tmp = tmp2; - } - array->size++; - } -} - -type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) { - return array->array[i]; -} - -void remove_ordered_array(uint32_t i, ordered_array_t *array) { - while(i < array->size) { - array->array[i] = array->array[i+1]; - i++; - } - array->size--; -} +#include "ordered_array.h" +#include "kheap.h" +#include "../libc/panic.h" +#include "../libc/string.h" + +uint8_t standard_lessthan_predicate(type_t a, type_t b) { + if (a < b) + return 1; + else + return 0; +} + +ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than) { + ordered_array_t to_ret; + to_ret.array = (void*)kmalloc(max_size*sizeof(type_t)); + memset(to_ret.array, 0, max_size*sizeof(type_t)); + to_ret.size = 0; + to_ret.max_size = max_size; + to_ret.less_than = less_than; + return to_ret; +} + +ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than) { + ordered_array_t to_ret; + to_ret.array = (type_t*)addr; + memset(to_ret.array, 0, max_size*sizeof(type_t)); + to_ret.size = 0; + to_ret.max_size = max_size; + to_ret.less_than = less_than; + return to_ret; +} + +void destroy_ordered_array(ordered_array_t *array) { + kfree(array->array); +} + +void insert_ordered_array(type_t item, ordered_array_t *array) { + uint32_t it = 0; + while(it < array->size && array->less_than(array->array[it], item)) + it++; + if(it == array->size) + array->array[array->size++] = item; + else { + type_t tmp = array->array[it]; + array->array[it] = item; + while(it < array->size) { + it++; + type_t tmp2 = array->array[it]; + array->array[it] = tmp; + tmp = tmp2; + } + array->size++; + } +} + +type_t lookup_ordered_array(uint32_t i, ordered_array_t *array) { + return array->array[i]; +} + +void remove_ordered_array(uint32_t i, ordered_array_t *array) { + while(i < array->size) { + array->array[i] = array->array[i+1]; + i++; + } + array->size--; +} diff --git a/kernel/mem/ordered_array.h b/kernel/mem/ordered_array.h index ca5ba88..5b39f6e 100644 --- a/kernel/mem/ordered_array.h +++ b/kernel/mem/ordered_array.h @@ -1,39 +1,39 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef ORDERED_ARRAY_H -#define ORDERED_ARRAY_H - -#include - -/* Our list is always in a 'sorted state', - * it can store anything that can be casted - * to void* */ -typedef void* type_t; -/* The following predicate should return non-zero - * if the first argument is less than the second */ -typedef uint8_t (*lessthan_predicate_t)(type_t,type_t); -typedef struct { - type_t *array; - uint32_t size; - uint32_t max_size; - lessthan_predicate_t less_than; -} ordered_array_t; - -uint8_t standard_lessthan_predicate(type_t a, type_t b); - -// Create a new ordered array -ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than); -ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than); -// Destroy an ordered array -void destroy_ordered_array(ordered_array_t *array); -// Add an item into the array -void insert_ordered_array(type_t item, ordered_array_t *array); -type_t lookup_ordered_array(uint32_t i, ordered_array_t *array); -void remove_ordered_array(uint32_t i, ordered_array_t *array); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef ORDERED_ARRAY_H +#define ORDERED_ARRAY_H + +#include + +/* Our list is always in a 'sorted state', + * it can store anything that can be casted + * to void* */ +typedef void* type_t; +/* The following predicate should return non-zero + * if the first argument is less than the second */ +typedef uint8_t (*lessthan_predicate_t)(type_t,type_t); +typedef struct { + type_t *array; + uint32_t size; + uint32_t max_size; + lessthan_predicate_t less_than; +} ordered_array_t; + +uint8_t standard_lessthan_predicate(type_t a, type_t b); + +// Create a new ordered array +ordered_array_t create_ordered_array(uint32_t max_size, lessthan_predicate_t less_than); +ordered_array_t place_ordered_array(void *addr, uint32_t max_size, lessthan_predicate_t less_than); +// Destroy an ordered array +void destroy_ordered_array(ordered_array_t *array); +// Add an item into the array +void insert_ordered_array(type_t item, ordered_array_t *array); +type_t lookup_ordered_array(uint32_t i, ordered_array_t *array); +void remove_ordered_array(uint32_t i, ordered_array_t *array); + +#endif diff --git a/kernel/mem/paging.c b/kernel/mem/paging.c index 7225b9c..97cc0eb 100644 --- a/kernel/mem/paging.c +++ b/kernel/mem/paging.c @@ -1,141 +1,141 @@ -#include "paging.h" -#include "../libc/string.h" -#include "../libc/panic.h" -#include "../libc/stdio.h" -#include "../drivers/tty.h" - -// External definitions from kheap.c -extern uint32_t placement_addr; -extern heap_t *kheap; - -// Bitset of frames, used or free -uint32_t *frame_allocations; -uint32_t nframes; // Number of physical frames -page_directory_t *kernel_directory = 0; -page_directory_t *current_directory = 0; - -static void set_frame(uint32_t addr) { - uint32_t frame = FRAME(addr); - uint32_t frame_alloc_s = FRAME_SECTION(frame); - uint32_t frame_alloc_o = FRAME_OFFSET(frame); - frame_allocations[frame_alloc_s] |= (1 << frame_alloc_o); -} - -static void clear_frame(uint32_t addr) { - uint32_t frame = FRAME(addr); - uint32_t frame_alloc_s = FRAME_SECTION(frame); - uint32_t frame_alloc_o = FRAME_OFFSET(frame); - frame_allocations[frame_alloc_s] &= ~(1 << frame_alloc_o); -} - -static uint32_t first_frame() { - uint32_t nsections = nframes / FRAME_ALLOCATIONS_SECTION_SIZE; - for(uint32_t sec = 0; sec < nsections; sec++) - if(frame_allocations[sec] != USED_FRAME_SECTION) - for(uint32_t idx = 0; idx < FRAME_ALLOCATIONS_SECTION_SIZE; idx++) - if(!(frame_allocations[sec] & (0x1 << idx))) - return (sec*FRAME_ALLOCATIONS_SECTION_SIZE) + idx; - return nsections * FRAME_ALLOCATIONS_SECTION_SIZE; -} - -void alloc_frame(page_t *page, int32_t is_super, int32_t is_write) { - if(page->fr != 0) - return; - else { - uint32_t fframe = first_frame(); - if(fframe == (uint32_t)-1) { - PANIC("No free frames availables!"); - } else { - // Set free frames to the page - page->pr = PAGE_PRESENT; - page->rw = (is_write) ? PAGE_READ_WRITE : PAGE_READ_ONLY; - page->us = (is_super) ? PAGE_SUPERVISOR : PAGE_USER; - page->fr = fframe; - // Set new frames as used - uint32_t physical_addr = fframe * FRAME_SIZE; - set_frame(physical_addr); - } - } -} - -void free_frame(page_t *page) { - uint32_t frame; - if(!(frame=page->fr)) - return; // page doesn't have a frame in first place - else { - clear_frame(frame); - page->fr = 0x0; - } -} - -void init_paging() { - // Setup frame allocation - nframes = PHYSICAL_MEM_SIZE / FRAME_SIZE; - frame_allocations = (uint32_t*)kmalloc(nframes/FRAME_ALLOCATIONS_SECTION_SIZE); - memset(frame_allocations, 0, nframes/FRAME_ALLOCATIONS_SECTION_SIZE); - - // Setup page directory - kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); - memset(kernel_directory, 0, sizeof(page_directory_t)); - current_directory = kernel_directory; - - // Map heap pages - for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += FRAME_SIZE) - get_page(i, 1, kernel_directory); - - // Setup identity map - for(uint32_t i = 0; i < placement_addr + FRAME_SIZE; i += FRAME_SIZE) - alloc_frame(get_page(i, 1, kernel_directory), 0, 0); - - // Allocate heap pages - for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE) - alloc_frame(get_page(i, 1, kernel_directory), 0, 0); - - // Register a new ISR to listen to IRQ 14 - register_interrupt_handler(14, page_fault); - enable_paging(kernel_directory); - kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0); -} - -void enable_paging(page_directory_t *dir) { - current_directory = dir; - asm volatile("mov %0, %%cr3" :: "r"(&dir->page_tables_physical)); - uint32_t cr0; - asm volatile("mov %%cr0, %0" : "=r"(cr0)); - cr0 |= 0x80000000; // Correct code to enable paging - asm volatile("mov %0, %%cr0" :: "r"(cr0)); -} - -page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) { - address /= 0x1000; // turn address into an index - uint32_t table_idx = address / 1024; // Find page that contains the address - if(dir->page_tables_virtual[table_idx]) - return &dir->page_tables_virtual[table_idx]->pages[address%1024]; - else if(make) { - uint32_t tmp; - dir->page_tables_virtual[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp); - memset(dir->page_tables_virtual[table_idx], 0, 0x1000); - dir->page_tables_physical[table_idx] = tmp | 0x7; - return &dir->page_tables_virtual[table_idx]->pages[address%1024]; - } else - return 0; -} - -void page_fault(registers_t regs) { - // Handle a page fault - uint32_t faulting_addr; - asm volatile("mov %%cr2, %0" : "=r" (faulting_addr)); - - // Gracefully print the error - kprint((uint8_t*)"\nPage fault! ( "); - if(!(regs.err_code & 0x1)) - kprint((uint8_t*)"Present "); - if(regs.err_code & 0x2) - kprint((uint8_t*)"Read-Only "); - if(regs.err_code & 0x4) - kprint((uint8_t*)"User-Mode "); - if(regs.err_code & 0x8) - kprint((uint8_t*)"Reserved"); - printf(") at %x\n", faulting_addr); - PANIC("Page fault"); -} +#include "paging.h" +#include "../libc/string.h" +#include "../libc/panic.h" +#include "../libc/stdio.h" +#include "../drivers/tty.h" + +// External definitions from kheap.c +extern uint32_t placement_addr; +extern heap_t *kheap; + +// Bitset of frames, used or free +uint32_t *frame_allocations; +uint32_t nframes; // Number of physical frames +page_directory_t *kernel_directory = 0; +page_directory_t *current_directory = 0; + +static void set_frame(uint32_t addr) { + uint32_t frame = FRAME(addr); + uint32_t frame_alloc_s = FRAME_SECTION(frame); + uint32_t frame_alloc_o = FRAME_OFFSET(frame); + frame_allocations[frame_alloc_s] |= (1 << frame_alloc_o); +} + +static void clear_frame(uint32_t addr) { + uint32_t frame = FRAME(addr); + uint32_t frame_alloc_s = FRAME_SECTION(frame); + uint32_t frame_alloc_o = FRAME_OFFSET(frame); + frame_allocations[frame_alloc_s] &= ~(1 << frame_alloc_o); +} + +static uint32_t first_frame() { + uint32_t nsections = nframes / FRAME_ALLOCATIONS_SECTION_SIZE; + for(uint32_t sec = 0; sec < nsections; sec++) + if(frame_allocations[sec] != USED_FRAME_SECTION) + for(uint32_t idx = 0; idx < FRAME_ALLOCATIONS_SECTION_SIZE; idx++) + if(!(frame_allocations[sec] & (0x1 << idx))) + return (sec*FRAME_ALLOCATIONS_SECTION_SIZE) + idx; + return nsections * FRAME_ALLOCATIONS_SECTION_SIZE; +} + +void alloc_frame(page_t *page, int32_t is_super, int32_t is_write) { + if(page->fr != 0) + return; + else { + uint32_t fframe = first_frame(); + if(fframe == (uint32_t)-1) { + PANIC("No free frames availables!"); + } else { + // Set free frames to the page + page->pr = PAGE_PRESENT; + page->rw = (is_write) ? PAGE_READ_WRITE : PAGE_READ_ONLY; + page->us = (is_super) ? PAGE_SUPERVISOR : PAGE_USER; + page->fr = fframe; + // Set new frames as used + uint32_t physical_addr = fframe * FRAME_SIZE; + set_frame(physical_addr); + } + } +} + +void free_frame(page_t *page) { + uint32_t frame; + if(!(frame=page->fr)) + return; // page doesn't have a frame in first place + else { + clear_frame(frame); + page->fr = 0x0; + } +} + +void init_paging() { + // Setup frame allocation + nframes = PHYSICAL_MEM_SIZE / FRAME_SIZE; + frame_allocations = (uint32_t*)kmalloc(nframes/FRAME_ALLOCATIONS_SECTION_SIZE); + memset(frame_allocations, 0, nframes/FRAME_ALLOCATIONS_SECTION_SIZE); + + // Setup page directory + kernel_directory = (page_directory_t*)kmalloc_a(sizeof(page_directory_t)); + memset(kernel_directory, 0, sizeof(page_directory_t)); + current_directory = kernel_directory; + + // Map heap pages + for(uint32_t i = KHEAP_START; i < KHEAP_START + KHEAP_INITIAL_SIZE; i += FRAME_SIZE) + get_page(i, 1, kernel_directory); + + // Setup identity map + for(uint32_t i = 0; i < placement_addr + FRAME_SIZE; i += FRAME_SIZE) + alloc_frame(get_page(i, 1, kernel_directory), 0, 0); + + // Allocate heap pages + for(uint32_t i = KHEAP_START; i < KHEAP_START+KHEAP_INITIAL_SIZE; i += FRAME_SIZE) + alloc_frame(get_page(i, 1, kernel_directory), 0, 0); + + // Register a new ISR to listen to IRQ 14 + register_interrupt_handler(14, page_fault); + enable_paging(kernel_directory); + kheap = create_heap(KHEAP_START, KHEAP_START+KHEAP_INITIAL_SIZE, 0xCFFFF000, 0, 0); +} + +void enable_paging(page_directory_t *dir) { + current_directory = dir; + asm volatile("mov %0, %%cr3" :: "r"(&dir->page_tables_physical)); + uint32_t cr0; + asm volatile("mov %%cr0, %0" : "=r"(cr0)); + cr0 |= 0x80000000; // Correct code to enable paging + asm volatile("mov %0, %%cr0" :: "r"(cr0)); +} + +page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir) { + address /= 0x1000; // turn address into an index + uint32_t table_idx = address / 1024; // Find page that contains the address + if(dir->page_tables_virtual[table_idx]) + return &dir->page_tables_virtual[table_idx]->pages[address%1024]; + else if(make) { + uint32_t tmp; + dir->page_tables_virtual[table_idx] = (page_table_t*)kmalloc_ap(sizeof(page_table_t), &tmp); + memset(dir->page_tables_virtual[table_idx], 0, 0x1000); + dir->page_tables_physical[table_idx] = tmp | 0x7; + return &dir->page_tables_virtual[table_idx]->pages[address%1024]; + } else + return 0; +} + +void page_fault(registers_t regs) { + // Handle a page fault + uint32_t faulting_addr; + asm volatile("mov %%cr2, %0" : "=r" (faulting_addr)); + + // Gracefully print the error + kprint((uint8_t*)"\nPage fault! ( "); + if(!(regs.err_code & 0x1)) + kprint((uint8_t*)"Present "); + if(regs.err_code & 0x2) + kprint((uint8_t*)"Read-Only "); + if(regs.err_code & 0x4) + kprint((uint8_t*)"User-Mode "); + if(regs.err_code & 0x8) + kprint((uint8_t*)"Reserved"); + printf(") at %x\n", faulting_addr); + PANIC("Page fault"); +} diff --git a/kernel/mem/paging.h b/kernel/mem/paging.h index ebe616e..cab5e14 100644 --- a/kernel/mem/paging.h +++ b/kernel/mem/paging.h @@ -1,81 +1,81 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef PAGING_H -#define PAGING_H - -#include -#include "../drivers/isr.h" -#include "kheap.h" - -#define FRAME_SIZE 4096 -#define PAGE_TABLE_SIZE 1024 -#define PAGE_DIRECTORY_SIZE 1024 -#define PAGE_NOT_PRESENT 0 -#define PAGE_PRESENT 1 -#define PAGE_READ_ONLY 0 -#define PAGE_READ_WRITE 1 -#define PAGE_USER 0 -#define PAGE_SUPERVISOR 0 -#define PAGE_SIZE_4KB 0 -#define PAGE_SIZE_4MB 1 -// Frames macros -#define FRAME_ALLOCATIONS_SECTION_SIZE 32 -#define USED_FRAME_SECTION 0xFFFFFFFF -#define FREE_FRAME_SECTION 0x00000000 - -#define FRAME(addr) (addr/FRAME_SIZE) -#define FRAME_SECTION(frame) (frame/FRAME_ALLOCATIONS_SECTION_SIZE) -#define FRAME_OFFSET(frame) (frame%FRAME_ALLOCATIONS_SECTION_SIZE) - -// Set physical memory to 15 MiB -#define PHYSICAL_MEM_SIZE 0x10000000 - -struct page { // Single page structure, from intel's developer manual - uint8_t pr : 1; // Present: 1 to map 4KB page - uint8_t rw : 1; // Read/Write mode - uint8_t us : 1; // if 0, user mode access aren't allowed to the page - uint8_t pw : 1; // Page-level write through - uint8_t pc : 1; // Page-level cache disable - uint8_t ac : 1; // 1 if we have accessed 4kb page - uint8_t di : 1; // 1 if page has been written(dirty) - uint8_t pa : 1; // Unused bit - uint8_t gl : 1; // 1 if page is global - uint8_t ig : 3; // Unused bit - uint32_t fr: 20; // Physical address of frame -} __attribute__((packed)); -typedef struct page page_t; - -typedef struct page_table { - page_t pages[PAGE_TABLE_SIZE]; -} page_table_t; - -/* Holds 2 arrays for each page directory - * one holds the physical address, while - * the other one holds the virtual address - * (to write/read to it) */ -typedef struct page_directory { - page_table_t *page_tables_virtual[PAGE_DIRECTORY_SIZE]; - uint32_t page_tables_physical[PAGE_DIRECTORY_SIZE]; -} page_directory_t; - -// Setup environment, page directories and enable paging -void init_paging(); -// Perform the "enable-paging" operation to the right register -void enable_paging(page_directory_t *dir); -// Retrieve a pointer from the given page -page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir); -// Identity map(phys = virtual addr) to access it as if paging wasn't enabled -void identity_map(); -// Delete a frame -void free_frame(page_t *page); -// Allocate a new frame -void alloc_frame(page_t *page, int32_t is_super, int32_t is_write); -// Page faults handler(ISR recorder) -void page_fault(registers_t regs); - -#endif +/***************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/vulcanos * + *****************************************/ +#ifndef PAGING_H +#define PAGING_H + +#include +#include "../drivers/isr.h" +#include "kheap.h" + +#define FRAME_SIZE 4096 +#define PAGE_TABLE_SIZE 1024 +#define PAGE_DIRECTORY_SIZE 1024 +#define PAGE_NOT_PRESENT 0 +#define PAGE_PRESENT 1 +#define PAGE_READ_ONLY 0 +#define PAGE_READ_WRITE 1 +#define PAGE_USER 0 +#define PAGE_SUPERVISOR 0 +#define PAGE_SIZE_4KB 0 +#define PAGE_SIZE_4MB 1 +// Frames macros +#define FRAME_ALLOCATIONS_SECTION_SIZE 32 +#define USED_FRAME_SECTION 0xFFFFFFFF +#define FREE_FRAME_SECTION 0x00000000 + +#define FRAME(addr) (addr/FRAME_SIZE) +#define FRAME_SECTION(frame) (frame/FRAME_ALLOCATIONS_SECTION_SIZE) +#define FRAME_OFFSET(frame) (frame%FRAME_ALLOCATIONS_SECTION_SIZE) + +// Set physical memory to 15 MiB +#define PHYSICAL_MEM_SIZE 0x10000000 + +struct page { // Single page structure, from intel's developer manual + uint8_t pr : 1; // Present: 1 to map 4KB page + uint8_t rw : 1; // Read/Write mode + uint8_t us : 1; // if 0, user mode access aren't allowed to the page + uint8_t pw : 1; // Page-level write through + uint8_t pc : 1; // Page-level cache disable + uint8_t ac : 1; // 1 if we have accessed 4kb page + uint8_t di : 1; // 1 if page has been written(dirty) + uint8_t pa : 1; // Unused bit + uint8_t gl : 1; // 1 if page is global + uint8_t ig : 3; // Unused bit + uint32_t fr: 20; // Physical address of frame +} __attribute__((packed)); +typedef struct page page_t; + +typedef struct page_table { + page_t pages[PAGE_TABLE_SIZE]; +} page_table_t; + +/* Holds 2 arrays for each page directory + * one holds the physical address, while + * the other one holds the virtual address + * (to write/read to it) */ +typedef struct page_directory { + page_table_t *page_tables_virtual[PAGE_DIRECTORY_SIZE]; + uint32_t page_tables_physical[PAGE_DIRECTORY_SIZE]; +} page_directory_t; + +// Setup environment, page directories and enable paging +void init_paging(); +// Perform the "enable-paging" operation to the right register +void enable_paging(page_directory_t *dir); +// Retrieve a pointer from the given page +page_t *get_page(uint32_t address, int32_t make, page_directory_t *dir); +// Identity map(phys = virtual addr) to access it as if paging wasn't enabled +void identity_map(); +// Delete a frame +void free_frame(page_t *page); +// Allocate a new frame +void alloc_frame(page_t *page, int32_t is_super, int32_t is_write); +// Page faults handler(ISR recorder) +void page_fault(registers_t regs); + +#endif diff --git a/kernel/userspace/Makefile b/kernel/userspace/Makefile index bf4f717..fb310a7 100644 --- a/kernel/userspace/Makefile +++ b/kernel/userspace/Makefile @@ -1,10 +1,10 @@ -OBJS = shell.o fetch.o -VER := $(shell git rev-parse --short HEAD) - -CC = i686-elf-gcc # cross-compiler -CFLAGS = -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c - -all:${OBJS} - -%.o: %.c - $(CC) $(CFLAGS) $< -o $@ +OBJS = shell.o fetch.o +VER := $(shell git rev-parse --short HEAD) + +CC = i686-elf-gcc # cross-compiler +CFLAGS = -DDEFAULT_USER=root -DDEFAULT_HOSTNAME=vulcan -DVULCAN_VERSION=$(VER) -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c + +all:${OBJS} + +%.o: %.c + $(CC) $(CFLAGS) $< -o $@ diff --git a/kernel/userspace/fetch.c b/kernel/userspace/fetch.c index e461b6b..44254df 100644 --- a/kernel/userspace/fetch.c +++ b/kernel/userspace/fetch.c @@ -1,75 +1,75 @@ -#include "fetch.h" -#include "../libc/stdio.h" -#include "../libc/string.h" -#include "../libc/time.h" -#include "../drivers/tty.h" -#include "../drivers/cpuid.h" -#define STRINGIZE(x) #x -#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) - -static void get_date(); -static void get_cpuid(); -static void get_version(); - -void system_fetcher() { - uint8_t user[64], hostname[64]; -#ifdef DEFAULT_USER - strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER)); -#else - #error "-DDEFAULT_USER flag not set" -#endif - -#ifdef DEFAULT_HOSTNAME - strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME)); -#else - #error "-DDEFAULT_HOSTNAME flag not set" -#endif - // print first line - printf_color("\n __ __ ___ ___ ", LIGHT_RED, BLACK); - printf_color((char*)user, LIGHT_CYAN, BLACK); - printf_color("@", LIGHT_RED, BLACK); - printf_color((char*)hostname, LIGHT_CYAN, BLACK); - // print second line - printf_color("\n \\ \\ / / / _ \\/ __| ", LIGHT_RED, BLACK); - printf_color("-----------", LIGHT_RED, BLACK); - // print third line - printf_color("\n \\ V / | (_) \\__ \\ ", LIGHT_RED, BLACK); - printf_color("Date: ", LIGHT_CYAN, BLACK); - get_date(); - // print fourth line - printf_color("\n \\_/ \\___/|___/ ", LIGHT_RED, BLACK); - get_cpuid(); - // print VulcanOS version - get_version(); -} - -// Date format is D/M/YY -void get_date() { - printf("%d", get_time(TIME_R_DAY)); // Day - printf_color("/", LIGHT_BLUE, BLACK); - - printf("%d", get_time(TIME_R_MONTH)); // Month - printf_color("/", LIGHT_BLUE, BLACK); - - printf("%d", get_time(TIME_R_YEAR)); // Year -} - - -void get_cpuid() { - printf_color("CPU type: ", LIGHT_CYAN, BLACK); - printf("%s", (char*)get_cpu_type()); // Print CPU type - printf("%s%s%c", " (", (char*)get_cpu_family(), ')'); -} - - -void get_version() { - uint8_t version[64]; -#ifdef VULCAN_VERSION - strcpy(version, (uint8_t*)STRINGIZE_VALUE_OF(VULCAN_VERSION)); -#else - #error "-DVULCAN_VERSION flag not set" -#endif - - printf_color("\n\t\t\t\t\t Version: ", LIGHT_CYAN, BLACK); - printf_color((char*)version, LIGHT_GREEN, BLACK); -} +#include "fetch.h" +#include "../libc/stdio.h" +#include "../libc/string.h" +#include "../libc/time.h" +#include "../drivers/tty.h" +#include "../drivers/cpuid.h" +#define STRINGIZE(x) #x +#define STRINGIZE_VALUE_OF(x) STRINGIZE(x) + +static void get_date(); +static void get_cpuid(); +static void get_version(); + +void system_fetcher() { + uint8_t user[64], hostname[64]; +#ifdef DEFAULT_USER + strcpy(user, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_USER)); +#else + #error "-DDEFAULT_USER flag not set" +#endif + +#ifdef DEFAULT_HOSTNAME + strcpy(hostname, (uint8_t*)STRINGIZE_VALUE_OF(DEFAULT_HOSTNAME)); +#else + #error "-DDEFAULT_HOSTNAME flag not set" +#endif + // print first line + printf_color("\n __ __ ___ ___ ", LIGHT_RED, BLACK); + printf_color((char*)user, LIGHT_CYAN, BLACK); + printf_color("@", LIGHT_RED, BLACK); + printf_color((char*)hostname, LIGHT_CYAN, BLACK); + // print second line + printf_color("\n \\ \\ / / / _ \\/ __| ", LIGHT_RED, BLACK); + printf_color("-----------", LIGHT_RED, BLACK); + // print third line + printf_color("\n \\ V / | (_) \\__ \\ ", LIGHT_RED, BLACK); + printf_color("Date: ", LIGHT_CYAN, BLACK); + get_date(); + // print fourth line + printf_color("\n \\_/ \\___/|___/ ", LIGHT_RED, BLACK); + get_cpuid(); + // print VulcanOS version + get_version(); +} + +// Date format is D/M/YY +void get_date() { + printf("%d", get_time(TIME_R_DAY)); // Day + printf_color("/", LIGHT_BLUE, BLACK); + + printf("%d", get_time(TIME_R_MONTH)); // Month + printf_color("/", LIGHT_BLUE, BLACK); + + printf("%d", get_time(TIME_R_YEAR)); // Year +} + + +void get_cpuid() { + printf_color("CPU type: ", LIGHT_CYAN, BLACK); + printf("%s", (char*)get_cpu_type()); // Print CPU type + printf("%s%s%c", " (", (char*)get_cpu_family(), ')'); +} + + +void get_version() { + uint8_t version[64]; +#ifdef VULCAN_VERSION + strcpy(version, (uint8_t*)STRINGIZE_VALUE_OF(VULCAN_VERSION)); +#else + #error "-DVULCAN_VERSION flag not set" +#endif + + printf_color("\n\t\t\t\t\t Version: ", LIGHT_CYAN, BLACK); + printf_color((char*)version, LIGHT_GREEN, BLACK); +} diff --git a/kernel/userspace/fetch.h b/kernel/userspace/fetch.h index 39f2103..1fd0880 100644 --- a/kernel/userspace/fetch.h +++ b/kernel/userspace/fetch.h @@ -1,15 +1,15 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef FETCH_H -#define FETCH_H - -#include - -void system_fetcher(); - -#endif +/************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ +#ifndef FETCH_H +#define FETCH_H + +#include + +void system_fetcher(); + +#endif diff --git a/kernel/userspace/shell.c b/kernel/userspace/shell.c index 73cde48..f01234f 100644 --- a/kernel/userspace/shell.c +++ b/kernel/userspace/shell.c @@ -1,122 +1,122 @@ -#include "shell.h" -#include "fetch.h" -#include "../libc/string.h" -#include "../libc/stdio.h" -#include "../drivers/tty.h" -#include "../drivers/ports.h" -#include "../drivers/timer.h" - -void helper() { - puts("\nList of available commands:\n" - "\nhelp - Print this helper" - "\nint - Test some interrupts" - "\nbanner - Show banner" - "\nclear, cls - Clear the screen" - "\nregs - Prints register dump" - "\ntimer - Prints timer tick" - "\nabout - About this kernel" - "\nreboot - Reboot the system" - ); -} - -void test_interrupts() { - // Testing some interrupts - asm("int $0"); // Division by zero - asm("int $4"); // Stack overflow - asm("int $1"); // Page fault -} - -void about() { - printf_color("\n====== IceOS v0.0.1 (c) 2019 Marco 'icebit' Cetica ======\n\n", - LIGHT_CYAN, BLACK); - printf_color( - "iceOS is a x86 monolithic kernel written in C from scratch.\n" - "This project doesn't aim to be a fully functional operating system\n" - "with tons of drivers and graphical applications,\nit's just a learning tool " - "to teach myself concepts like\nOperating Systems, Computer Architecture and Digital Electronics.\n" - "\n\n" - "iceOS comes with the following features:\n" - "- Bare metal booting;\n" - "- VGA driver;\n" - "- Interrupts implementation;\n" - "- PIC & PIT implementation;\n" - "- PS2 driver;\n" - "- Support for x86 architecture;\n" - "- GRUB as bootloader;\n", - LIGHT_GREEN, BLACK); -} - -void register_dump() { - register uint32_t eax_v asm("eax"); - register uint32_t ebx_v asm("ebx"); - register uint32_t ecx_v asm("ecx"); - register uint32_t edx_v asm("edx"); - register uint32_t esx_v asm("esi"); - register uint32_t edi_v asm("edi"); - register uint32_t ebp_v asm("ebp"); - register uint32_t esp_v asm("esp"); - - printf_color("\n===================================\n" - " BEGIN 32 BITS CPU REGISTER DUMP \n" - "===================================\n", - LIGHT_BROWN, BLACK); - printf(" EAX: %x\n" - " EBX: %x\n" - " ECX: %x\n" - " EDX: %x\n" - " ESX: %x\n" - " EDI: %x\n" - " EBP: %x\n" - " ESP: %x\n", - eax_v, ebx_v, ecx_v, edx_v, esx_v, edi_v, ebp_v, esp_v); - printf_color("\n==================================\n" - " END 32 BITS CPU REGISTER DUMP \n" - "==================================\n", - LIGHT_BROWN, BLACK); -} - -void timer_dump() { - uint8_t buf[8]; - uitoa(tick, buf, 10); - - printf_color("\nTicks since boot: ", - LIGHT_GREEN, BLACK); - printf_color((const char*)buf, - LIGHT_CYAN, BLACK); -} -void reboot() { - uint8_t tmp; - asm("cli"); // First disable all interrupts - - // Clear keyboard buffers - do { - tmp = inb(0x64); // Keyboard interface - if(check_flag(tmp, 0) != 0) - inb(0x60); // Clear keyboard data - } while(check_flag(tmp, 1) != 0); - - outb(0x64, 0xFE); // Reset the CPU -} - -void processCommand(uint8_t *cmd) { - if(strcmp(cmd, (uint8_t*)"help") == 0) - helper(); - else if(strcmp(cmd, (uint8_t*)"int") == 0) - test_interrupts(); - else if(strcmp(cmd, (uint8_t*)"clear") == 0 || strcmp(cmd, (uint8_t*)"cls") == 0) - clear_prompt(); - else if(strcmp(cmd, (uint8_t*)"about") == 0) - about(); - else if(strcmp(cmd, (uint8_t*)"regs") == 0) - register_dump(); - else if(strcmp(cmd, (uint8_t*)"timer") == 0) - timer_dump(); - else if(strcmp(cmd, (uint8_t*)"fetch") == 0) - system_fetcher(); - else if(strcmp(cmd, (uint8_t*)"reboot") == 0) - reboot(); - else if(strcmp(cmd, (uint8_t*)"") == 0) - puts(""); - else - puts("\nCommand not found!"); -} +#include "shell.h" +#include "fetch.h" +#include "../libc/string.h" +#include "../libc/stdio.h" +#include "../drivers/tty.h" +#include "../drivers/ports.h" +#include "../drivers/timer.h" + +void helper() { + puts("\nList of available commands:\n" + "\nhelp - Print this helper" + "\nint - Test some interrupts" + "\nbanner - Show banner" + "\nclear, cls - Clear the screen" + "\nregs - Prints register dump" + "\ntimer - Prints timer tick" + "\nabout - About this kernel" + "\nreboot - Reboot the system" + ); +} + +void test_interrupts() { + // Testing some interrupts + asm("int $0"); // Division by zero + asm("int $4"); // Stack overflow + asm("int $1"); // Page fault +} + +void about() { + printf_color("\n====== IceOS v0.0.1 (c) 2019 Marco 'icebit' Cetica ======\n\n", + LIGHT_CYAN, BLACK); + printf_color( + "iceOS is a x86 monolithic kernel written in C from scratch.\n" + "This project doesn't aim to be a fully functional operating system\n" + "with tons of drivers and graphical applications,\nit's just a learning tool " + "to teach myself concepts like\nOperating Systems, Computer Architecture and Digital Electronics.\n" + "\n\n" + "iceOS comes with the following features:\n" + "- Bare metal booting;\n" + "- VGA driver;\n" + "- Interrupts implementation;\n" + "- PIC & PIT implementation;\n" + "- PS2 driver;\n" + "- Support for x86 architecture;\n" + "- GRUB as bootloader;\n", + LIGHT_GREEN, BLACK); +} + +void register_dump() { + register uint32_t eax_v asm("eax"); + register uint32_t ebx_v asm("ebx"); + register uint32_t ecx_v asm("ecx"); + register uint32_t edx_v asm("edx"); + register uint32_t esx_v asm("esi"); + register uint32_t edi_v asm("edi"); + register uint32_t ebp_v asm("ebp"); + register uint32_t esp_v asm("esp"); + + printf_color("\n===================================\n" + " BEGIN 32 BITS CPU REGISTER DUMP \n" + "===================================\n", + LIGHT_BROWN, BLACK); + printf(" EAX: %x\n" + " EBX: %x\n" + " ECX: %x\n" + " EDX: %x\n" + " ESX: %x\n" + " EDI: %x\n" + " EBP: %x\n" + " ESP: %x\n", + eax_v, ebx_v, ecx_v, edx_v, esx_v, edi_v, ebp_v, esp_v); + printf_color("\n==================================\n" + " END 32 BITS CPU REGISTER DUMP \n" + "==================================\n", + LIGHT_BROWN, BLACK); +} + +void timer_dump() { + uint8_t buf[8]; + uitoa(tick, buf, 10); + + printf_color("\nTicks since boot: ", + LIGHT_GREEN, BLACK); + printf_color((const char*)buf, + LIGHT_CYAN, BLACK); +} +void reboot() { + uint8_t tmp; + asm("cli"); // First disable all interrupts + + // Clear keyboard buffers + do { + tmp = inb(0x64); // Keyboard interface + if(check_flag(tmp, 0) != 0) + inb(0x60); // Clear keyboard data + } while(check_flag(tmp, 1) != 0); + + outb(0x64, 0xFE); // Reset the CPU +} + +void processCommand(uint8_t *cmd) { + if(strcmp(cmd, (uint8_t*)"help") == 0) + helper(); + else if(strcmp(cmd, (uint8_t*)"int") == 0) + test_interrupts(); + else if(strcmp(cmd, (uint8_t*)"clear") == 0 || strcmp(cmd, (uint8_t*)"cls") == 0) + clear_prompt(); + else if(strcmp(cmd, (uint8_t*)"about") == 0) + about(); + else if(strcmp(cmd, (uint8_t*)"regs") == 0) + register_dump(); + else if(strcmp(cmd, (uint8_t*)"timer") == 0) + timer_dump(); + else if(strcmp(cmd, (uint8_t*)"fetch") == 0) + system_fetcher(); + else if(strcmp(cmd, (uint8_t*)"reboot") == 0) + reboot(); + else if(strcmp(cmd, (uint8_t*)"") == 0) + puts(""); + else + puts("\nCommand not found!"); +} diff --git a/kernel/userspace/shell.h b/kernel/userspace/shell.h index a69cf0c..4581295 100644 --- a/kernel/userspace/shell.h +++ b/kernel/userspace/shell.h @@ -1,19 +1,19 @@ -/************************************** - * VulcanOS Kernel * - * Developed by Marco 'icebit' Cetica * - * (c) 2019-2021 * - * Released under GPLv3 * - * https://github.com/ice-bit/iceOS * - ***************************************/ -#ifndef _SHELL_H_ -#define _SHELL_H_ - -#include - -#define bit(n) (1 << (n)) -#define check_flag(flags, n) ((flags) & bit(n)) - -void helper(); -void processCommand(uint8_t *cmd); - -#endif +/************************************** + * VulcanOS Kernel * + * Developed by Marco 'icebit' Cetica * + * (c) 2019-2021 * + * Released under GPLv3 * + * https://github.com/ice-bit/iceOS * + ***************************************/ +#ifndef _SHELL_H_ +#define _SHELL_H_ + +#include + +#define bit(n) (1 << (n)) +#define check_flag(flags, n) ((flags) & bit(n)) + +void helper(); +void processCommand(uint8_t *cmd); + +#endif diff --git a/link.ld b/link.ld index 201e2dc..5af9144 100644 --- a/link.ld +++ b/link.ld @@ -1,28 +1,27 @@ -ENTRY(kernel_loader) -SECTIONS -{ - - .text 0x100000 : - { - code = .; _code = .; __code = .; - *(.text) - . = ALIGN(4096); - } - - .data : - { - data = .; _data = .; __data = .; - *(.data) - *(.rodata) - . = ALIGN(4096); - } - - .bss : - { - bss = .; _bss = .; __bss = .; - *(.bss) - . = ALIGN(4096); - } - - end = .; _end = .; __end = .; -} +ENTRY(kernel_loader) + +SECTIONS +{ + . = 1M; + + .boot : + { + KEEP(*(.multiboot_header)) + . = ALIGN(4096); + } + + .text : + { + *(.data) + *(.rodata) + . = ALIGN(4096); + } + + .bss : + { + *(.bss) + . = ALIGN(4096); + } + + end = .; _end = .; __end = .; +} \ No newline at end of file