summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore58
-rw-r--r--LICENSE625
-rw-r--r--README.md3
-rwxr-xr-xbackup.sh13
-rwxr-xr-xcompiler/create_crosscompiler.sh42
-rw-r--r--notes23
-rw-r--r--src/.gdb_history256
-rw-r--r--src/amd64_vol2.pdfbin0 -> 3511027 bytes
-rw-r--r--src/bootloader/bios_functions/bios_disk.asm38
-rw-r--r--src/bootloader/bios_functions/print.asm59
-rw-r--r--src/bootloader/bootloader.asm145
-rw-r--r--src/bootloader/cpu_check.asm100
-rw-r--r--src/bootloader/enter_kernel.asm80
-rw-r--r--src/bootloader/enter_kernel_backup87
-rw-r--r--src/bootloader/gdt.asm70
-rw-r--r--src/bootloader/multicore.asm10
-rw-r--r--src/bootloader/notes0
-rw-r--r--src/bootloader/video.asm179
-rw-r--r--src/debug/.gdb_history4
-rwxr-xr-xsrc/indigo_osbin0 -> 15312 bytes
-rw-r--r--src/kernel/include/acpi.h39
-rw-r--r--src/kernel/include/libc.h10
-rw-r--r--src/kernel/include/paging.h60
-rw-r--r--src/kernel/include/printf.h117
-rw-r--r--src/kernel/include/serial.h16
-rw-r--r--src/kernel/include/video.h49
-rw-r--r--src/kernel/kernel.c42
-rw-r--r--src/kernel/libs/acpi.c61
-rw-r--r--src/kernel/libs/drivers/serial.c43
-rw-r--r--src/kernel/libs/drivers/video.c6
-rw-r--r--src/kernel/libs/libc.c47
-rw-r--r--src/kernel/libs/page.c107
-rw-r--r--src/kernel/libs/printf.c924
-rw-r--r--src/kernel/libs/printf.h117
-rw-r--r--src/link.ld37
-rw-r--r--src/makefile53
-rwxr-xr-xtools/edid/bparse-edid16
-rw-r--r--tools/edid/desktop_edidbin0 -> 128 bytes
-rw-r--r--tools/edid/laptop_edidbin0 -> 128 bytes
-rwxr-xr-xtools/page/page.py29
40 files changed, 3565 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d1ab991
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,58 @@
+# ---> C
+# 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
+
+*.gz
+compiler/*
+!.gitignore
+!create_crosscompiler.sh
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e142a52
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,625 @@
+GNU GENERAL PUBLIC LICENSE
+
+Version 3, 29 June 2007
+
+Copyright © 2007 Free Software Foundation, Inc. <https://fsf.org/>
+
+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.
+
+<one line to give the program's name and a brief idea of what it does.>
+
+Copyright (C) <year> <name of author>
+
+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 <https://www.gnu.org/licenses/>.
+
+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:
+
+<program> Copyright (C) <year> <name of author>
+
+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 <https://www.gnu.org/licenses/>.
+
+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 <https://www.gnu.org/
+licenses /why-not-lgpl.html>.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..969b48b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# IndigoOS
+
+mod testing \ No newline at end of file
diff --git a/backup.sh b/backup.sh
new file mode 100755
index 0000000..74c3189
--- /dev/null
+++ b/backup.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+if [ $# -ne 1 ]
+then
+ echo "Usage: $0 [file suffix]"
+ exit 1
+fi
+
+archive_name=$(date +%m.%d.%y."$1".tar)
+shopt -s extglob
+tar -cf $archive_name !(*gz)
+pigz -9 $archive_name
+
+
diff --git a/compiler/create_crosscompiler.sh b/compiler/create_crosscompiler.sh
new file mode 100755
index 0000000..49bc9cb
--- /dev/null
+++ b/compiler/create_crosscompiler.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+export PREFIX=/home/indigo/projects/small/indigo_os/compiler/indigo_gcc
+export TARGET=x86_64-elf
+export PATH="$PREFIX/bin:$PATH"
+
+export JOBS=7
+
+mkdir -p indigo_gcc/
+mkdir -p src/
+
+mkdir src/packs
+mkdir src/build_binutils
+mkdir src/build_gcc
+
+
+
+#download the latest binutils
+lftp -c "set xfer:clobber on; connect ftp.gnu.org; get -O src/packs/ gnu/binutils/$(lftp -c 'connect ftp.gnu.org; ls gnu/binutils/binutils*.tar.gz' | awk '{print $NF}' | sort -V | tail -n 1)"
+
+#download gcc
+#yes, I know, I'm making too many connections, I'm tired as fuck rn
+latest_gcc=$(lftp -c 'connect ftp.gnu.org; ls -d gnu/gcc/gcc-*' | grep -E "^d" | awk '{print $NF}' | sort -V | tail -1)
+lftp -c "set xfer:clobber on; connect ftp.gnu.org; get -O src/packs/ gnu/gcc/$latest_gcc/$latest_gcc.tar.gz"
+
+cd src/packs/
+
+for f in *tar.gz; do
+ tar -xf "$f"
+done
+
+cd ../build_binutils
+../packs/binutils-*/configure --target=$TARGET --enable-interwork --enable-multilib --disable-nls --disable-werror --prefix="$PREFIX" &&
+make -j$JOBS all install 2>&1 | tee binutils_build_log
+make install
+
+cd ../build_gcc
+../packs/gcc-*/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --disable-libssp --enable-languages=c --without-headers &&
+make -j$JOBS all-gcc &&
+make -j$JOBS all-target-libgcc &&
+make install-gcc
+make install-target-libgcc
+
diff --git a/notes b/notes
new file mode 100644
index 0000000..1d7d34a
--- /dev/null
+++ b/notes
@@ -0,0 +1,23 @@
+| type start end size |
+| 1 1 0x0000000000000000 0x000000000009FC00 0x000000000009FC00 |
+| 2 1 0x000000000009FC00 0x00000000000A0000 0x0000000000000400 |
+| 2 1 0x00000000000E0000 0x0000000000100000 0x0000000000020000 |
+| 1 1 0x0000000000100000 0x00000000BA6E4000 0x00000000BA5E4000 |
+| 2 1 0x00000000BA6E4000 0x00000000BA868000 0x0000000000184000 |
+| 3 1 0x00000000BA868000 0x00000000BA878000 0x0000000000010000 |
+| 4 1 0x00000000BA878000 0x00000000BB67A000 0x0000000000E02000 |
+| 2 1 0x00000000BB67A000 0x00000000BCA37000 0x00000000013BD000 |
+| 1 1 0x00000000BCA37000 0x00000000BCA38000 0x0000000000001000 |
+| 4 1 0x00000000BCA38000 0x00000000BCC3E000 0x0000000000206000 |
+| 1 1 0x00000000BCC3E000 0x00000000BD083000 0x0000000000445000 |
+| 2 1 0x00000000BD083000 0x00000000BD7F4000 0x0000000000771000 |
+| 1 1 0x00000000BD7F4000 0x00000000BD800000 0x000000000000C000 |
+| 1 1 0x0000000100001000 0x000000043F000000 0x000000033EFFF000 |
+| 2 1 0x00000000F8000000 0x00000000FC000000 0x0000000004000000 |
+| 2 1 0x00000000FEC00000 0x00000000FEC01000 0x0000000000001000 |
+| 2 1 0x00000000FEC10000 0x00000000FEC11000 0x0000000000001000 |
+| 2 1 0x00000000FEC20000 0x00000000FEC21000 0x0000000000001000 |
+| 2 1 0x00000000FED00000 0x00000000FED01000 0x0000000000001000 |
+| 2 1 0x00000000FED61000 0x00000000FED71000 0x0000000000010000 |
+| 2 1 0x00000000FED80000 0x00000000FED90000 0x0000000000010000 |
+| 2 1 0x00000000FEF00000 0x0000000100000000 0x0000000001100000 |
diff --git a/src/.gdb_history b/src/.gdb_history
new file mode 100644
index 0000000..f627526
--- /dev/null
+++ b/src/.gdb_history
@@ -0,0 +1,256 @@
+x 0x7FFE1667
+x 0x7FFE1667
+x 0x200000
+quit
+break main
+c
+next
+stepi
+next
+x 0x200000
+return
+next
+x 0x20000
+x 0x20000 4096
+dq 0x20000 (4096/8)
+dq 0x20000 1
+dq 0x20000 2
+dq 0x20000 3
+dq 0x200000 3
+print rsdp.v1->rsdp
+print rsdp->v1.rsdt_addr
+print (void*)rsdp->v1.rsdt_addr
+print (page table*)0x4000
+print (page_table*)0x4000
+print (page_table*)0x4000->pml4e
+print (page_table*)0x4000.pml4e
+print (page_table*)0x4000->pml4e
+print *(page_table*)0x4000->pml4e
+print (page_table*)0x4000.pml4e
+print (page_table*)0x4000.pml4e[0]
+print (page_table*)0x4000->pml4e[0]
+print (page_table*)0x4000.pml4e[0]
+print (page_table*)0x4000.pdpe
+print (page_table*)0x4000.pde
+print (page_table*)0x4000
+print *(page_table*)0x4000
+print *((page_table*)0x4000)
+print *((page_table*)0x4000).pde
+print *((page_table*)0x4000).pml4e
+print *((page_table*)0x3000).pml4e
+print *((page_table*)0x4000).pml4e
+print *((page_table*)0x4000).pde
+print *((page_table*)0x4000).pte
+print rsdp.v1.base_addr
+print rsdp.v1.rsdt_addr
+print (void*)rsdp.v1.rsdt_addr
+print *((page_table*)0x4000).pte
+print *((page_table*)0x4000).pte[1]
+print *((page_table*)0x4000).pte
+print *((page_table*)0x4000)->pte[1]
+print *((page_table*)0x4000).pte
+print *((page_table*)0x4000).pte[0]
+print ((page_table*)0x4000).pte
+print ((page_table*)0x4000)->pte
+print ((page_table*)0x4000)->pte[0]
+print ((page_table*)0x4000)->pte[1]
+print ((page_table*)0x4000)->pte[2]
+print ((page_table*)0x4000)->pte[3]
+print ((page_table*)0x4000)->pte[4]
+print ((page_table*)0x4000)->pte[5]
+print ((page_table*)0x4000)->pte[10]
+print ((page_table*)0x4000)->pte[1512]
+print ((page_table*)0x4000)->pte[512]
+print ((page_table*)0x4000)->pte[513]
+print ((page_table*)0x4000)->pte[512]
+print ((page_table*)0x4000)->pte[511]
+print ((page_table*)0x4000)->pte[510]
+print ((page_table*)0x4000)->pte
+quit
+break main
+c
+next
+print rsdp.v1.rsdt_addr
+print (void*)rsdp.v1.rsdt_addr
+quit
+break map_page
+c
+next
+print size
+next
+print table->pde[pde_i]
+next
+print table->pde[pde_i]
+next
+print table->pde[pde_i]
+next
+print table->pde[pde_i]
+print table->pte[pte_i]
+next
+print table->pte[pte_i]
+next
+x 0x20000
+dq 0x20000 30
+dq 0x20000 40
+print table->pte[pte_i]
+context
+quit
+break map_page
+c
+next
+print table->pte[pte_i0
+print table->pte[pte_i]
+quit
+r
+c
+quit
+c
+quit
+break panic
+c
+x 0x7ffe1000
+quit
+break panic
+c
+x 0x200000
+dq 0x200000
+dq 0x200000 4
+dq 0x200000 8
+search -4 FACP
+search -4 FACP
+search -4 'FACP'
+search -s 'FACP'
+search -s 'ACPI'
+search -s 'RSDT'
+x 0x200000 + 0x667
+dq 0x200000 + 0x667
+dq (0x200000 + 0x667)
+x 0x200000 + 0x667
+x/20i 0x200000 + 0x667
+x/20x 0x200000 + 0x667
+x/100x 0x200000 + 0x667
+x/400x 0x200000 + 0x667
+x/400x 0x200000 + 0x1000
+x/400x 0x200000 + (0x1000)
+x/400x 0x200000 + (0x1000-8)
+x/400x 0x200000 + (0x1000-8)
+quit
+break panic
+c
+x 0x2000
+x 0x20000
+x 0x200000
+x 0x2000000
+x 0x200000
+x 0x2000000
+x 0x200000
+x 0x202000
+x 0x20b000
+x 0x20b000+8
+x 0x20b000
+x 0x202000
+x 0x201000
+x 0x200000
+x 0x201000
+x 0x201000-8
+x 0x200000-8
+x 0x200000
+quit
+break panic
+c
+0x200000
+x 0x200000
+x/s 0x200000
+quit
+break panic
+c
+quit
+break panic
+c
+quit
+break panic
+c
+quit
+break panic
+c
+x 0x20000
+x 0x21667
+x 0x20667
+x 0x200000
+x 0x200667
+x 0x200667
+x/s 0x200667
+quit
+break panic
+c
+x apic
+quit
+break main
+c
+next
+pirnt apic
+print apic
+print rsdp
+print apic
+print *apic
+(struct apic_header *)((uint64_t)0x200000 + (rsdp->v1.rsdt_addr % 0x1000)
+print (struct apic_header *)((uint64_t)0x200000 + (rsdp->v1.rsdt_addr % 0x1000)
+quit
+break panic
+c
+prit apic
+print apic
+print acpi
+print *acpi
+print acpi
+print acpi.sig
+quit
+break main
+c
+next
+print apic
+ptype apic_header
+quit
+ptype acpi
+ptype acpi_header
+break main
+c
+next
+print apic
+print acpi
+print acpi.*
+context
+print apic
+quit
+break main
+c
+next
+print apic
+print apci_header
+ptype apci_header
+ptype apci_header
+quit
+break main
+c
+next
+print acpi
+next
+print acpi
+quit
+print acpi
+break main
+c
+print acpi
+next
+print acpi
+next
+print acpi
+next
+print acpi
+next
+print acpi
+ptype acpi_header
+quit
+quit
+quit
+quit
diff --git a/src/amd64_vol2.pdf b/src/amd64_vol2.pdf
new file mode 100644
index 0000000..edcafc6
--- /dev/null
+++ b/src/amd64_vol2.pdf
Binary files differ
diff --git a/src/bootloader/bios_functions/bios_disk.asm b/src/bootloader/bios_functions/bios_disk.asm
new file mode 100644
index 0000000..28fc74d
--- /dev/null
+++ b/src/bootloader/bios_functions/bios_disk.asm
@@ -0,0 +1,38 @@
+bios_disk:
+.load_sectors:
+pusha
+mov es, dx
+
+mov ah, 0x02 ; read disc sectors
+mov ch, 0x00 ; track 0
+mov dh, 0x00 ; head 0
+mov dl, [stage0.boot_device]
+
+int 0x13
+
+jc .failed
+
+mov ah, 0
+popa
+ret
+
+.failed:
+
+mov bx, .loadsectors_error
+mov cx, 0
+call bios_print
+
+push 0
+mov al, ah
+mov ah, 0 ; you need to clean up the bios print function!
+push ax
+mov cx, 1
+mov bx, sp
+call bios_print
+
+
+mov ah, 1
+popa
+ret
+
+.loadsectors_error: db "Error loading sectors: ", 0
diff --git a/src/bootloader/bios_functions/print.asm b/src/bootloader/bios_functions/print.asm
new file mode 100644
index 0000000..d071cd9
--- /dev/null
+++ b/src/bootloader/bios_functions/print.asm
@@ -0,0 +1,59 @@
+;TODO fix null problem, allow direct passes
+bios_print:
+;push ax ; we need to use ax, so let's push it in case whoever called needs it
+pusha
+mov ah, 0x0e ; tells bios we're in tty mode
+
+.print_loop:
+mov al, [bx] ; al is the char MEANT TO BE CX
+cmp al, 0 ; compare the char we're about to print with null
+je .fini ; if it is null, we gonna scoot the fuck outta here
+
+test cx, cx ; if cx is zero, ascii, otherwise hex string
+jne .print_hex
+int 0x10 ; bios call, actually prints the char
+.print_hex_ret:
+inc bx ; adds to the pointer
+jmp .print_loop ; goes back to loop start
+
+.fini:
+mov al, 0xd ; \r
+int 0x10
+mov al, 0xa ; \n
+int 0x10
+popa
+ret
+
+
+.print_hex:
+mov al, '0'
+int 0x10
+
+mov al, 'x'
+int 0x10
+
+mov al, [bx] ; shift bits to get first nibble
+shr al, 4
+call .bios_print_nibble
+
+mov al, [bx]
+and al, 0x0f
+call .bios_print_nibble
+
+mov al, ' '
+int 0x10
+
+jmp .print_hex_ret
+
+
+.bios_print_nibble:
+cmp al, 9 ; see if letter worthy
+ja .print_hex_letter
+add al, 0x30 ;'1'
+int 0x10
+ret
+
+.print_hex_letter:
+add al, 0x57 ;'a'
+int 0x10
+ret
diff --git a/src/bootloader/bootloader.asm b/src/bootloader/bootloader.asm
new file mode 100644
index 0000000..14116db
--- /dev/null
+++ b/src/bootloader/bootloader.asm
@@ -0,0 +1,145 @@
+[bits 16]
+[extern _kernel_size]
+[extern _bootloader_stage1_size]
+[extern _kernel_loc]
+
+;TODO clean up unreal mode
+jmp stage0
+times 3-($-$$) db 0x90 ; a temporary dirty fix to emulate a floppy disk insted of a hard risk
+times 59 db 0 ; (TODO support hard disks)
+
+stage0:
+
+jmp 0:.entry
+.entry:
+
+mov ax, 0
+mov ds, ax
+mov bp, ax
+
+mov ds, ax
+mov es, ax
+
+mov ax, 0x8fc0
+mov ss, ax
+mov ax, 0xfffe
+mov sp, ax
+
+mov al, 0x92
+or al, 2
+out 0x92, al
+
+mov [.boot_device], dl
+
+mov bx, .loadstage2_msg
+mov cx, 0
+call bios_print
+
+; TODO put in an error message and a maximum fail count
+.load_stage1:
+mov al, _bootloader_stage1_size
+mov cl, 0x2 ; read sector 2
+mov dx, 0x0 ; dest segment 0
+mov bx, 0x7e00 ; dest offst 0
+call bios_disk.load_sectors
+
+
+jmp mbr_end.entry
+
+.boot_device: db 0
+
+.loadstage2_msg: db "Loading (stage 2) bootloader...", 0
+
+%include "bootloader/bios_functions/bios_disk.asm"
+%include "bootloader/bios_functions/print.asm"
+
+times 510 - ($-$$) db 0
+dw 0xaa55
+
+%include "bootloader/gdt.asm"
+
+boot_msg:
+.debugmsg: db "debugeroni", 0
+.kernel_loaded: db `Kernel loaded!\r\nBooting to protected, then long mode...`, 0
+.stage2_loaded: db `Done loading bootloader!\r\nLoading kernel...`, 0
+
+
+
+
+mbr_end:
+.entry:
+; entering unreal mode
+mov bx, boot_msg.stage2_loaded
+mov cx, 0
+call bios_print
+
+
+cli
+push ds
+
+lgdt [protected_gdt.descriptor]
+
+mov eax, cr0
+or al, 1
+mov cr0, eax
+
+jmp $+2
+
+mov bx, 0x10 ; descriptor 2, the data descriptor
+mov ds, bx ; put it into the segment register
+mov es, bx ;
+
+and al, 0xfe
+mov cr0, eax
+
+pop ds
+sti
+;we are now in unreal mode
+
+mov cl, 5 ; starting sector TODO automate this
+mov edi, _kernel_loc
+.loop:
+mov al, 0x1 ; sector count
+mov dx, 0x0 ; dest addr segment
+mov bx, 0x500 ; dest addr offset
+call bios_disk.load_sectors
+
+
+inc cl
+
+push cx
+
+mov esi, 0x500
+mov ecx, 512
+a32 rep movsb
+nop
+
+mov bx, boot_msg.debugmsg
+mov cx, 0
+call bios_print
+
+pop cx
+
+cmp cl, _kernel_size
+je .loop_end
+
+jmp .loop
+
+.loop_end:
+
+mov bx, boot_msg.kernel_loaded
+mov cx, 0
+call bios_print
+
+
+call detect_arch
+call vbe_init
+done:
+
+call enter_longmode
+jmp $
+
+%include "bootloader/cpu_check.asm"
+%include "bootloader/video.asm"
+%include "bootloader/enter_kernel.asm"
+times 2048 - ($ - $$) db 0
diff --git a/src/bootloader/cpu_check.asm b/src/bootloader/cpu_check.asm
new file mode 100644
index 0000000..ffdd908
--- /dev/null
+++ b/src/bootloader/cpu_check.asm
@@ -0,0 +1,100 @@
+; TODO move this file to something like "system_check", now that we do ram checks here
+[extern _meminfo_loc]
+detect_arch:
+; todo: figure out how to just handle invalid opcode exceptions, it would be faster and (maybe?) easier
+; todo: digest this part a little better when it's _not_ 1am.
+pushfd ; pushes eflags to stack
+pushfd ; pushes eflags to stack a second time
+xor dword [esp], 0x00200000 ; inverses the ID bit to see if cpuid is a thing
+pop eax ;gets our modified cpuid back
+xor eax, [esp] ; checks with the first time we pushed it; the OG eflag
+popfd ; pops the flags back I guess?
+and eax, 0x00200000 ; checks to see if the bit was inverted
+jz .print_cpuid_error
+;now we detect if we support long slong (aka 64 bit)
+
+;https://www.amd.com/system/files/TechDocs/25481.pdf page 21
+;So apperently some dumbass engineers thought it would be funny to sell CPUs that have the long mode bit set without it being supported, dispite including it in their own documentation.
+;there's a work around by checking other bits, and it's a low priority TODO. However, I really think us coming accross this will be extremely rare.
+mov eax, 0x80000001
+cpuid ;cpuid returns into edx
+and edx, 0x0020000000 ; the 21st bit is cpuid.
+jz .print_long_error
+
+mov eax, 0x00000001
+cpuid
+and edx, 0x00000200
+jz .print_apic_error
+
+
+mov bx, .no_error
+mov cx, 0
+call bios_print
+
+
+;mapping memory
+mov ax, 0
+mov es, ax
+mov ax, _meminfo_loc
+mov di, ax
+
+mov eax, 0xe820
+mov ebx, 0
+mov ecx, 24
+mov edx, 0x534d4150
+int 0x15
+
+jc .print_mem_error
+cmp eax, 0x534D4150
+jne .print_mem_error
+
+.mem_detect_loop:
+add di, 24
+mov [di + 20], dword 1
+mov eax, 0xe820
+mov ecx, 24
+
+int 0x15
+jc .mem_detected
+cmp ebx, 0
+je .mem_detected
+jmp .mem_detect_loop
+.mem_detected:
+
+ret
+
+
+.print_cpuid_error:
+mov bx, .cpuid_error
+mov cx, 0
+call bios_print
+jmp $
+
+.print_long_error:
+mov bx, .arch_error ; lets just test for now
+mov cx, 0
+call bios_print
+jmp $
+
+.print_apic_error:
+mov bx, .apic_error
+mov cx, 0
+call bios_print
+
+.print_mem_error:
+mov bx, .mem_error
+mov cx, 0
+call bios_print
+
+
+.cpuid_error:
+ db "No CPUID capabilitity", 0x0
+.arch_error:
+ db "This operating system was compiled to run in 64 bit mode!", 0x0
+.apic_error:
+ db "No apic support", 0x0
+.mem_error:
+ db "Could not get information on memory!", 0x0
+.no_error:
+ db "CPU info gathered!", 0x0
+
diff --git a/src/bootloader/enter_kernel.asm b/src/bootloader/enter_kernel.asm
new file mode 100644
index 0000000..c9991e3
--- /dev/null
+++ b/src/bootloader/enter_kernel.asm
@@ -0,0 +1,80 @@
+[extern main]
+[extern _kernel_stack_loc]
+enter_longmode:
+cli
+
+; TODO check if a20 is already set
+mov al, 0x92
+or al, 2
+out 0x92, al
+
+lgdt [protected_gdt.descriptor]
+mov eax, cr0
+or eax, 0x1
+mov cr0, eax
+
+mov eax, 0x8
+mov ds, eax
+
+jmp 0x8:init_longmode
+
+bits 32
+init_longmode:
+mov ebp, 0xffff
+mov esp, ebp
+mov ax, PROTECTED_DATA_SEGMENT
+mov ds, ax
+mov ss, ax
+mov es, ax
+mov fs, ax
+mov gs, ax
+
+mov edi, 0x4000 ; 0x3000
+mov cr3, edi
+mov eax, 0
+mov ecx, 0xc00 ; 0x1000
+rep stosd
+mov edi, cr3
+
+
+mov DWORD [edi], 0x5003 ; pml4e[0] = pdpe
+add edi, 0x1000
+mov DWORD [edi], 0x6003 ; pdpe[0] = pde
+add edi, 0x1000
+mov DWORD [edi], 0x83 ; pde[0] = pte
+
+mov eax, cr4
+or eax, 1 << 5
+mov cr4, eax
+
+;end of setting up pages
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8
+wrmsr
+
+mov eax, cr0
+or eax, 1 << 31 | 1 << 0 ; this is where we set paging and protected mode (respectively)!
+mov cr0, eax
+
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8
+wrmsr
+
+mov eax, cr0
+or eax, 1 << 31
+mov cr0, eax
+
+lgdt [long_gdt.descriptor]
+
+jmp LONG_CODE_SEGMENT:enter_kernel
+enter_kernel:
+bits 64
+mov rbp, _kernel_stack_loc
+mov rsp, _kernel_stack_loc
+call main ; where we actually call the kernel
+jmp $
+ret
diff --git a/src/bootloader/enter_kernel_backup b/src/bootloader/enter_kernel_backup
new file mode 100644
index 0000000..7631f20
--- /dev/null
+++ b/src/bootloader/enter_kernel_backup
@@ -0,0 +1,87 @@
+[extern main]
+[extern _kernel_stack_loc]
+enter_longmode:
+cli
+
+; TODO check if a20 is already set
+mov al, 0x92
+or al, 2
+out 0x92, al
+
+lgdt [protected_gdt.descriptor]
+mov eax, cr0
+or eax, 0x1
+mov cr0, eax
+
+mov eax, 0x8
+mov ds, eax
+
+jmp 0x8:init_longmode
+
+bits 32
+init_longmode:
+mov ebp, 0xffff
+mov esp, ebp
+mov ax, PROTECTED_DATA_SEGMENT
+mov ds, ax
+mov ss, ax
+mov es, ax
+mov fs, ax
+mov gs, ax
+
+mov edi, 0x3000 ; this is where our page tables will be
+mov cr3, edi
+mov eax, 0 ; what we'll be putting there
+mov ecx, 4096 ; how many times we'll put it there
+rep stosd ; kinda like memset(&edi, ecx, edi)
+mov edi, cr3
+
+mov DWORD [edi], 0x4003 ; pml4e[0] = pdpe
+add edi, 0x1000
+mov DWORD [edi], 0x5003 ; pdpe[0] = pde
+add edi, 0x1000
+mov DWORD [edi], 0x6003 ; pde[0] = pte
+add edi, 0x1000
+
+mov ebx, 0x00000003 ; the flags
+mov ecx, 512; the loop counter, will map 2 mib
+
+.idmap_pte_loop:
+mov DWORD [edi], ebx
+add ebx, 0x1000 ; physical address. Should leave us at 0x7000
+add edi, 8 ; position in page table
+loop .idmap_pte_loop
+
+mov eax, cr4
+or eax, 1 << 5
+mov cr4, eax
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8
+wrmsr
+
+mov eax, cr0
+or eax, 1 << 31 | 1 << 0 ; this is where we set paging and protected mode (respectively)!
+mov cr0, eax
+
+
+mov ecx, 0xc0000080
+rdmsr
+or eax, 1 << 8
+wrmsr
+
+mov eax, cr0
+or eax, 1 << 31
+mov cr0, eax
+
+lgdt [long_gdt.descriptor]
+
+jmp LONG_CODE_SEGMENT:enter_kernel
+enter_kernel:
+bits 64
+mov rbp, _kernel_stack_loc
+mov rsp, _kernel_stack_loc
+call main ; where we actually call the kernel
+jmp $
+ret
diff --git a/src/bootloader/gdt.asm b/src/bootloader/gdt.asm
new file mode 100644
index 0000000..d506cdf
--- /dev/null
+++ b/src/bootloader/gdt.asm
@@ -0,0 +1,70 @@
+protected_gdt:
+.gdt_start: ; we need to start with a null gdt
+dd 0
+dd 0
+
+.gdt_code:
+dw 0xffff
+dw 0x0000
+db 0x00
+db 10011010b
+db 11001111b
+db 0x0000
+
+
+.gdt_data:
+dw 0xffff
+dw 0x0000
+db 0x00
+db 10010010b
+db 11001111b
+db 0x0000
+
+.gdt_end:
+
+.descriptor:
+ dw .gdt_end - .gdt_start - 1
+dq .gdt_start
+
+PROTECTED_CODE_SEGMENT equ .gdt_code - .gdt_start
+PROTECTED_DATA_SEGMENT equ .gdt_data - .gdt_start
+
+
+long_gdt:
+.gdt_start:
+;and now we set up a temporary GDT creating a 1:1 mapping
+dw 0xffff
+dw 0
+db 0 ;this is the invalid GDT
+db 0
+db 1
+db 0
+
+;now for the code GDT:
+.gdt_code:
+dw 0 ; segment limit 15:00 (I don't think this matters in 64 bit mode!)
+dw 0 ; base address 15:00
+db 0 ; base address 23:16
+db 10011010b ;1st flags and type. The first four bits (1010) are type, and the last are flags. See https://www.cs.bham.ac.uk/~exr/lectures/opsys/10_11/lectures/os-dev.pdf
+db 10101111b ;1111 is segment limit continued. 0: available, 0: 64 bit (change?), 1: 32 bit segment, 1: granularity (shifts 3 hex didgets to get all of memory)
+db 0
+
+; the data GDT is the exact same, and it overlaps. We don't care, we'll be booting into long mode right after then programming in C
+; TODO: clarify once you figure out what you're doing
+.gdt_data:
+dw 0
+dw 0
+db 0
+db 10010010b
+db 00000000b
+db 0
+
+.gdt_end: ; later calculates offset in defs below
+
+
+.descriptor:
+ dw .gdt_end - .gdt_start - 1
+dq .gdt_start
+
+LONG_CODE_SEGMENT equ .gdt_code - .gdt_start
+LONG_DATA_SEGMENT equ .gdt_data - .gdt_start
diff --git a/src/bootloader/multicore.asm b/src/bootloader/multicore.asm
new file mode 100644
index 0000000..fa33ea5
--- /dev/null
+++ b/src/bootloader/multicore.asm
@@ -0,0 +1,10 @@
+multicore_boot:
+jmp $
+
+mov ecx, 0x0000001b
+rdmsr
+;mov [apic_register] dx:ax
+
+apic_register: dq 0
+multicore_msg1: db "CPUs available: ", 0
+
diff --git a/src/bootloader/notes b/src/bootloader/notes
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/bootloader/notes
diff --git a/src/bootloader/video.asm b/src/bootloader/video.asm
new file mode 100644
index 0000000..5b292c2
--- /dev/null
+++ b/src/bootloader/video.asm
@@ -0,0 +1,179 @@
+[extern _vbe_infoblock]
+vbe_init:
+.init_video:
+;getting edid
+
+mov ax, 0
+mov es, ax
+mov di, 0x500
+
+mov ax, 0x4f15
+mov bx, 0x1
+mov cx, 0
+mov dx, 0
+
+int 0x10
+
+cmp al, 0x4f
+jne .vbe_unsupported
+cmp ah, 0x00
+jne .edid_error
+
+
+mov ah, [0x500+58]
+shr ah, 4
+mov al, [0x500+56]
+push ax
+
+mov ah, [0x500+61]
+shr ah, 4
+mov al, [0x500+59]
+push ax
+
+mov al, BYTE [0x500+20]
+test al, 0x80
+jz .res_unsupported ; uses an analog signal
+
+shr al, 4
+and al, 7
+
+.cdp_6:
+cmp al, 0b001
+jne .cdp_8
+mov ax, 18
+jmp .colordepth_found
+
+.cdp_8:
+cmp al, 0b010
+jne .cdp_10
+mov ax, 24
+jmp .colordepth_found
+
+.cdp_10:
+cmp al, 0b011
+jne .cdp_12
+mov ax, 30
+jmp .colordepth_found
+
+.cdp_12:
+cmp al, 0b100
+jne .cdp_14
+mov ax, 36
+jmp .colordepth_found
+
+.cdp_14:
+cmp al, 0b101
+jne .cdp_16
+mov ax, 42
+jmp .colordepth_found
+
+.cdp_16:
+cmp al, 0b110
+jne .cdp_undefined
+mov ax, 48
+jmp .colordepth_found
+
+.cdp_undefined:
+mov ax, 24
+; TODO print warning, this only happens when we can't find bitdepth
+
+.colordepth_found:
+push ax
+
+
+
+
+; _______________________________________________________________________________________________________
+
+; When we get things sorted out, some time you should come back here and find a good resolution that isn't
+; native as a fallback.
+; Maybe redo this part in C?
+
+;getting available modes
+mov ax, 0
+mov es, ax
+mov ax, 0x500
+mov di, ax
+
+;get vbe capabilities
+mov ax, 0x4f00
+int 0x10
+cmp ax, 0x4f
+jne .vbe_generic_error
+cmp DWORD [0x500], "VESA"
+jne .vbe_generic_error
+
+; now we loop through the modes
+mov ebx, [0x500+14] ; pointer to modes
+mov di, 0x600
+mov ax, 0
+mov es, ax
+.mode_loop:
+mov ax, 0x4f01
+mov cx, [ebx]
+cmp cx, 0xffff
+je .res_unsupported
+
+int 0x10
+
+mov ax, [esp]
+cmp al, BYTE [0x600+25] ; might be wrong
+jne .mode_loop_next
+
+; width (1920)
+mov ax, [esp+4]
+cmp ax, [0x600+18]
+jne .mode_loop_next
+
+; height
+mov ax, [esp+2]
+cmp ax, [0x600+20]
+jne .mode_loop_next
+
+
+
+jmp .mode_found
+
+.mode_loop_next:
+add ebx, 2
+jmp .mode_loop
+
+.mode_found:
+mov ax, 0x4f02
+mov bx, cx
+int 0x10
+;getting rid of stack
+pop ax
+pop ax
+pop ax
+ret
+; ________________________________________________________________________________________________________
+
+.vbe_unsupported:
+mov bx, .unsupported_msg
+mov cx, 0
+call bios_print
+jmp $
+
+.vbe_generic_error:
+mov bx, .lazyerror_msg
+mov cx, 0
+call bios_print
+jmp $
+
+.edid_error:
+mov bx, .ediderror_msg
+mov cx, 0
+call bios_print
+jmp $
+
+.res_unsupported:
+mov bx, .res_unsupported_msg
+mov cx, 0
+call bios_print
+jmp $
+
+.unsupported_msg: db "Your BIOS doesn't support VESA. It's probably time to get a new computer!", 0
+.lazyerror_msg: db "A VESA error has occured.", 0
+.ediderror_msg: db "EDID error", 0
+.res_unsupported_msg: db "Native resolution not supported!", 0
diff --git a/src/debug/.gdb_history b/src/debug/.gdb_history
new file mode 100644
index 0000000..e513052
--- /dev/null
+++ b/src/debug/.gdb_history
@@ -0,0 +1,4 @@
+quit
+quit
+c
+quit
diff --git a/src/indigo_os b/src/indigo_os
new file mode 100755
index 0000000..b1d65ea
--- /dev/null
+++ b/src/indigo_os
Binary files differ
diff --git a/src/kernel/include/acpi.h b/src/kernel/include/acpi.h
new file mode 100644
index 0000000..c15e044
--- /dev/null
+++ b/src/kernel/include/acpi.h
@@ -0,0 +1,39 @@
+#include <stdint.h>
+#include <libc.h>
+
+struct rsdp_v1 {
+ char sig[8];
+ uint8_t checksum;
+ char OEMID[6];
+ uint8_t version;
+ uint32_t rsdt_addr;
+
+} __attribute__((packed));
+
+struct rsdp_v2 {
+ struct rsdp_v1 v1;
+ uint32_t len;
+ uint64_t xsdt_addr;
+ uint8_t extended_checksum;
+ uint8_t reserved[3];
+} __attribute__((packed));
+
+
+typedef union rsdp_t {
+ struct rsdp_v1 v1;
+ struct rsdp_v2 v2;
+} rsdp_t;
+
+struct acpi_header {
+ char sig[4];
+ uint32_t length;
+ uint8_t revision;
+ uint8_t checksum;
+ char OEMID[6];
+ char OEMTableID[8];
+ uint32_t OEMRevision;
+ uint32_t creator_id;
+ uint32_t creator_revision;
+} __attribute__((packed));
+
+rsdp_t *find_RSDP();
diff --git a/src/kernel/include/libc.h b/src/kernel/include/libc.h
new file mode 100644
index 0000000..7e837ae
--- /dev/null
+++ b/src/kernel/include/libc.h
@@ -0,0 +1,10 @@
+#ifndef _STRING_H_
+#define _STRING_H_
+#include <stddef.h>
+
+int strcmp(const char *str1, const char *str2);
+int strncmp(const char *str1, const char *str2, size_t n);
+void strcpy(char *dest, char *src);
+void memcpy(void *dest, void *src, size_t n); //TODO
+int memcmp(const void *s1, const void *s2, size_t n);
+#endif
diff --git a/src/kernel/include/paging.h b/src/kernel/include/paging.h
new file mode 100644
index 0000000..3b89af9
--- /dev/null
+++ b/src/kernel/include/paging.h
@@ -0,0 +1,60 @@
+#include <stdbool.h>
+//paging errors
+#define PAGEMAP_LOCATION 0x4000
+#ifndef _PAGE_H_
+#define _PAGE_H_
+#include <stdint.h>
+
+#define PAGE_VIRT_UNALIGNED 0x01
+#define PAGE_PHYS_UNALIGNED 0x02
+#define PAGE_PHYS_INVALID 0x03
+#define PAGE_VIRT_INVALID 0x04
+
+//*
+typedef struct __attribute__((packed)) {
+ unsigned int present : 1; // present, must be one when accessed.
+ unsigned int read_write : 1; // if set to one, read and write is set
+ unsigned int user : 1; // another bit we'll never use, for seperating CPL 0-2 and 3+
+ unsigned int writethrough_cache : 1; // honestly maybe I should look into caching
+ unsigned int cachable : 1; // hardware chaching. 0 is enabled, whats the worst that could happen?
+ unsigned int accessed : 1; // we'll never use any of these!
+ unsigned int zg0 : 1; // needs to be (and will be) zero'd
+ unsigned int size : 1;
+ unsigned int zg1 : 1; // needs to be (and will be) zero'd
+ unsigned int software_marks : 3; // available for our own use, I doubt we'll use it in such a simple thing
+
+ uintptr_t base_ptr : 40;
+ unsigned int available:11;
+} page_entry;
+
+
+typedef struct __attribute__((packed)) {
+ page_entry pml4e[512];
+ page_entry pdpe[512];
+ page_entry pde[512];
+ page_entry pte[512];
+} page_table;
+
+#define MEM_AVAILABLE 0
+#define MEM_RESERVED 1
+#define MEM_APCI_RECLAIMABLE 2
+#define MEM_APCI_NVS 3
+#define MEM_BAD 4
+
+#define PAGE_SIZE_4K 12
+#define PAGE_SIZE_2M 21
+#define PAGE_SIZE_1G 30
+
+struct memory_table {
+ uint64_t base;
+ uint64_t length;
+ uint32_t type;
+ uint32_t ACPI; //we'll never use this
+} __attribute__((packed));
+
+
+extern void* _meminfo_loc;
+
+bool map_page(uintptr_t virtual_addr, uintptr_t physical_addr, uint8_t PAGE_SIZE);
+void debug_print_memory();
+#endif
diff --git a/src/kernel/include/printf.h b/src/kernel/include/printf.h
new file mode 100644
index 0000000..6104ccf
--- /dev/null
+++ b/src/kernel/include/printf.h
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+// 2014-2019, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// 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 THE
+// AUTHORS OR COPYRIGHT HOLDERS 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.
+//
+// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
+// embedded systems with a very limited resources.
+// Use this instead of bloated standard/newlib printf.
+// These routines are thread safe and reentrant.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _PRINTF_H_
+#define _PRINTF_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Output a character to a custom device like UART, used by the printf() function
+ * This function is declared here only. You have to write your custom implementation somewhere
+ * \param character Character to output
+ */
+void _putchar(char character);
+
+
+/**
+ * Tiny printf implementation
+ * You have to implement _putchar if you use printf()
+ * To avoid conflicts with the regular printf() API it is overridden by macro defines
+ * and internal underscore-appended functions like printf_() are used
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are written into the array, not counting the terminating null character
+ */
+#define printf printf_
+int printf_(const char* format, ...);
+
+
+/**
+ * Tiny sprintf implementation
+ * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
+ * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
+ */
+#define sprintf sprintf_
+int sprintf_(char* buffer, const char* format, ...);
+
+
+/**
+ * Tiny snprintf/vsnprintf implementation
+ * \param buffer A pointer to the buffer where to store the formatted string
+ * \param count The maximum number of characters to store in the buffer, including a terminating null character
+ * \param format A string that specifies the format of the output
+ * \param va A value identifying a variable arguments list
+ * \return The number of characters that COULD have been written into the buffer, not counting the terminating
+ * null character. A value equal or larger than count indicates truncation. Only when the returned value
+ * is non-negative and less than count, the string has been completely written.
+ */
+#define snprintf snprintf_
+#define vsnprintf vsnprintf_
+int snprintf_(char* buffer, size_t count, const char* format, ...);
+int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
+
+
+/**
+ * Tiny vprintf implementation
+ * \param format A string that specifies the format of the output
+ * \param va A value identifying a variable arguments list
+ * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
+ */
+#define vprintf vprintf_
+int vprintf_(const char* format, va_list va);
+
+
+/**
+ * printf with output function
+ * You may use this as dynamic alternative to printf() with its fixed _putchar() output
+ * \param out An output function which takes one character and an argument pointer
+ * \param arg An argument pointer for user data passed to output function
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are sent to the output function, not counting the terminating null character
+ */
+int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _PRINTF_H_
diff --git a/src/kernel/include/serial.h b/src/kernel/include/serial.h
new file mode 100644
index 0000000..824e245
--- /dev/null
+++ b/src/kernel/include/serial.h
@@ -0,0 +1,16 @@
+//these com values are just guesses! Figure out how to find em later if you want
+#ifndef _SERIAL_H_
+#define _SERIAL_H_
+
+#include <stdint.h>
+#define COM1 0x3f8
+#define COM2 0x2f8
+#define COM3 0x3e8
+#define COM4 0x2e8
+
+
+int init_serial(uint16_t port);
+void serial_out(uint16_t port, char *string);
+void _putchar_serial(uint16_t port, char character);
+
+#endif
diff --git a/src/kernel/include/video.h b/src/kernel/include/video.h
new file mode 100644
index 0000000..6f702b1
--- /dev/null
+++ b/src/kernel/include/video.h
@@ -0,0 +1,49 @@
+#include <stdint.h>
+void dump_video();
+
+//this struct was stolen from wiki.osdev.org
+struct mode_info {
+ uint16_t attributes;
+ uint8_t window_a;
+ uint8_t window_b;
+ uint16_t granularity;
+ uint16_t window_size;
+ uint16_t segment_a;
+ uint16_t segment_b;
+ uint32_t win_func_ptr;
+ uint16_t pitch;
+ uint16_t width;
+ uint16_t height;
+ uint8_t w_char;
+ uint8_t y_char;
+ uint8_t planes;
+ uint8_t bpp;
+ uint8_t banks;
+ uint8_t memory_model;
+ uint8_t bank_size;
+ uint8_t image_pages;
+ uint8_t reserved0;
+ uint8_t red_mask;
+ uint8_t red_position;
+ uint8_t green_mask;
+ uint8_t green_position;
+ uint8_t blue_mask;
+ uint8_t blue_position;
+ uint8_t reserved_mask;
+ uint8_t reserved_position;
+ uint8_t direct_color_attributes;
+
+ uint32_t framebuffer;
+ uint32_t off_screen_mem_off;
+ uint16_t off_screen_mem_size;
+ uint8_t reserved1[206];
+} __attribute__((packed));
+
+struct vbe_infoblock {
+ char vbe_signature[4];
+ uint16_t vbe_version;
+ uint16_t oem_ptr[2];
+ uint8_t capabilities[4];
+ uint32_t videomodeptr;
+ uint16_t total_memory;
+} __attribute__((packed));
diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c
new file mode 100644
index 0000000..8db2e50
--- /dev/null
+++ b/src/kernel/kernel.c
@@ -0,0 +1,42 @@
+#include <stdbool.h>
+#include <serial.h>
+#include <printf.h>
+#include <paging.h>
+#include <video.h>
+#include <acpi.h>
+
+void panic() { // will fill with debugging info latter
+ printf("Kernel panic!\n");
+ for(;;);
+}
+
+
+void main() {
+ if(!(init_serial(COM1))) {
+ printf("\nKernal started on CPU 1!\n"); // will detect cpu later
+ }
+
+ rsdp_t *rsdp;
+ struct memory_table *table = (struct memory_table *)&_meminfo_loc;
+ struct vbe_infoblock *vbe_info = (struct vbe_infoblock *)0x500;
+ debug_print_memory();
+
+ rsdp = find_RSDP();
+ if(!(rsdp)) {
+ printf("Couldn't find the RSDP... uhh, not sure what to do now.\n");
+ panic();
+ }
+ dump_video();
+
+ if(rsdp->v1.version) {
+ map_page(0x200000, (rsdp->v2.xsdt_addr / 0x1000) * 0x1000, PAGE_SIZE_4K);
+ }
+ else {
+ map_page(0x200000, (rsdp->v1.rsdt_addr / 0x1000) * 0x1000, PAGE_SIZE_4K);
+ struct acpi_header *acpi = (struct acpi_header *)((uint64_t)0x200000 + (rsdp->v1.rsdt_addr % 0x1000));
+ }
+
+ printf("kernel is done, you can ignore this panic\n");
+ panic();
+
+}
diff --git a/src/kernel/libs/acpi.c b/src/kernel/libs/acpi.c
new file mode 100644
index 0000000..8bc6a56
--- /dev/null
+++ b/src/kernel/libs/acpi.c
@@ -0,0 +1,61 @@
+#include <acpi.h>
+#include <stdint.h>
+#include <printf.h>
+
+static int RSDP_verify(void *rsdp_pointer) {
+ printf("Verifying potential RSDP at address 0x%p... ", rsdp_pointer);
+ union rsdp_t *rsdp = rsdp_pointer;
+ uint8_t checksum = 0;
+ char *rsdp_csm_ptr = rsdp_pointer;
+ int i;
+ if(checksum) return 0;
+ if(rsdp->v1.version) {
+ printf("APCI revision > 2.\n");
+ checksum = 0;
+ printf("len : %i\n", rsdp->v2.len);
+ for(i = 0; i < rsdp->v2.len; i++) {
+ checksum += rsdp_csm_ptr[i];
+ }
+ }
+ else {
+ printf("APCI revision 1.\n");
+ for(i = 0; i <= 20; i++) {
+ checksum += rsdp_csm_ptr[i];
+ }
+ }
+ if(checksum) {
+ return 0;
+ printf("Invalid, searching on.\n");
+ }
+ printf("RSDP Verified!\n");
+ return 1;
+}
+
+// TODO: move these when you gain your sanity
+rsdp_t *find_RSDP() { // finds root descriptor
+ const char sig[9] = "RSD PTR ";
+ uintptr_t *p = (void *)0x040e;
+ uintptr_t *ebda_unshifted = (void *)p;
+
+ // TODO you REALLY need to verify this.
+ void *ebda = (void *)((uintptr_t)ebda_unshifted << (uintptr_t)4 & (uintptr_t)0xfffff);
+
+
+ for(void *i = ebda; i <= ebda + 64000; i += 16) {
+ if(!(memcmp(sig, i, 8))) {
+ if(RSDP_verify(i)) {
+ return(i);
+ }
+ }
+ }
+
+ for(void *i = (void *)0xe0000; i <= (void *)0xfffff; i += 16) {
+ if(!(memcmp(sig, i, 8))) {
+ if(RSDP_verify(i)) {
+ return(i);
+ }
+ }
+ }
+}
+
+
diff --git a/src/kernel/libs/drivers/serial.c b/src/kernel/libs/drivers/serial.c
new file mode 100644
index 0000000..665f06c
--- /dev/null
+++ b/src/kernel/libs/drivers/serial.c
@@ -0,0 +1,43 @@
+#include <stdint.h>
+#include <serial.h>
+//you can add more options if you need to later
+// PORT + 3: values are from bit zero (right) to left
+// dlab(1) | misteryyy bone(1) | paraty(3) | stop bits (1) | character length (2)
+static inline void outb(uint16_t port, uint8_t value) {
+ //here "a" is the a register, and "Nd" is inteter (I think?) in the d register
+ asm volatile(
+ "outb %0, %1" :: "a"(value), "Nd"(port)
+ );
+}
+
+static inline uint8_t inb(uint16_t port) {
+ uint8_t ret;
+ asm volatile(
+ "inb %1, %0" : "=a"(ret) : "Nd"(port)
+ );
+ return(ret);
+}
+
+int init_serial(uint16_t port) {
+ outb(port + 1, 0x00); // disable them fuckin interupts
+ outb(port + 3, 0x80); // sets dlab, allowing custom serial speeds
+ outb(port + 0, 0x06); // speed is 115200/6
+ outb(port + 1, 0x00);
+ outb(port + 3, 0x03); // disables dlab, as well as 8 bit char len, 1 stop bit, no paraty, no mystery
+ outb(port + 2, 0xc7); // I have no fucking clue what this means
+ outb(port + 4, 0x0b); // don't know what this means eather... delete if you can
+ outb(port + 4, 0x1e); // loopback mode (where the hell is this documented????)
+
+ outb(port + 0, 0xae); // test char
+
+ if(inb(port + 0) != 0xae)
+ return 1;
+
+ outb(port + 4, 0x0f); // dissable interupts
+ return 0;
+}
+
+void _putchar_serial(uint16_t port, char msg) {
+ while(!(inb(port + 5) & 0x20)); //wait for transmit to be doneroni
+ outb(port, msg);
+}
diff --git a/src/kernel/libs/drivers/video.c b/src/kernel/libs/drivers/video.c
new file mode 100644
index 0000000..9bb4187
--- /dev/null
+++ b/src/kernel/libs/drivers/video.c
@@ -0,0 +1,6 @@
+#include <printf.h>
+#include <video.h>
+void dump_video() {
+ struct mode_info *video = (struct mode_info *)0x600;
+ printf("Video info:\nx:\t%u\ny:\t%u\nbbp:\t%u\nloc:\t0x%p\n", video->width, video->height, video->bpp, video->framebuffer);
+}
diff --git a/src/kernel/libs/libc.c b/src/kernel/libs/libc.c
new file mode 100644
index 0000000..31580ff
--- /dev/null
+++ b/src/kernel/libs/libc.c
@@ -0,0 +1,47 @@
+#include <stddef.h>
+#include <stdint.h>
+//#include <printf.h>
+// you need to sort all these into diffrent files! TODO
+int strncmp(const char *s1, const char *s2, unsigned int n) {
+ int i;
+ for(i = 0; ((i <= n) && (s1[i] != '\0') && (s2[i] != '\0')); i++) {
+ if(s1[i] != s2[i]) {
+ return(s1[i] - s2[i]);
+ }
+ }
+ return(s1[i] - s2[i]);
+}
+
+int strcmp(const char *s1, const char *s2) {
+ int i;
+ for(i = 0; ((s1[i] != '\0') && (s2[i] != '\0')); i++) {
+ if(s1[i] != s2[i]) {
+ return(s1[i] - s2[i]);
+ }
+ }
+ return(s1[i] - s2[i]);
+}
+
+int memcmp(const void *s1, const void *s2, size_t n) {
+ const unsigned char *p1 = s1; // Why is c such a bitch?
+ const unsigned char *p2 = s2;
+ int i;
+ for(i = 0; i < n; i++) {
+ if(p1[i] != p2[i]) {
+ return(p1[i] - p2[i]);
+ }
+ }
+ return(p1[n-1] - p2[n-1]);
+}
+
+void strcpy(char *dest, char *src) {
+ for(unsigned int i = 0; src[i] != '\0'; i++){
+ dest[i] = src[i];
+ }
+}
+
+void memcpy(char *dest, char *src, size_t n) {
+ for(unsigned int i = 0; i <= n; i++) {
+ dest[i] = src[i];
+ }
+}
diff --git a/src/kernel/libs/page.c b/src/kernel/libs/page.c
new file mode 100644
index 0000000..88d0c2f
--- /dev/null
+++ b/src/kernel/libs/page.c
@@ -0,0 +1,107 @@
+#include <printf.h>
+#include <paging.h>
+#include <stdint.h>
+
+// for now, this will always remain the same.
+// If this ever isn't the case, we'll add paramaters to the paging functions.
+// We will also never need to mess with many bits,
+// as we are not implimenting security for a bare metal fractal generator.
+// Also, is this really the cleanest way to do things?
+
+//after we get paging working, we can probably remove these structs and replace them with plain old uint_16ts.
+
+void debug_print_memory() {
+ struct memory_table *memtable = (struct memory_table *)&_meminfo_loc;
+ printf(" __________________________________________________________________________\n");
+ printf("| type\tstart\t\t\tend\t\t\tsize\t\t |\n");
+ printf("|--------------------------------------------------------------------------|\n");
+ for(unsigned int i = 0; memtable[i].length > 0; i++) {
+ printf("| %u %u\t0x%p\t0x%p\t0x%p |\n", memtable[i].type, memtable[i].ACPI, memtable[i].base, (memtable[i].base + memtable[i].length), memtable[i].length);
+ }
+ printf("----------------------------------------------------------------------------\n");
+}
+
+
+/**
+ * You can critisise the quality of this function all you want, it's messy due to planning mistakes
+ * and I'm planning on sanatising it.
+ * BUT, don't critisise it _just_ for using goto, that's bullshit. See the following links.
+ *
+ * https://www.kernel.org/doc/html/v4.17/process/coding-style.html "goto" section
+ * https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/
+**/
+
+bool map_page(uintptr_t virtual_addr, uintptr_t physical_addr, uint8_t size) {
+ printf("map page called\n");
+ if((virtual_addr % (1 << size)) || (physical_addr % (1 << size))) {
+ return 0;
+ }
+ page_table *table = (page_table *)PAGEMAP_LOCATION;
+ int pte_i = (virtual_addr >> 12) & 0x1ff;
+ int pde_i = (virtual_addr >> 21) & 0x1ff;
+ int pdpe_i = (virtual_addr >> 30) & 0x1ff;
+ int pml4e_i = (virtual_addr >> 39) & 0x1ff;
+ //TODO remove this debugging info
+ printf("Virtual offsets:\npte:\t\t%i\npde:\t\t%i\npdpe:\t\t%i\npml4e\t\t%i\n", pte_i, pde_i, pdpe_i, pml4e_i);
+
+ if(table->pml4e[pml4e_i].present) {
+ if(table->pml4e[pml4e_i].base_ptr != (uintptr_t)&table->pdpe[pdpe_i] >> 12) goto error;
+ if(table->pdpe[pdpe_i].present) {
+ if(size == PAGE_SIZE_1G) {
+ if(table->pdpe[pdpe_i].base_ptr == (uintptr_t)physical_addr >> 30 & 0x1ff)
+ return true;
+ goto error;
+ }
+ if(table->pdpe[pdpe_i].base_ptr != (uintptr_t)&table->pde[pde_i] >> 12) goto error;
+
+ if(table->pde[pde_i].present) {
+ if(size == PAGE_SIZE_2M) {
+ if(table->pde[pde_i].base_ptr == (uintptr_t)physical_addr >> 21 & 0x1ff)
+ return true;
+ goto error;
+ }
+ if(table->pde[pde_i].base_ptr != (uintptr_t)&table->pte[pte_i] >> 12) goto error;
+ if(table->pte[pte_i].present) {
+ if(table->pte[pte_i].base_ptr != ((physical_addr >> 12) & 0x1ff)) goto error;
+ return true;
+ }
+ else goto mod_page_pte;
+ }
+ else goto mod_page_pde;
+ }
+ else goto mod_page_pdpe;
+ }
+ else {
+ table->pml4e[pml4e_i].base_ptr = (uintptr_t)&table->pdpe[pdpe_i] >> 12;
+ table->pdpe[pml4e_i].read_write = 1;
+ table->pml4e[pml4e_i].present = 1;
+mod_page_pdpe:
+ table->pdpe[pdpe_i].read_write = 1;
+ if(size == PAGE_SIZE_1G) {
+ table->pdpe[pdpe_i].size = 1;
+ table->pdpe[pdpe_i].base_ptr = physical_addr >> 30;
+ table->pdpe[pdpe_i].present = 1;
+ return true;
+ }
+ table->pdpe[pdpe_i].base_ptr = (uintptr_t)&table->pde[pde_i] >> 12;
+ table->pdpe[pdpe_i].present = 1;
+mod_page_pde:
+ table->pde[pde_i].read_write = 1;
+ if(size == PAGE_SIZE_2M) {
+ table->pde[pde_i].size = 1;
+ table->pde[pde_i].base_ptr = physical_addr >> 21;
+ table->pde[pde_i].present = 1;
+ return true;
+ }
+ table->pde[pde_i].base_ptr = (uintptr_t)&table->pte[pte_i] >> 12;
+ table->pde[pde_i].present = 1;
+mod_page_pte:
+ table->pte[pte_i].base_ptr = (physical_addr >> 12);
+ table->pte[pte_i].read_write = 1;
+ table->pte[pte_i].present = 1;
+ return true;
+ }
+error:
+ printf("Page allocation error!\n");
+ return false;
+}
diff --git a/src/kernel/libs/printf.c b/src/kernel/libs/printf.c
new file mode 100644
index 0000000..14c897d
--- /dev/null
+++ b/src/kernel/libs/printf.c
@@ -0,0 +1,924 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+// 2014-2019, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// 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 THE
+// AUTHORS OR COPYRIGHT HOLDERS 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.
+//
+// \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on
+// embedded systems with a very limited resources. These routines are thread
+// safe and reentrant!
+// Use this instead of the bloated standard/newlib printf cause these use
+// malloc for printf (and may not be thread safe).
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "printf.h"
+
+//this is my own ugly library
+#include <serial.h>
+
+//and my options
+#define PRINTF_DISABLE_SUPPORT_FLOAT
+#define PRINTF_DISABLE_SUPPORT_EXPONENTIAL
+#define PRINTF_DISABLE_SUPPORT_LONG_LONG
+#define PRINTF_DISABLE_SUPPORT_PTRDIFF_T
+
+
+// define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the
+// printf_config.h header file
+// default: undefined
+#ifdef PRINTF_INCLUDE_CONFIG_H
+#include "printf_config.h"
+#endif
+
+
+// 'ntoa' conversion buffer size, this must be big enough to hold one converted
+// numeric number including padded zeros (dynamically created on stack)
+// default: 32 byte
+#ifndef PRINTF_NTOA_BUFFER_SIZE
+#define PRINTF_NTOA_BUFFER_SIZE 32U
+#endif
+
+// 'ftoa' conversion buffer size, this must be big enough to hold one converted
+// float number including padded zeros (dynamically created on stack)
+// default: 32 byte
+#ifndef PRINTF_FTOA_BUFFER_SIZE
+#define PRINTF_FTOA_BUFFER_SIZE 32U
+#endif
+
+// support for the floating point type (%f)
+// default: activated
+#ifndef PRINTF_DISABLE_SUPPORT_FLOAT
+#define PRINTF_SUPPORT_FLOAT
+#endif
+
+// support for exponential floating point notation (%e/%g)
+// default: activated
+#ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL
+#define PRINTF_SUPPORT_EXPONENTIAL
+#endif
+
+// define the default floating point precision
+// default: 6 digits
+#ifndef PRINTF_DEFAULT_FLOAT_PRECISION
+#define PRINTF_DEFAULT_FLOAT_PRECISION 6U
+#endif
+
+// define the largest float suitable to print with %f
+// default: 1e9
+#ifndef PRINTF_MAX_FLOAT
+#define PRINTF_MAX_FLOAT 1e9
+#endif
+
+// support for the long long types (%llu or %p)
+// default: activated
+#ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG
+#define PRINTF_SUPPORT_LONG_LONG
+#endif
+
+// support for the ptrdiff_t type (%t)
+// ptrdiff_t is normally defined in <stddef.h> as long or long long type
+// default: activated
+#ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T
+#define PRINTF_SUPPORT_PTRDIFF_T
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+// internal flag definitions
+#define FLAGS_ZEROPAD (1U << 0U)
+#define FLAGS_LEFT (1U << 1U)
+#define FLAGS_PLUS (1U << 2U)
+#define FLAGS_SPACE (1U << 3U)
+#define FLAGS_HASH (1U << 4U)
+#define FLAGS_UPPERCASE (1U << 5U)
+#define FLAGS_CHAR (1U << 6U)
+#define FLAGS_SHORT (1U << 7U)
+#define FLAGS_LONG (1U << 8U)
+#define FLAGS_LONG_LONG (1U << 9U)
+#define FLAGS_PRECISION (1U << 10U)
+#define FLAGS_ADAPT_EXP (1U << 11U)
+
+
+// import float.h for DBL_MAX
+#if defined(PRINTF_SUPPORT_FLOAT)
+#include <float.h>
+#endif
+
+
+// output function type
+typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
+
+
+// wrapper (used as buffer) for output function type
+typedef struct {
+ void (*fct)(char character, void* arg);
+ void* arg;
+} out_fct_wrap_type;
+
+
+// internal buffer output
+static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen)
+{
+ if (idx < maxlen) {
+ ((char*)buffer)[idx] = character;
+ }
+}
+
+
+// internal null output
+static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen)
+{
+ (void)character; (void)buffer; (void)idx; (void)maxlen;
+}
+
+
+// internal _putchar wrapper
+static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
+{
+ (void)buffer; (void)idx; (void)maxlen;
+ if (character) {
+ _putchar_serial(COM1, character); // later we should figure out a way to not specifify exclusively com1
+
+ }
+}
+
+
+// internal output function wrapper
+static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen)
+{
+ (void)idx; (void)maxlen;
+ if (character) {
+ // buffer is the output fct pointer
+ ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg);
+ }
+}
+
+
+// internal secure strlen
+// \return The length of the string (excluding the terminating 0) limited by 'maxsize'
+static inline unsigned int _strnlen_s(const char* str, size_t maxsize)
+{
+ const char* s;
+ for (s = str; *s && maxsize--; ++s);
+ return (unsigned int)(s - str);
+}
+
+
+// internal test if char is a digit (0-9)
+// \return true if char is a digit
+static inline bool _is_digit(char ch)
+{
+ return (ch >= '0') && (ch <= '9');
+}
+
+
+// internal ASCII string to unsigned int conversion
+static unsigned int _atoi(const char** str)
+{
+ unsigned int i = 0U;
+ while (_is_digit(**str)) {
+ i = i * 10U + (unsigned int)(*((*str)++) - '0');
+ }
+ return i;
+}
+
+
+// output the specified string in reverse, taking care of any zero-padding
+static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags)
+{
+ const size_t start_idx = idx;
+
+ // pad spaces up to given width
+ if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
+ for (size_t i = len; i < width; i++) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+
+ // reverse string
+ while (len) {
+ out(buf[--len], buffer, idx++, maxlen);
+ }
+
+ // append pad spaces up to given width
+ if (flags & FLAGS_LEFT) {
+ while (idx - start_idx < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+
+ return idx;
+}
+
+
+// internal itoa format
+static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ // pad leading zeros
+ if (!(flags & FLAGS_LEFT)) {
+ if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
+ width--;
+ }
+ while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ }
+
+ // handle hash
+ if (flags & FLAGS_HASH) {
+ if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) {
+ len--;
+ if (len && (base == 16U)) {
+ len--;
+ }
+ }
+ if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'x';
+ }
+ else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'X';
+ }
+ else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) {
+ buf[len++] = 'b';
+ }
+ if (len < PRINTF_NTOA_BUFFER_SIZE) {
+ buf[len++] = '0';
+ }
+ }
+
+ if (len < PRINTF_NTOA_BUFFER_SIZE) {
+ if (negative) {
+ buf[len++] = '-';
+ }
+ else if (flags & FLAGS_PLUS) {
+ buf[len++] = '+'; // ignore the space if the '+' exists
+ }
+ else if (flags & FLAGS_SPACE) {
+ buf[len++] = ' ';
+ }
+ }
+
+ return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
+}
+
+
+// internal itoa for 'long' type
+static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ char buf[PRINTF_NTOA_BUFFER_SIZE];
+ size_t len = 0U;
+
+ // no hash for 0 values
+ if (!value) {
+ flags &= ~FLAGS_HASH;
+ }
+
+ // write if precision != 0 and value is != 0
+ if (!(flags & FLAGS_PRECISION) || value) {
+ do {
+ const char digit = (char)(value % base);
+ buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
+ value /= base;
+ } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
+ }
+
+ return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
+}
+
+
+// internal itoa for 'long long' type
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ char buf[PRINTF_NTOA_BUFFER_SIZE];
+ size_t len = 0U;
+
+ // no hash for 0 values
+ if (!value) {
+ flags &= ~FLAGS_HASH;
+ }
+
+ // write if precision != 0 and value is != 0
+ if (!(flags & FLAGS_PRECISION) || value) {
+ do {
+ const char digit = (char)(value % base);
+ buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10;
+ value /= base;
+ } while (value && (len < PRINTF_NTOA_BUFFER_SIZE));
+ }
+
+ return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags);
+}
+#endif // PRINTF_SUPPORT_LONG_LONG
+
+
+#if defined(PRINTF_SUPPORT_FLOAT)
+
+#if defined(PRINTF_SUPPORT_EXPONENTIAL)
+// forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT
+static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags);
+#endif
+
+
+// internal ftoa for fixed decimal floating point
+static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ char buf[PRINTF_FTOA_BUFFER_SIZE];
+ size_t len = 0U;
+ double diff = 0.0;
+
+ // powers of 10
+ static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+
+ // test for special values
+ if (value != value)
+ return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags);
+ if (value < -DBL_MAX)
+ return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags);
+ if (value > DBL_MAX)
+ return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags);
+
+ // test for very large values
+ // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad
+ if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) {
+#if defined(PRINTF_SUPPORT_EXPONENTIAL)
+ return _etoa(out, buffer, idx, maxlen, value, prec, width, flags);
+#else
+ return 0U;
+#endif
+ }
+
+ // test for negative
+ bool negative = false;
+ if (value < 0) {
+ negative = true;
+ value = 0 - value;
+ }
+
+ // set default precision, if not set explicitly
+ if (!(flags & FLAGS_PRECISION)) {
+ prec = PRINTF_DEFAULT_FLOAT_PRECISION;
+ }
+ // limit precision to 9, cause a prec >= 10 can lead to overflow errors
+ while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) {
+ buf[len++] = '0';
+ prec--;
+ }
+
+ int whole = (int)value;
+ double tmp = (value - whole) * pow10[prec];
+ unsigned long frac = (unsigned long)tmp;
+ diff = tmp - frac;
+
+ if (diff > 0.5) {
+ ++frac;
+ // handle rollover, e.g. case 0.99 with prec 1 is 1.0
+ if (frac >= pow10[prec]) {
+ frac = 0;
+ ++whole;
+ }
+ }
+ else if (diff < 0.5) {
+ }
+ else if ((frac == 0U) || (frac & 1U)) {
+ // if halfway, round up if odd OR if last digit is 0
+ ++frac;
+ }
+
+ if (prec == 0U) {
+ diff = value - (double)whole;
+ if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) {
+ // exactly 0.5 and ODD, then round up
+ // 1.5 -> 2, but 2.5 -> 2
+ ++whole;
+ }
+ }
+ else {
+ unsigned int count = prec;
+ // now do fractional part, as an unsigned number
+ while (len < PRINTF_FTOA_BUFFER_SIZE) {
+ --count;
+ buf[len++] = (char)(48U + (frac % 10U));
+ if (!(frac /= 10U)) {
+ break;
+ }
+ }
+ // add extra 0s
+ while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) {
+ buf[len++] = '0';
+ }
+ if (len < PRINTF_FTOA_BUFFER_SIZE) {
+ // add decimal
+ buf[len++] = '.';
+ }
+ }
+
+ // do whole part, number is reversed
+ while (len < PRINTF_FTOA_BUFFER_SIZE) {
+ buf[len++] = (char)(48 + (whole % 10));
+ if (!(whole /= 10)) {
+ break;
+ }
+ }
+
+ // pad leading zeros
+ if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) {
+ if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
+ width--;
+ }
+ while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) {
+ buf[len++] = '0';
+ }
+ }
+
+ if (len < PRINTF_FTOA_BUFFER_SIZE) {
+ if (negative) {
+ buf[len++] = '-';
+ }
+ else if (flags & FLAGS_PLUS) {
+ buf[len++] = '+'; // ignore the space if the '+' exists
+ }
+ else if (flags & FLAGS_SPACE) {
+ buf[len++] = ' ';
+ }
+ }
+
+ return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags);
+}
+
+
+#if defined(PRINTF_SUPPORT_EXPONENTIAL)
+// internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse <m.jasperse@gmail.com>
+static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags)
+{
+ // check for NaN and special values
+ if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) {
+ return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags);
+ }
+
+ // determine the sign
+ const bool negative = value < 0;
+ if (negative) {
+ value = -value;
+ }
+
+ // default precision
+ if (!(flags & FLAGS_PRECISION)) {
+ prec = PRINTF_DEFAULT_FLOAT_PRECISION;
+ }
+
+ // determine the decimal exponent
+ // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c)
+ union {
+ uint64_t U;
+ double F;
+ } conv;
+
+ conv.F = value;
+ int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2
+ conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2)
+ // now approximate log10 from the log2 integer part and an expansion of ln around 1.5
+ int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168);
+ // now we want to compute 10^expval but we want to be sure it won't overflow
+ exp2 = (int)(expval * 3.321928094887362 + 0.5);
+ const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453;
+ const double z2 = z * z;
+ conv.U = (uint64_t)(exp2 + 1023) << 52U;
+ // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex
+ conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14)))));
+ // correct for rounding errors
+ if (value < conv.F) {
+ expval--;
+ conv.F /= 10;
+ }
+
+ // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters
+ unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U;
+
+ // in "%g" mode, "prec" is the number of *significant figures* not decimals
+ if (flags & FLAGS_ADAPT_EXP) {
+ // do we want to fall-back to "%f" mode?
+ if ((value >= 1e-4) && (value < 1e6)) {
+ if ((int)prec > expval) {
+ prec = (unsigned)((int)prec - expval - 1);
+ }
+ else {
+ prec = 0;
+ }
+ flags |= FLAGS_PRECISION; // make sure _ftoa respects precision
+ // no characters in exponent
+ minwidth = 0U;
+ expval = 0;
+ }
+ else {
+ // we use one sigfig for the whole part
+ if ((prec > 0) && (flags & FLAGS_PRECISION)) {
+ --prec;
+ }
+ }
+ }
+
+ // will everything fit?
+ unsigned int fwidth = width;
+ if (width > minwidth) {
+ // we didn't fall-back so subtract the characters required for the exponent
+ fwidth -= minwidth;
+ } else {
+ // not enough characters, so go back to default sizing
+ fwidth = 0U;
+ }
+ if ((flags & FLAGS_LEFT) && minwidth) {
+ // if we're padding on the right, DON'T pad the floating part
+ fwidth = 0U;
+ }
+
+ // rescale the float value
+ if (expval) {
+ value /= conv.F;
+ }
+
+ // output the floating part
+ const size_t start_idx = idx;
+ idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP);
+
+ // output the exponent part
+ if (minwidth) {
+ // output the exponential symbol
+ out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen);
+ // output the exponent value
+ idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS);
+ // might need to right-pad spaces
+ if (flags & FLAGS_LEFT) {
+ while (idx - start_idx < width) out(' ', buffer, idx++, maxlen);
+ }
+ }
+ return idx;
+}
+#endif // PRINTF_SUPPORT_EXPONENTIAL
+#endif // PRINTF_SUPPORT_FLOAT
+
+
+// internal vsnprintf
+static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
+{
+ unsigned int flags, width, precision, n;
+ size_t idx = 0U;
+
+ if (!buffer) {
+ // use null output function
+ out = _out_null;
+ }
+
+ while (*format)
+ {
+ // format specifier? %[flags][width][.precision][length]
+ if (*format != '%') {
+ // no
+ out(*format, buffer, idx++, maxlen);
+ format++;
+ continue;
+ }
+ else {
+ // yes, evaluate it
+ format++;
+ }
+
+ // evaluate flags
+ flags = 0U;
+ do {
+ switch (*format) {
+ case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break;
+ case '-': flags |= FLAGS_LEFT; format++; n = 1U; break;
+ case '+': flags |= FLAGS_PLUS; format++; n = 1U; break;
+ case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break;
+ case '#': flags |= FLAGS_HASH; format++; n = 1U; break;
+ default : n = 0U; break;
+ }
+ } while (n);
+
+ // evaluate width field
+ width = 0U;
+ if (_is_digit(*format)) {
+ width = _atoi(&format);
+ }
+ else if (*format == '*') {
+ const int w = va_arg(va, int);
+ if (w < 0) {
+ flags |= FLAGS_LEFT; // reverse padding
+ width = (unsigned int)-w;
+ }
+ else {
+ width = (unsigned int)w;
+ }
+ format++;
+ }
+
+ // evaluate precision field
+ precision = 0U;
+ if (*format == '.') {
+ flags |= FLAGS_PRECISION;
+ format++;
+ if (_is_digit(*format)) {
+ precision = _atoi(&format);
+ }
+ else if (*format == '*') {
+ const int prec = (int)va_arg(va, int);
+ precision = prec > 0 ? (unsigned int)prec : 0U;
+ format++;
+ }
+ }
+
+ // evaluate length field
+ switch (*format) {
+ case 'l' :
+ flags |= FLAGS_LONG;
+ format++;
+ if (*format == 'l') {
+ flags |= FLAGS_LONG_LONG;
+ format++;
+ }
+ break;
+ case 'h' :
+ flags |= FLAGS_SHORT;
+ format++;
+ if (*format == 'h') {
+ flags |= FLAGS_CHAR;
+ format++;
+ }
+ break;
+#if defined(PRINTF_SUPPORT_PTRDIFF_T)
+ case 't' :
+ flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+#endif
+ case 'j' :
+ flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+ case 'z' :
+ flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
+ format++;
+ break;
+ default :
+ break;
+ }
+
+ // evaluate specifier
+ switch (*format) {
+ case 'd' :
+ case 'i' :
+ case 'u' :
+ case 'x' :
+ case 'X' :
+ case 'o' :
+ case 'b' : {
+ // set the base
+ unsigned int base;
+ if (*format == 'x' || *format == 'X') {
+ base = 16U;
+ }
+ else if (*format == 'o') {
+ base = 8U;
+ }
+ else if (*format == 'b') {
+ base = 2U;
+ }
+ else {
+ base = 10U;
+ flags &= ~FLAGS_HASH; // no hash for dec format
+ }
+ // uppercase
+ if (*format == 'X') {
+ flags |= FLAGS_UPPERCASE;
+ }
+
+ // no plus or space flag for u, x, X, o, b
+ if ((*format != 'i') && (*format != 'd')) {
+ flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
+ }
+
+ // ignore '0' flag when precision is given
+ if (flags & FLAGS_PRECISION) {
+ flags &= ~FLAGS_ZEROPAD;
+ }
+
+ // convert the integer
+ if ((*format == 'i') || (*format == 'd')) {
+ // signed
+ if (flags & FLAGS_LONG_LONG) {
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+ const long long value = va_arg(va, long long);
+ idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
+#endif
+ }
+ else if (flags & FLAGS_LONG) {
+ const long value = va_arg(va, long);
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
+ }
+ else {
+ const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int);
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags);
+ }
+ }
+ else {
+ // unsigned
+ if (flags & FLAGS_LONG_LONG) {
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+ idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags);
+#endif
+ }
+ else if (flags & FLAGS_LONG) {
+ idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags);
+ }
+ else {
+ const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int);
+ idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags);
+ }
+ }
+ format++;
+ break;
+ }
+#if defined(PRINTF_SUPPORT_FLOAT)
+ case 'f' :
+ case 'F' :
+ if (*format == 'F') flags |= FLAGS_UPPERCASE;
+ idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
+ format++;
+ break;
+#if defined(PRINTF_SUPPORT_EXPONENTIAL)
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP;
+ if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE;
+ idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags);
+ format++;
+ break;
+#endif // PRINTF_SUPPORT_EXPONENTIAL
+#endif // PRINTF_SUPPORT_FLOAT
+ case 'c' : {
+ unsigned int l = 1U;
+ // pre padding
+ if (!(flags & FLAGS_LEFT)) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ // char output
+ out((char)va_arg(va, int), buffer, idx++, maxlen);
+ // post padding
+ if (flags & FLAGS_LEFT) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ format++;
+ break;
+ }
+
+ case 's' : {
+ const char* p = va_arg(va, char*);
+ unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1);
+ // pre padding
+ if (flags & FLAGS_PRECISION) {
+ l = (l < precision ? l : precision);
+ }
+ if (!(flags & FLAGS_LEFT)) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ // string output
+ while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) {
+ out(*(p++), buffer, idx++, maxlen);
+ }
+ // post padding
+ if (flags & FLAGS_LEFT) {
+ while (l++ < width) {
+ out(' ', buffer, idx++, maxlen);
+ }
+ }
+ format++;
+ break;
+ }
+
+ case 'p' : {
+ width = sizeof(void*) * 2U;
+ flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE;
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+ const bool is_ll = sizeof(uintptr_t) == sizeof(long long);
+ if (is_ll) {
+ idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags);
+ }
+ else {
+#endif
+ idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags);
+#if defined(PRINTF_SUPPORT_LONG_LONG)
+ }
+#endif
+ format++;
+ break;
+ }
+
+ case '%' :
+ out('%', buffer, idx++, maxlen);
+ format++;
+ break;
+
+ default :
+ out(*format, buffer, idx++, maxlen);
+ format++;
+ break;
+ }
+ }
+
+ // termination
+ out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
+
+ // return written chars without terminating \0
+ return (int)idx;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+int printf_(const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ char buffer[1];
+ const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
+ va_end(va);
+ return ret;
+}
+
+
+int sprintf_(char* buffer, const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va);
+ va_end(va);
+ return ret;
+}
+
+
+int snprintf_(char* buffer, size_t count, const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ const int ret = _vsnprintf(_out_buffer, buffer, count, format, va);
+ va_end(va);
+ return ret;
+}
+
+
+int vprintf_(const char* format, va_list va)
+{
+ char buffer[1];
+ return _vsnprintf(_out_char, buffer, (size_t)-1, format, va);
+}
+
+
+int vsnprintf_(char* buffer, size_t count, const char* format, va_list va)
+{
+ return _vsnprintf(_out_buffer, buffer, count, format, va);
+}
+
+
+int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...)
+{
+ va_list va;
+ va_start(va, format);
+ const out_fct_wrap_type out_fct_wrap = { out, arg };
+ const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va);
+ va_end(va);
+ return ret;
+}
diff --git a/src/kernel/libs/printf.h b/src/kernel/libs/printf.h
new file mode 100644
index 0000000..6104ccf
--- /dev/null
+++ b/src/kernel/libs/printf.h
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////////////////////////////////
+// \author (c) Marco Paland (info@paland.com)
+// 2014-2019, PALANDesign Hannover, Germany
+//
+// \license The MIT License (MIT)
+//
+// 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 THE
+// AUTHORS OR COPYRIGHT HOLDERS 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.
+//
+// \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on
+// embedded systems with a very limited resources.
+// Use this instead of bloated standard/newlib printf.
+// These routines are thread safe and reentrant.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _PRINTF_H_
+#define _PRINTF_H_
+
+#include <stdarg.h>
+#include <stddef.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * Output a character to a custom device like UART, used by the printf() function
+ * This function is declared here only. You have to write your custom implementation somewhere
+ * \param character Character to output
+ */
+void _putchar(char character);
+
+
+/**
+ * Tiny printf implementation
+ * You have to implement _putchar if you use printf()
+ * To avoid conflicts with the regular printf() API it is overridden by macro defines
+ * and internal underscore-appended functions like printf_() are used
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are written into the array, not counting the terminating null character
+ */
+#define printf printf_
+int printf_(const char* format, ...);
+
+
+/**
+ * Tiny sprintf implementation
+ * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD!
+ * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output!
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
+ */
+#define sprintf sprintf_
+int sprintf_(char* buffer, const char* format, ...);
+
+
+/**
+ * Tiny snprintf/vsnprintf implementation
+ * \param buffer A pointer to the buffer where to store the formatted string
+ * \param count The maximum number of characters to store in the buffer, including a terminating null character
+ * \param format A string that specifies the format of the output
+ * \param va A value identifying a variable arguments list
+ * \return The number of characters that COULD have been written into the buffer, not counting the terminating
+ * null character. A value equal or larger than count indicates truncation. Only when the returned value
+ * is non-negative and less than count, the string has been completely written.
+ */
+#define snprintf snprintf_
+#define vsnprintf vsnprintf_
+int snprintf_(char* buffer, size_t count, const char* format, ...);
+int vsnprintf_(char* buffer, size_t count, const char* format, va_list va);
+
+
+/**
+ * Tiny vprintf implementation
+ * \param format A string that specifies the format of the output
+ * \param va A value identifying a variable arguments list
+ * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character
+ */
+#define vprintf vprintf_
+int vprintf_(const char* format, va_list va);
+
+
+/**
+ * printf with output function
+ * You may use this as dynamic alternative to printf() with its fixed _putchar() output
+ * \param out An output function which takes one character and an argument pointer
+ * \param arg An argument pointer for user data passed to output function
+ * \param format A string that specifies the format of the output
+ * \return The number of characters that are sent to the output function, not counting the terminating null character
+ */
+int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // _PRINTF_H_
diff --git a/src/link.ld b/src/link.ld
new file mode 100644
index 0000000..a325c1a
--- /dev/null
+++ b/src/link.ld
@@ -0,0 +1,37 @@
+SEARCH_DIR(objects)
+
+INPUT(
+bootloader.o
+libc.o
+serial.o
+video.o
+printf.o
+page.o
+acpi.o
+kernel.o
+)
+
+/*while we do need to worry about the stack converging on our kernel,
+this is only temporary, and it will be more noticable then if it were to hit bios (we want to find bugs, not ignore them!)*/
+_kernel_stack_loc = 0x200000 - 16;
+_kernel_loc = 0x100000;
+_meminfo_loc = 0x7000;
+_vbe_infoblock = 0x500; /* this does not account for segmentation to get over 0xffff*/
+
+SECTIONS
+{
+ . = 0x0;
+ bootloader 0x7c00 :
+ {
+ bootloader.o(.text)
+ }
+ kernel _kernel_loc :
+ AT (ADDR(bootloader) + SIZEOF(bootloader))
+ /*ALIGN(4096)*/
+ {
+ EXCLUDE_FILE (*bootloader.o) *(.text .data .bss .rodata .comment .eh_frame)
+ }
+}
+
+_kernel_size = (SIZEOF(kernel) / 512) + (SIZEOF(bootloader) / 512) + 2;
+_bootloader_stage1_size = (SIZEOF(bootloader) / 512) - 1;
diff --git a/src/makefile b/src/makefile
new file mode 100644
index 0000000..93f5196
--- /dev/null
+++ b/src/makefile
@@ -0,0 +1,53 @@
+LD=../compiler/indigo_gcc/bin/x86_64-elf-ld
+CC=../compiler/indigo_gcc/bin/x86_64-elf-gcc
+OBJCPY=../compiler/indigo_gcc/bin/x86_64-elf-objcopy
+INC=-Ikernel/include
+
+EMU_CORES=4
+EMU_RAM=2G
+XRES=1024
+YRES=768
+
+#TODO clean up make vs debug
+
+make:
+ nasm -g -felf64 bootloader/bootloader.asm -o objects/bootloader.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/kernel.c -o objects/kernel.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/acpi.c -o objects/acpi.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/drivers/serial.c -o objects/serial.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/drivers/video.c -o objects/video.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/printf.c -o objects/printf.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/page.c -o objects/page.o
+ $(CC) $(INC) -g -ffreestanding -c kernel/libs/libc.c -o objects/libc.o
+ $(LD) -o indigo_os.elf --oformat=elf64-x86-64 -T link.ld
+ $(OBJCPY) --only-keep-debug indigo_os.elf debug/debug_syms.o
+ $(OBJCPY) -O binary --strip-all indigo_os.elf indigo_os
+ifneq ("$(wildcard $(./debug/serial.in))","")
+ mkfifo debug/serial.in
+endif
+ifneq ("$(wildcard $(./debug/serial.out))","")
+ mkfifo debug/serial.out
+endif
+ rm -f indigo_os.elf
+
+
+run:
+ qemu-system-x86_64 -smp $(EMU_CORES) -m $(EMU_RAM) -nographic -drive format=raw,file=./indigo_os
+
+
+gdb: indigo_os
+ tmux new-session -s os_gdb "qemu-system-x86_64 -smp $(EMU_CORES) -nographic -S -s -drive format=raw,file=./indigo_os -m $(EMU_RAM)"\;\
+ split-window -h "gdb -x debug/gdbinit.gdb; killall qemu-system-x86_64"
+
+run-graphical:
+ qemu-system-x86_64 -S -s -smp $(EMU_CORES) -serial pipe:debug/serial -device VGA,edid=on,xres=$(XRES),yres=$(YRES) -drive format=raw,file=./indigo_os &\
+ gdb -x debug/gdbinit.gdb; killall qemu-system-x86_64
+
+clean:
+ rm -f objects/*
+ rm -f indigo_os
+ rm -f bin/*
+ rm -f debug/debug_syms.o
+ rm -f debug/serial.in
+ rm -f debug/serial.out
+ rm -f indigo_os.elf
diff --git a/tools/edid/bparse-edid b/tools/edid/bparse-edid
new file mode 100755
index 0000000..9983102
--- /dev/null
+++ b/tools/edid/bparse-edid
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('edid_file', type=str, help="edid file")
+args = parser.parse_args()
+
+f = open(args.edid_file, 'rb')
+edid = f.read()
+x = edid[56] | ((edid[58] & 0xf0) << 4)
+y = edid[59] | ((edid[61] & 0xf0) << 4)
+
+print("resolution: {} x {}".format(x, y))
+
+f.close()
+
diff --git a/tools/edid/desktop_edid b/tools/edid/desktop_edid
new file mode 100644
index 0000000..a0e0ae3
--- /dev/null
+++ b/tools/edid/desktop_edid
Binary files differ
diff --git a/tools/edid/laptop_edid b/tools/edid/laptop_edid
new file mode 100644
index 0000000..1e011e3
--- /dev/null
+++ b/tools/edid/laptop_edid
Binary files differ
diff --git a/tools/page/page.py b/tools/page/page.py
new file mode 100755
index 0000000..03d8e32
--- /dev/null
+++ b/tools/page/page.py
@@ -0,0 +1,29 @@
+#!/usr/bin/env python3
+from math import ceil as c
+def get_offsets(addr):
+ if addr % 4096:
+ print("You must align to 4096!")
+ return 0
+ if addr > 2 ** 47:
+ print("Address too big!")
+ return 0
+
+
+ pte = (addr >> 12) & 0x1ff
+ pde = (addr >> 21) & 0x1ff
+ pdpe =(addr >> 30) & 0x1ff
+ pml4 =(addr >> 39) & 0x1ff
+ print("pte:\t{}\npde:\t{}\npdpe:\t{}\npml4:\t{}".format(pte, pde, pdpe, pml4))
+
+def get_table_size(addr):
+ pte_cnt = c(c(addr / (1 << 12)) / 512) * 512
+ pde_cnt = c(c(addr / (1 << 21)) / 512) * 512
+ pdpe_cnt = c(c(addr / (1 << 30)) / 512) * 512
+ pml4_cnt = c(c(addr / (1 << 39)) / 512) * 512
+
+
+ return((pte_cnt + pde_cnt + pdpe_cnt + pml4_cnt) * 8)
+
+ts = get_table_size(68719476736)
+print(hex(ts))
+