first commit
This commit is contained in:
commit
66289aa8ec
58
.gitignore
vendored
Normal file
58
.gitignore
vendored
Normal file
@ -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
|
625
LICENSE
Normal file
625
LICENSE
Normal file
@ -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>.
|
13
backup.sh
Executable file
13
backup.sh
Executable file
@ -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
|
||||
|
||||
|
42
compiler/create_crosscompiler.sh
Executable file
42
compiler/create_crosscompiler.sh
Executable file
@ -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
|
||||
|
23
notes
Normal file
23
notes
Normal file
@ -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 |
|
256
src/.gdb_history
Normal file
256
src/.gdb_history
Normal file
@ -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
|
BIN
src/amd64_vol2.pdf
Normal file
BIN
src/amd64_vol2.pdf
Normal file
Binary file not shown.
38
src/bootloader/bios_functions/bios_disk.asm
Normal file
38
src/bootloader/bios_functions/bios_disk.asm
Normal file
@ -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
|
59
src/bootloader/bios_functions/print.asm
Normal file
59
src/bootloader/bios_functions/print.asm
Normal file
@ -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
|
145
src/bootloader/bootloader.asm
Normal file
145
src/bootloader/bootloader.asm
Normal file
@ -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
|
100
src/bootloader/cpu_check.asm
Normal file
100
src/bootloader/cpu_check.asm
Normal file
@ -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
|
||||
|
80
src/bootloader/enter_kernel.asm
Normal file
80
src/bootloader/enter_kernel.asm
Normal file
@ -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
|
87
src/bootloader/enter_kernel_backup
Normal file
87
src/bootloader/enter_kernel_backup
Normal file
@ -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
|
70
src/bootloader/gdt.asm
Normal file
70
src/bootloader/gdt.asm
Normal file
@ -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
|
10
src/bootloader/multicore.asm
Normal file
10
src/bootloader/multicore.asm
Normal file
@ -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
|
||||
|
0
src/bootloader/notes
Normal file
0
src/bootloader/notes
Normal file
179
src/bootloader/video.asm
Normal file
179
src/bootloader/video.asm
Normal file
@ -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
|
4
src/debug/.gdb_history
Normal file
4
src/debug/.gdb_history
Normal file
@ -0,0 +1,4 @@
|
||||
quit
|
||||
quit
|
||||
c
|
||||
quit
|
BIN
src/indigo_os
Executable file
BIN
src/indigo_os
Executable file
Binary file not shown.
39
src/kernel/include/acpi.h
Normal file
39
src/kernel/include/acpi.h
Normal file
@ -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();
|
10
src/kernel/include/libc.h
Normal file
10
src/kernel/include/libc.h
Normal file
@ -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
|
60
src/kernel/include/paging.h
Normal file
60
src/kernel/include/paging.h
Normal file
@ -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
|
117
src/kernel/include/printf.h
Normal file
117
src/kernel/include/printf.h
Normal file
@ -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_
|
16
src/kernel/include/serial.h
Normal file
16
src/kernel/include/serial.h
Normal file
@ -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
|
49
src/kernel/include/video.h
Normal file
49
src/kernel/include/video.h
Normal file
@ -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));
|
42
src/kernel/kernel.c
Normal file
42
src/kernel/kernel.c
Normal file
@ -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();
|
||||
|
||||
}
|
61
src/kernel/libs/acpi.c
Normal file
61
src/kernel/libs/acpi.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
43
src/kernel/libs/drivers/serial.c
Normal file
43
src/kernel/libs/drivers/serial.c
Normal file
@ -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);
|
||||
}
|
6
src/kernel/libs/drivers/video.c
Normal file
6
src/kernel/libs/drivers/video.c
Normal file
@ -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);
|
||||
}
|
47
src/kernel/libs/libc.c
Normal file
47
src/kernel/libs/libc.c
Normal file
@ -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];
|
||||
}
|
||||
}
|
107
src/kernel/libs/page.c
Normal file
107
src/kernel/libs/page.c
Normal file
@ -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;
|
||||
}
|
924
src/kernel/libs/printf.c
Normal file
924
src/kernel/libs/printf.c
Normal file
@ -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;
|
||||
}
|
117
src/kernel/libs/printf.h
Normal file
117
src/kernel/libs/printf.h
Normal file
@ -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_
|
37
src/link.ld
Normal file
37
src/link.ld
Normal file
@ -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;
|
53
src/makefile
Normal file
53
src/makefile
Normal file
@ -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
|
16
tools/edid/bparse-edid
Executable file
16
tools/edid/bparse-edid
Executable file
@ -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()
|
||||
|
BIN
tools/edid/desktop_edid
Normal file
BIN
tools/edid/desktop_edid
Normal file
Binary file not shown.
BIN
tools/edid/laptop_edid
Normal file
BIN
tools/edid/laptop_edid
Normal file
Binary file not shown.
29
tools/page/page.py
Executable file
29
tools/page/page.py
Executable file
@ -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))
|
||||
|
Loading…
x
Reference in New Issue
Block a user