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