forked from KolibriOS/kolibrios
Created a branch for low-level work with disks
git-svn-id: svn://kolibrios.org@9191 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
347
kernel/branches/kolibri-lldw/COPYING.TXT
Normal file
347
kernel/branches/kolibri-lldw/COPYING.TXT
Normal file
@@ -0,0 +1,347 @@
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 2, June 1991
|
||||
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
675 Mass Ave, Cambridge, MA 02139, USA
|
||||
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) 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
|
||||
this service 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 make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. 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.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
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
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the 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 a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE 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.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: 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
|
||||
convey 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) 19yy <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 2 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, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision 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, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This 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 Library General
|
||||
Public License instead of this License.
|
||||
47
kernel/branches/kolibri-lldw/Makefile
Normal file
47
kernel/branches/kolibri-lldw/Makefile
Normal file
@@ -0,0 +1,47 @@
|
||||
FASM=fasm
|
||||
FLAGS=-m 65536
|
||||
languages=en|ru|ge|et|sp
|
||||
|
||||
.PHONY: all kernel bootloader clean
|
||||
|
||||
all: kernel bootloader bootbios
|
||||
|
||||
kernel: check_lang bootbios
|
||||
@echo "*** building kernel with language '$(lang)' ..."
|
||||
@mkdir -p bin
|
||||
@echo "lang fix $(lang)" > lang.inc
|
||||
@echo "--- building 'bin/kernel.mnt' ..."
|
||||
@$(FASM) $(FLAGS) kernel.asm bin/kernel.mnt
|
||||
@$(FASM) $(FLAGS) -dUEFI=1 kernel.asm bin/kernel.bin
|
||||
@rm -f lang.inc
|
||||
|
||||
bootbios: check_lang
|
||||
@echo "*** building bootbios.bin with language '$(lang)' ..."
|
||||
@mkdir -p bin
|
||||
@echo "lang fix $(lang)" > lang.inc
|
||||
@echo "--- building 'bootbios.bin' ..."
|
||||
@$(FASM) $(FLAGS) bootbios.asm bootbios.bin
|
||||
@rm -f lang.inc
|
||||
|
||||
bootloader: check_lang
|
||||
@echo "*** building bootloader with language '$(lang)' ..."
|
||||
@mkdir -p bin
|
||||
@echo "lang fix $(lang)" > lang.inc
|
||||
@echo "--- building 'bin/boot_fat12.bin' ..."
|
||||
@$(FASM) $(FLAGS) bootloader/boot_fat12.asm bin/boot_fat12.bin
|
||||
@rm -f lang.inc
|
||||
|
||||
|
||||
check_lang:
|
||||
@case "$(lang)" in \
|
||||
$(languages)) \
|
||||
;; \
|
||||
*) \
|
||||
echo "*** error: language is incorrect or not specified"; \
|
||||
exit 1; \
|
||||
;; \
|
||||
esac
|
||||
|
||||
clean:
|
||||
rm -rf bin
|
||||
rm -f lang.inc
|
||||
7
kernel/branches/kolibri-lldw/Tupfile.lua
Normal file
7
kernel/branches/kolibri-lldw/Tupfile.lua
Normal file
@@ -0,0 +1,7 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("echo lang fix " .. ((tup.getconfig("LANG") == "") and "en" or tup.getconfig("LANG")) .. " > %o", {"lang.inc"})
|
||||
tup.rule({"bootbios.asm", extra_inputs = {"lang.inc"}}, "fasm %f %o ", "bootbios.bin")
|
||||
tup.rule({"bootbios.asm", extra_inputs = {"lang.inc"}}, "fasm %f %o -dextended_primary_loader=1", "bootbios.bin.ext_loader")
|
||||
tup.rule({"kernel.asm", extra_inputs = {"bootbios.bin", "lang.inc"}}, "fasm -m 65536 %f %o " .. tup.getconfig("KERPACK_CMD"), "kernel.mnt")
|
||||
tup.rule({"kernel.asm", extra_inputs = {"bootbios.bin.ext_loader", "lang.inc"}}, "fasm -m 65536 %f %o -dextended_primary_loader=1" .. tup.getconfig("KERPACK_CMD"), "kernel.mnt.ext_loader")
|
||||
tup.rule({"kernel.asm", extra_inputs = {"lang.inc"}}, "fasm -m 65536 %f %o -dUEFI=1 -dextended_primary_loader=1", "kolibri.krn")
|
||||
304
kernel/branches/kolibri-lldw/acpi/acpi.inc
Normal file
304
kernel/branches/kolibri-lldw/acpi/acpi.inc
Normal file
@@ -0,0 +1,304 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
; ACPI Generic Address Structure
|
||||
struct GAS
|
||||
ASID db ? ; address space id
|
||||
BitWidth db ?
|
||||
BitOffset db ?
|
||||
AccessSize db ?
|
||||
Address DQ ?
|
||||
ends
|
||||
|
||||
ASID.SYSTEM_MEMORY = 0
|
||||
ASID.SYSTEM_IO = 1
|
||||
ASID.PCI_CONFIG = 2
|
||||
ASID.PCI_EC = 3
|
||||
ASID.PCI_SMBUS = 4
|
||||
|
||||
ACCESS_SIZE.UNDEFINED = 0
|
||||
ACCESS_SIZE.BYTE = 1
|
||||
ACCESS_SIZE.WORD = 2
|
||||
ACCESS_SIZE.DWORD = 3
|
||||
ACCESS_SIZE.QWORD = 4
|
||||
|
||||
|
||||
struct ACPI_RSDP
|
||||
Signature DQ ?
|
||||
Checksum db ?
|
||||
OEMID rb 6
|
||||
Revision db ?
|
||||
RsdtAddress dd ?
|
||||
; for Revision >= 2
|
||||
Length dd ?
|
||||
XsdtAddress DQ ?
|
||||
ExtChecksum db ?
|
||||
Reserved rb 3
|
||||
ends
|
||||
|
||||
struct ACPI_TABLE ; DESCRIPTION_HEADER
|
||||
Signature dd ?
|
||||
Length dd ?
|
||||
Revision db ?
|
||||
Checksum db ?
|
||||
OEMID rb 6
|
||||
OEMTableID rb 8
|
||||
OEMRevision rb 4
|
||||
CreatorID rb 4
|
||||
CreatorRevision rb 4
|
||||
ends
|
||||
|
||||
struct ACPI_RSDT ACPI_TABLE
|
||||
Entry rd (0x1000-sizeof.ACPI_TABLE)/4
|
||||
ends
|
||||
|
||||
struct ACPI_HPET ACPI_TABLE
|
||||
ID dd ?
|
||||
Base GAS
|
||||
SeqNumber db ?
|
||||
MainCounterMinimum dw ?
|
||||
PageProtectionOEM db ?
|
||||
ends
|
||||
|
||||
struct ACPI_MADT ACPI_TABLE
|
||||
Local_IC_Addr dd ?
|
||||
Flags dd ?
|
||||
IntController rb 0x1000-sizeof.ACPI_TABLE-ACPI_MADT.IntController
|
||||
ends
|
||||
|
||||
struct ACPI_FADT ACPI_TABLE
|
||||
FirmwareCtrl dd ?
|
||||
DSDT dd ?
|
||||
db ?
|
||||
PreferredPMProfile db ?
|
||||
SCI_INT dw ?
|
||||
SMI_CMD dd ?
|
||||
ACPI_ENABLE db ?
|
||||
ACPI_DISABLE db ?
|
||||
S4BIOS_REQ db ?
|
||||
PSTATE_CNT db ?
|
||||
PM1a_EVT_BLK dd ?
|
||||
PM1b_EVT_BLK dd ?
|
||||
PM1a_CNT_BLK dd ?
|
||||
PM1b_CNT_BLK dd ?
|
||||
PM2_CNT_BLK dd ?
|
||||
PM_TMR_BLK dd ?
|
||||
GPE0_BLK dd ?
|
||||
GPE1_BLK dd ?
|
||||
PM1_EVT_LEN db ?
|
||||
PM1_CNT_LEN db ?
|
||||
PM2_CNT_LEN db ?
|
||||
PM_TMR_LEN db ?
|
||||
GPE0_BLK_LEN db ?
|
||||
GPE1_BLK_LEN db ?
|
||||
GPE1_BASE db ?
|
||||
CST_CNT db ?
|
||||
P_LVL2_LAT dw ?
|
||||
P_LVL3_LAT dw ?
|
||||
FLUSH_SIZE dw ?
|
||||
FLUSH_STRIDE dw ?
|
||||
DUTY_OFFSET db ?
|
||||
DUTY_WIDTH db ?
|
||||
DAY_ALRM db ?
|
||||
MON_ALRM db ?
|
||||
CENTURY db ?
|
||||
IAPC_BOOT_ARCH dw ?
|
||||
db ?
|
||||
Flags dd ?
|
||||
RESET_REG GAS
|
||||
RESET_VALUE db ?
|
||||
ARM_BOOT_ARCH dw ?
|
||||
FADT_Minor_Version db ?
|
||||
X_FIRMWARE_CTRL DQ ?
|
||||
X_DSDT DQ ?
|
||||
X_PM1a_EVT_BLK GAS
|
||||
X_PM1b_EVT_BLK GAS
|
||||
X_PM1a_CNT_BLK GAS
|
||||
X_PM1b_CNT_BLK GAS
|
||||
X_PM2_CNT_BLK GAS
|
||||
X_PM_TMR_BLK GAS
|
||||
X_GPE0_BLK GAS
|
||||
X_GPE1_BLK GAS
|
||||
SLEEP_CONTROL_REG GAS
|
||||
SLEEP_STATUS_REG GAS
|
||||
HypervisorVendorID rb 8
|
||||
ends
|
||||
|
||||
MAX_SSDTS = 32
|
||||
|
||||
iglobal
|
||||
align 4
|
||||
acpi_lapic_base dd 0xfee00000 ; default local apic base
|
||||
endg
|
||||
|
||||
uglobal
|
||||
align 4
|
||||
acpi_dev_data rd 1
|
||||
acpi_dev_size rd 1
|
||||
|
||||
acpi_rsdp_base rd 1
|
||||
acpi_rsdt_base rd 1
|
||||
acpi_rsdt_size rd 1
|
||||
acpi_fadt_base rd 1
|
||||
acpi_fadt_size rd 1
|
||||
acpi_ssdt_base rd MAX_SSDTS
|
||||
acpi_ssdt_size rd MAX_SSDTS
|
||||
acpi_ssdt_cnt rd 1
|
||||
acpi_madt_base rd 1
|
||||
acpi_madt_size rd 1
|
||||
acpi_ioapic_base rd MAX_IOAPICS
|
||||
acpi_hpet_base rd 1
|
||||
acpi_hpet_size rd 1
|
||||
cpu_count rd 1
|
||||
smpt rd 16
|
||||
endg
|
||||
|
||||
align 4
|
||||
; @returns ACPI Root System Description Pointer
|
||||
acpi_get_root_ptr:
|
||||
mov eax, [acpi_rsdp_base]
|
||||
ret
|
||||
|
||||
align 4
|
||||
rsdt_find: ;ecx= rsdt edx= SIG
|
||||
push ebx
|
||||
push esi
|
||||
|
||||
lea ebx, [ecx+ACPI_RSDT.Entry]
|
||||
mov esi, [ecx+ACPI_RSDT.Length]
|
||||
add esi, ecx
|
||||
align 4
|
||||
.next:
|
||||
mov eax, [ebx]
|
||||
cmp [eax], edx
|
||||
je .done
|
||||
|
||||
add ebx, 4
|
||||
cmp ebx, esi
|
||||
jb .next
|
||||
|
||||
xor eax, eax
|
||||
pop esi
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
.done:
|
||||
mov eax, [ebx]
|
||||
pop esi
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
align 4
|
||||
check_acpi:
|
||||
cmp [acpi_rsdp_base], 0
|
||||
jz .done
|
||||
stdcall map_io_mem, [acpi_rsdp_base], sizeof.ACPI_RSDP, \
|
||||
PG_GLOBAL+PAT_WB+PG_READ
|
||||
mov [acpi_rsdp_base], eax
|
||||
.rsdp_done:
|
||||
cmp [acpi_rsdt_base], 0
|
||||
jz .rsdt_done
|
||||
stdcall map_io_mem, [acpi_rsdt_base], [acpi_rsdt_size], \
|
||||
PG_GLOBAL+PAT_WB+PG_READ
|
||||
mov [acpi_rsdt_base], eax
|
||||
.rsdt_done:
|
||||
cmp [acpi_fadt_base], 0
|
||||
jz .fadt_done
|
||||
stdcall map_io_mem, [acpi_fadt_base], [acpi_fadt_size], \
|
||||
PG_GLOBAL+PAT_WB+PG_READ
|
||||
mov [acpi_fadt_base], eax
|
||||
.fadt_done:
|
||||
cmp [acpi_hpet_base], 0
|
||||
jz .hpet_done
|
||||
stdcall map_io_mem, [acpi_hpet_base], [acpi_hpet_size], \
|
||||
PG_GLOBAL+PAT_WB+PG_READ
|
||||
mov [acpi_hpet_base], eax
|
||||
mov eax, [eax+ACPI_HPET.Base.Address.lo]
|
||||
mov [hpet_base], eax
|
||||
.hpet_done:
|
||||
cmp [acpi_madt_base], 0
|
||||
jz .madt_done
|
||||
stdcall map_io_mem, [acpi_madt_base], [acpi_madt_size], \
|
||||
PG_GLOBAL+PAT_WB+PG_READ
|
||||
mov [acpi_madt_base], eax
|
||||
|
||||
mov ecx, [eax+ACPI_MADT.Local_IC_Addr]
|
||||
mov [acpi_lapic_base], ecx
|
||||
push eax
|
||||
stdcall map_io_mem, ecx, 0x1000, PG_GLOBAL+PG_NOCACHE+PG_SWR
|
||||
mov [LAPIC_BASE], eax
|
||||
mov ecx, eax
|
||||
pop eax
|
||||
|
||||
mov edi, smpt
|
||||
mov ebx, [ecx+APIC_ID]
|
||||
shr ebx, 24 ; read APIC ID
|
||||
|
||||
mov [edi], ebx ; bootstrap always first
|
||||
inc [cpu_count]
|
||||
add edi, 4
|
||||
|
||||
mov [ioapic_cnt], 0
|
||||
lea edx, [eax+ACPI_MADT.IntController]
|
||||
mov ecx, [eax+ACPI_MADT.Length]
|
||||
add ecx, eax
|
||||
.check:
|
||||
mov eax, [edx]
|
||||
cmp al, 0
|
||||
je .lapic
|
||||
cmp al, 1
|
||||
je .io_apic
|
||||
jmp .next
|
||||
.lapic:
|
||||
shr eax, 24 ; get APIC ID
|
||||
cmp eax, ebx ; skip self
|
||||
je .next
|
||||
|
||||
test [edx+4], byte 1 ; is enabled ?
|
||||
jz .next
|
||||
|
||||
cmp [cpu_count], 16
|
||||
jae .next
|
||||
|
||||
stosd ; store APIC ID
|
||||
inc [cpu_count]
|
||||
jmp .next
|
||||
|
||||
.io_apic:
|
||||
mov eax, [ioapic_cnt]
|
||||
push dword[edx+4]
|
||||
pop [acpi_ioapic_base+eax*4]
|
||||
push dword[edx+8]
|
||||
pop [ioapic_gsi_base+eax*4]
|
||||
inc [ioapic_cnt]
|
||||
jmp .next
|
||||
|
||||
.next:
|
||||
mov eax, [edx]
|
||||
movzx eax, ah
|
||||
add edx, eax
|
||||
cmp edx, ecx
|
||||
jb .check
|
||||
.madt_done:
|
||||
|
||||
xor ecx, ecx
|
||||
.next_ssdt:
|
||||
cmp ecx, [acpi_ssdt_cnt]
|
||||
jz .ssdt_done
|
||||
push ecx
|
||||
stdcall map_io_mem, [acpi_ssdt_base+ecx*4], [acpi_ssdt_size+ecx*4], \
|
||||
PG_GLOBAL+PAT_WB+PG_READ
|
||||
pop ecx
|
||||
mov [acpi_ssdt_base+ecx*4], eax
|
||||
inc ecx
|
||||
jmp .next_ssdt
|
||||
.ssdt_done:
|
||||
|
||||
.done:
|
||||
ret
|
||||
2066
kernel/branches/kolibri-lldw/asmxygen.py
Normal file
2066
kernel/branches/kolibri-lldw/asmxygen.py
Normal file
File diff suppressed because it is too large
Load Diff
1403
kernel/branches/kolibri-lldw/blkdev/ahci.inc
Normal file
1403
kernel/branches/kolibri-lldw/blkdev/ahci.inc
Normal file
File diff suppressed because it is too large
Load Diff
301
kernel/branches/kolibri-lldw/blkdev/bd_drv.inc
Normal file
301
kernel/branches/kolibri-lldw/blkdev/bd_drv.inc
Normal file
@@ -0,0 +1,301 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
; Disk access through BIOS
|
||||
iglobal
|
||||
align 4
|
||||
bd_callbacks:
|
||||
dd bd_callbacks.end - bd_callbacks ; strucsize
|
||||
dd 0 ; no close function
|
||||
dd 0 ; no closemedia function
|
||||
dd bd_querymedia
|
||||
dd bd_read_interface
|
||||
dd bd_write_interface
|
||||
dd 0 ; no flush function
|
||||
dd 0 ; use default cache size
|
||||
.end:
|
||||
endg
|
||||
|
||||
uglobal
|
||||
bios_hdpos dd 0
|
||||
bios_cur_sector dd ?
|
||||
bios_read_len dd ?
|
||||
cache_chain_ptr dd ?
|
||||
int13_regs_in rb sizeof.v86_regs
|
||||
int13_regs_out rb sizeof.v86_regs
|
||||
cache_chain_size db ?
|
||||
endg
|
||||
|
||||
struct BiosDiskData
|
||||
DriveNumber db ?
|
||||
IRQ db ?
|
||||
ATADEVbit dw ?
|
||||
SectorSize dd ?
|
||||
Capacity dq ?
|
||||
ends
|
||||
;-----------------------------------------------------------------
|
||||
proc bd_read_interface stdcall uses edi, \
|
||||
userdata, buffer, startsector:qword, numsectors
|
||||
; userdata = old [hdpos] = 80h + index in NumBiosDisks
|
||||
; buffer = pointer to buffer for data
|
||||
; startsector = 64-bit start sector
|
||||
; numsectors = pointer to number of sectors on input,
|
||||
; must be filled with number of sectors really read
|
||||
locals
|
||||
sectors_todo dd ?
|
||||
endl
|
||||
; 1. Initialize number of sectors: get number of requested sectors
|
||||
; and say that no sectors were read yet.
|
||||
mov ecx, [numsectors]
|
||||
mov eax, [ecx]
|
||||
mov dword [ecx], 0
|
||||
mov [sectors_todo], eax
|
||||
; 2. Acquire the global lock.
|
||||
mov ecx, ide_mutex
|
||||
call mutex_lock
|
||||
; 3. Convert parameters to the form suitable for worker procedures.
|
||||
; Underlying procedures do not know about 64-bit sectors.
|
||||
; Worker procedures use global variables and edi for [buffer].
|
||||
cmp dword [startsector+4], 0
|
||||
jnz .fail
|
||||
and [hd_error], 0
|
||||
mov eax, [userdata]
|
||||
mov [hdpos], eax
|
||||
mov eax, dword [startsector]
|
||||
mov edi, [buffer]
|
||||
; 4. Worker procedures take one sectors per time, so loop over all sectors to read.
|
||||
.sectors_loop:
|
||||
call bd_read
|
||||
cmp [hd_error], 0
|
||||
jnz .fail
|
||||
mov ecx, [numsectors]
|
||||
inc dword [ecx] ; one more sector is read
|
||||
dec [sectors_todo]
|
||||
jz .done
|
||||
inc eax
|
||||
jnz .sectors_loop
|
||||
; 5. Loop is done, either due to error or because everything is done.
|
||||
; Release the global lock and return the corresponding status.
|
||||
.fail:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
or eax, -1
|
||||
ret
|
||||
.done:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------
|
||||
proc bd_write_interface stdcall uses esi edi, \
|
||||
userdata, buffer, startsector:qword, numsectors
|
||||
; userdata = old [hdpos] = 80h + index in NumBiosDisks
|
||||
; buffer = pointer to buffer with data
|
||||
; startsector = 64-bit start sector
|
||||
; numsectors = pointer to number of sectors on input,
|
||||
; must be filled with number of sectors really written
|
||||
locals
|
||||
sectors_todo dd ?
|
||||
endl
|
||||
; 1. Initialize number of sectors: get number of requested sectors
|
||||
; and say that no sectors were read yet.
|
||||
mov ecx, [numsectors]
|
||||
mov eax, [ecx]
|
||||
mov dword [ecx], 0
|
||||
mov [sectors_todo], eax
|
||||
; 2. Acquire the global lock.
|
||||
mov ecx, ide_mutex
|
||||
call mutex_lock
|
||||
; 3. Convert parameters to the form suitable for worker procedures.
|
||||
; Underlying procedures do not know about 64-bit sectors.
|
||||
; Worker procedures use global variables and esi for [buffer].
|
||||
cmp dword [startsector+4], 0
|
||||
jnz .fail
|
||||
and [hd_error], 0
|
||||
mov eax, [userdata]
|
||||
mov [hdpos], eax
|
||||
mov esi, [buffer]
|
||||
lea edi, [startsector]
|
||||
mov [cache_chain_ptr], edi
|
||||
; 4. Worker procedures take max 16 sectors per time,
|
||||
; loop until all sectors will be processed.
|
||||
.sectors_loop:
|
||||
mov ecx, 16
|
||||
cmp ecx, [sectors_todo]
|
||||
jbe @f
|
||||
mov ecx, [sectors_todo]
|
||||
@@:
|
||||
mov [cache_chain_size], cl
|
||||
call bd_write_cache_chain
|
||||
cmp [hd_error], 0
|
||||
jnz .fail
|
||||
movzx ecx, [cache_chain_size]
|
||||
mov eax, [numsectors]
|
||||
add [eax], ecx
|
||||
sub [sectors_todo], ecx
|
||||
jz .done
|
||||
add [edi], ecx
|
||||
jc .fail
|
||||
shl ecx, 9
|
||||
add esi, ecx
|
||||
jmp .sectors_loop
|
||||
; 5. Loop is done, either due to error or because everything is done.
|
||||
; Release the global lock and return the corresponding status.
|
||||
.fail:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
or eax, -1
|
||||
ret
|
||||
.done:
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------
|
||||
proc bd_querymedia stdcall, hd_data, mediainfo
|
||||
mov edx, [mediainfo]
|
||||
mov eax, [hd_data]
|
||||
lea eax, [(eax-80h)*4]
|
||||
lea eax, [BiosDisksData+eax*4]
|
||||
mov [edx+DISKMEDIAINFO.Flags], 0
|
||||
mov ecx, [eax+BiosDiskData.SectorSize]
|
||||
mov [edx+DISKMEDIAINFO.SectorSize], ecx
|
||||
mov ecx, dword [eax+BiosDiskData.Capacity+0]
|
||||
mov eax, dword [eax+BiosDiskData.Capacity+4]
|
||||
mov dword [edx+DISKMEDIAINFO.Capacity+0], ecx
|
||||
mov dword [edx+DISKMEDIAINFO.Capacity+4], eax
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------
|
||||
bd_read:
|
||||
push eax
|
||||
push edx
|
||||
mov edx, [bios_hdpos]
|
||||
cmp edx, [hdpos]
|
||||
jne .notread
|
||||
mov edx, [bios_cur_sector]
|
||||
cmp eax, edx
|
||||
jb .notread
|
||||
add edx, [bios_read_len]
|
||||
dec edx
|
||||
cmp eax, edx
|
||||
ja .notread
|
||||
sub eax, [bios_cur_sector]
|
||||
shl eax, 9
|
||||
add eax, (OS_BASE+0x99000)
|
||||
push ecx esi
|
||||
mov esi, eax
|
||||
mov ecx, 512/4
|
||||
cld
|
||||
rep movsd
|
||||
pop esi ecx
|
||||
pop edx
|
||||
pop eax
|
||||
ret
|
||||
.notread:
|
||||
push ecx
|
||||
mov dl, 42h
|
||||
mov ecx, 16
|
||||
call int13_call
|
||||
pop ecx
|
||||
test eax, eax
|
||||
jnz .v86err
|
||||
test edx, edx
|
||||
jz .readerr
|
||||
mov [bios_read_len], edx
|
||||
mov edx, [hdpos]
|
||||
mov [bios_hdpos], edx
|
||||
pop edx
|
||||
pop eax
|
||||
mov [bios_cur_sector], eax
|
||||
jmp bd_read
|
||||
.readerr:
|
||||
.v86err:
|
||||
pop edx
|
||||
pop eax
|
||||
mov [hd_error], 1
|
||||
jmp hd_read_error
|
||||
;-----------------------------------------------------------------
|
||||
bd_write_cache_chain:
|
||||
pusha
|
||||
mov edi, OS_BASE + 0x99000
|
||||
movzx ecx, [cache_chain_size]
|
||||
push ecx
|
||||
shl ecx, 9-2
|
||||
rep movsd
|
||||
pop ecx
|
||||
mov dl, 43h
|
||||
mov eax, [cache_chain_ptr]
|
||||
mov eax, [eax]
|
||||
call int13_call
|
||||
test eax, eax
|
||||
jnz .v86err
|
||||
cmp edx, ecx
|
||||
jnz .writeerr
|
||||
popa
|
||||
ret
|
||||
.v86err:
|
||||
.writeerr:
|
||||
popa
|
||||
mov [hd_error], 1
|
||||
jmp hd_write_error
|
||||
;-----------------------------------------------------------------
|
||||
int13_call:
|
||||
; Because this code uses fixed addresses,
|
||||
; it can not be run simultaniously by many threads.
|
||||
; In current implementation it is protected by common mutex 'ide_status'
|
||||
mov word [OS_BASE + 510h], 10h ; packet length
|
||||
mov word [OS_BASE + 512h], cx ; number of sectors
|
||||
mov dword [OS_BASE + 514h], 99000000h ; buffer 9900:0000
|
||||
mov dword [OS_BASE + 518h], eax
|
||||
and dword [OS_BASE + 51Ch], 0
|
||||
push ebx ecx esi edi
|
||||
mov ebx, int13_regs_in
|
||||
mov edi, ebx
|
||||
mov ecx, sizeof.v86_regs/4
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
mov byte [ebx+v86_regs.eax+1], dl
|
||||
mov eax, [hdpos]
|
||||
lea eax, [(eax-80h)*4]
|
||||
lea eax, [BiosDisksData+eax*4]
|
||||
mov dl, [eax]
|
||||
mov byte [ebx+v86_regs.edx], dl
|
||||
movzx edx, byte [eax+1]
|
||||
; mov dl, 5
|
||||
test edx, edx
|
||||
jnz .hasirq
|
||||
dec edx
|
||||
jmp @f
|
||||
.hasirq:
|
||||
pushad
|
||||
stdcall enable_irq, edx
|
||||
popad
|
||||
@@:
|
||||
mov word [ebx+v86_regs.esi], 510h
|
||||
mov word [ebx+v86_regs.ss], 9000h
|
||||
mov word [ebx+v86_regs.esp], 09000h
|
||||
mov word [ebx+v86_regs.eip], 500h
|
||||
mov [ebx+v86_regs.eflags], 20200h
|
||||
mov esi, [sys_v86_machine]
|
||||
mov ecx, 0x502
|
||||
push fs
|
||||
call v86_start
|
||||
pop fs
|
||||
and [bios_hdpos], 0
|
||||
pop edi esi ecx ebx
|
||||
movzx edx, byte [OS_BASE + 512h]
|
||||
test byte [int13_regs_out+v86_regs.eflags], 1
|
||||
jnz @f
|
||||
mov edx, ecx
|
||||
@@:
|
||||
ret
|
||||
1218
kernel/branches/kolibri-lldw/blkdev/cd_drv.inc
Normal file
1218
kernel/branches/kolibri-lldw/blkdev/cd_drv.inc
Normal file
File diff suppressed because it is too large
Load Diff
1666
kernel/branches/kolibri-lldw/blkdev/disk.inc
Normal file
1666
kernel/branches/kolibri-lldw/blkdev/disk.inc
Normal file
File diff suppressed because it is too large
Load Diff
1387
kernel/branches/kolibri-lldw/blkdev/disk_cache.inc
Normal file
1387
kernel/branches/kolibri-lldw/blkdev/disk_cache.inc
Normal file
File diff suppressed because it is too large
Load Diff
68
kernel/branches/kolibri-lldw/blkdev/fdc.inc
Normal file
68
kernel/branches/kolibri-lldw/blkdev/fdc.inc
Normal file
@@ -0,0 +1,68 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
uglobal
|
||||
dmasize db 0x0
|
||||
dmamode db 0x0
|
||||
endg
|
||||
|
||||
fdc_init: ;start with clean tracks.
|
||||
mov edi, OS_BASE+0xD201
|
||||
mov al, 0
|
||||
mov ecx, 160
|
||||
rep stosb
|
||||
ret
|
||||
|
||||
save_image:
|
||||
cmp [ramdisk_actual_size], FLOPPY_CAPACITY
|
||||
jnz .fail
|
||||
pusha
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_lock
|
||||
mov [flp_number], bl
|
||||
call floppy_read_bootsector
|
||||
cmp [FDC_Status], 0
|
||||
jne .unnecessary_save_image
|
||||
mov [FDD_Track], 0; Цилиндр
|
||||
mov [FDD_Head], 0; Сторона
|
||||
mov [FDD_Sector], 1; Сектор
|
||||
mov esi, RAMDISK
|
||||
call SeekTrack
|
||||
.save_image_1:
|
||||
call take_data_from_application_1
|
||||
call WriteSectWithRetr
|
||||
; call WriteSector
|
||||
cmp [FDC_Status], 0
|
||||
jne .unnecessary_save_image
|
||||
inc [FDD_Sector]
|
||||
cmp [FDD_Sector], 19
|
||||
jne .save_image_1
|
||||
mov [FDD_Sector], 1
|
||||
inc [FDD_Head]
|
||||
cmp [FDD_Head], 2
|
||||
jne .save_image_1
|
||||
mov [FDD_Head], 0
|
||||
inc [FDD_Track]
|
||||
call SeekTrack
|
||||
cmp [FDD_Track], 80
|
||||
jne .save_image_1
|
||||
.unnecessary_save_image:
|
||||
cmp [FDC_Status], 0
|
||||
pushf
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_unlock
|
||||
popf
|
||||
popa
|
||||
jnz .fail
|
||||
xor eax, eax
|
||||
ret
|
||||
.fail:
|
||||
movi eax, 1
|
||||
ret
|
||||
960
kernel/branches/kolibri-lldw/blkdev/flp_drv.inc
Normal file
960
kernel/branches/kolibri-lldw/blkdev/flp_drv.inc
Normal file
@@ -0,0 +1,960 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
;**********************************************************
|
||||
; Direct work with floppy disk drive
|
||||
;**********************************************************
|
||||
; Source code author - Kulakov Vladimir Gennadievich.
|
||||
; Adaptation and improvement - Mario79.
|
||||
|
||||
;give_back_application_data: ; give back to application
|
||||
; mov edi,[TASK_BASE]
|
||||
; mov edi,[edi+TASKDATA.mem_start]
|
||||
; add edi,ecx
|
||||
give_back_application_data_1:
|
||||
mov esi, FDD_BUFF;FDD_DataBuffer ;0x40000
|
||||
mov ecx, 128
|
||||
cld
|
||||
rep movsd
|
||||
ret
|
||||
|
||||
;take_data_from_application: ; take from application
|
||||
; mov esi,[TASK_BASE]
|
||||
; mov esi,[esi+TASKDATA.mem_start]
|
||||
; add esi,ecx
|
||||
take_data_from_application_1:
|
||||
mov edi, FDD_BUFF;FDD_DataBuffer ;0x40000
|
||||
mov ecx, 128
|
||||
cld
|
||||
rep movsd
|
||||
ret
|
||||
|
||||
; Controller operations result codes (FDC_Status)
|
||||
FDC_Normal = 0 ; normal finish
|
||||
FDC_TimeOut = 1 ; time out error
|
||||
FDC_DiskNotFound = 2 ; no disk in drive
|
||||
FDC_TrackNotFound = 3 ; track not found
|
||||
FDC_SectorNotFound = 4 ; sector not found
|
||||
|
||||
; Maximum values of the sector coordinates (specified
|
||||
; values correspond to the parameters of the standard
|
||||
; 3-inch 1.44 MB floppy disk)
|
||||
MAX_Track = 79
|
||||
MAX_Head = 1
|
||||
MAX_Sector = 18
|
||||
|
||||
uglobal
|
||||
; Timer tick counter
|
||||
TickCounter dd ?
|
||||
; Operation completion code with the floppy disk drive controller
|
||||
FDC_Status DB ?
|
||||
; Interrupt flag from floppy disk drive
|
||||
FDD_IntFlag DB ?
|
||||
; The moment of the beginning of the last operation with FDD
|
||||
FDD_Time DD ?
|
||||
; Drive number
|
||||
FDD_Type db 0
|
||||
; Sector coordinates
|
||||
FDD_Track DB ?
|
||||
FDD_Head DB ?
|
||||
FDD_Sector DB ?
|
||||
|
||||
; Operation result block
|
||||
FDC_ST0 DB ?
|
||||
FDC_ST1 DB ?
|
||||
FDC_ST2 DB ?
|
||||
FDC_C DB ?
|
||||
FDC_H DB ?
|
||||
FDC_R DB ?
|
||||
FDC_N DB ?
|
||||
; Read operation repetition counter
|
||||
ReadRepCounter DB ?
|
||||
; Recalibration operation repetition counter
|
||||
RecalRepCounter DB ?
|
||||
endg
|
||||
; Memory area for storing the readed sector
|
||||
;FDD_DataBuffer: times 512 db 0 ;DB 512 DUP (?)
|
||||
fdd_motor_status db 0
|
||||
timer_fdd_motor dd 0
|
||||
|
||||
;**************************************
|
||||
;* INITIALIZATION OF DMA MODE FOR FDD *
|
||||
;**************************************
|
||||
Init_FDC_DMA:
|
||||
pushad
|
||||
mov al, 0
|
||||
out 0x0c, al; reset the flip-flop to a known state.
|
||||
mov al, 6 ; mask channel 2 so we can reprogram it.
|
||||
out 0x0a, al
|
||||
mov al, [dmamode]; 0x46 -> Read from floppy - 0x4A Write to floppy
|
||||
out 0x0b, al
|
||||
mov al, 0
|
||||
out 0x0c, al; reset the flip-flop to a known state.
|
||||
mov eax, 0xD000
|
||||
out 0x04, al; set the channel 2 starting address to 0
|
||||
shr eax, 8
|
||||
out 0x04, al
|
||||
shr eax, 8
|
||||
out 0x81, al
|
||||
mov al, 0
|
||||
out 0x0c, al; reset flip-flop
|
||||
mov al, 0xff;set count (actual size -1)
|
||||
out 0x5, al
|
||||
mov al, 0x1;[dmasize] ;(0x1ff = 511 / 0x23ff =9215)
|
||||
out 0x5, al
|
||||
mov al, 2
|
||||
out 0xa, al
|
||||
popad
|
||||
ret
|
||||
|
||||
;***********************************
|
||||
;* WRITE BYTE TO FDC DATA PORT *
|
||||
;* Parameters: *
|
||||
;* AL - byte to write. *
|
||||
;***********************************
|
||||
FDCDataOutput:
|
||||
; DEBUGF 1,'K : FDCDataOutput(%x)',al
|
||||
; pusha
|
||||
push eax ecx edx
|
||||
mov AH, AL ; remember byte to AH
|
||||
; Reset controller state variable
|
||||
mov [FDC_Status], FDC_Normal
|
||||
; Check the readiness of the controller to receive data
|
||||
mov DX, 3F4h ; (FDC state port)
|
||||
mov ecx, 0x10000 ; set timeout counter
|
||||
@@TestRS:
|
||||
in AL, DX ; read the RS register
|
||||
and AL, 0C0h ; get digits 6 and 7
|
||||
cmp AL, 80h ; check digits 6 and 7
|
||||
je @@OutByteToFDC
|
||||
loop @@TestRS
|
||||
; Time out error
|
||||
; DEBUGF 1,' timeout\n'
|
||||
mov [FDC_Status], FDC_TimeOut
|
||||
jmp @@End_5
|
||||
; Write byte to data port
|
||||
@@OutByteToFDC:
|
||||
inc DX
|
||||
mov AL, AH
|
||||
out DX, AL
|
||||
; DEBUGF 1,' ok\n'
|
||||
@@End_5:
|
||||
; popa
|
||||
pop edx ecx eax
|
||||
ret
|
||||
|
||||
;******************************************
|
||||
;* READ BYTE FROM FDC DATA PORT *
|
||||
;* Procedure doesnt have input params. *
|
||||
;* Output : *
|
||||
;* AL - byte read. *
|
||||
;******************************************
|
||||
FDCDataInput:
|
||||
push ECX
|
||||
push DX
|
||||
; Reset controller state variable
|
||||
mov [FDC_Status], FDC_Normal
|
||||
; Check the readiness of the controller to receive data
|
||||
mov DX, 3F4h ;(FDC state port)
|
||||
mov ecx, 0x10000 ; set timeout counter
|
||||
@@TestRS_1:
|
||||
in AL, DX ; read the RS register
|
||||
and AL, 0C0h ; get digits 6 and 7
|
||||
cmp AL, 0C0h ; check digits 6 and 7
|
||||
je @@GetByteFromFDC
|
||||
loop @@TestRS_1
|
||||
; Time out error
|
||||
; DEBUGF 1,'K : FDCDataInput: timeout\n'
|
||||
mov [FDC_Status], FDC_TimeOut
|
||||
jmp @@End_6
|
||||
; Get byte from data port
|
||||
@@GetByteFromFDC:
|
||||
inc DX
|
||||
in AL, DX
|
||||
; DEBUGF 1,'K : FDCDataInput: %x\n',al
|
||||
@@End_6:
|
||||
pop DX
|
||||
pop ECX
|
||||
ret
|
||||
|
||||
;*********************************************
|
||||
;* FDC INTERRUPT HANDLER *
|
||||
;*********************************************
|
||||
FDCInterrupt:
|
||||
; dbgstr 'FDCInterrupt'
|
||||
; Set the interrupt flag
|
||||
mov [FDD_IntFlag], 1
|
||||
mov al, 1
|
||||
ret
|
||||
|
||||
;*******************************************
|
||||
;* WAIT FOR INTERRUPT FROM FDC *
|
||||
;*******************************************
|
||||
WaitFDCInterrupt:
|
||||
pusha
|
||||
; Reset operation status byte
|
||||
mov [FDC_Status], FDC_Normal
|
||||
; Zero out the tick counter
|
||||
mov eax, [timer_ticks]
|
||||
mov [TickCounter], eax
|
||||
; Wait for the floppy disk interrupt flag to be set
|
||||
@@TestRS_2:
|
||||
call change_task
|
||||
cmp [FDD_IntFlag], 0
|
||||
jnz @@End_7 ; interrupt occured
|
||||
mov eax, [timer_ticks]
|
||||
sub eax, [TickCounter]
|
||||
cmp eax, 200;50 ;25 ;5 ; wait 5 ticks
|
||||
jb @@TestRS_2
|
||||
; jl @@TestRS_2
|
||||
; Time out error
|
||||
; dbgstr 'WaitFDCInterrupt: timeout'
|
||||
mov [FDC_Status], FDC_TimeOut
|
||||
@@End_7:
|
||||
popa
|
||||
ret
|
||||
|
||||
;***********************************
|
||||
;* Turn on the motor of drive "A:" *
|
||||
;***********************************
|
||||
FDDMotorON:
|
||||
; dbgstr 'FDDMotorON'
|
||||
pusha
|
||||
; cmp [fdd_motor_status],1
|
||||
; je fdd_motor_on
|
||||
mov al, [flp_number]
|
||||
cmp [fdd_motor_status], al
|
||||
je fdd_motor_on
|
||||
; Reset the FDD controller
|
||||
mov DX, 3F2h ; motor control port
|
||||
mov AL, 0
|
||||
out DX, AL
|
||||
; Select and turn on the drive motor
|
||||
cmp [flp_number], 1
|
||||
jne FDDMotorON_B
|
||||
; call FDDMotorOFF_B
|
||||
mov AL, 1Ch ; Floppy A
|
||||
jmp FDDMotorON_1
|
||||
FDDMotorON_B:
|
||||
; call FDDMotorOFF_A
|
||||
mov AL, 2Dh ; Floppy B
|
||||
FDDMotorON_1:
|
||||
out DX, AL
|
||||
; Zero out the tick counter
|
||||
mov eax, [timer_ticks]
|
||||
mov [TickCounter], eax
|
||||
; wait 0.5 s
|
||||
@@dT:
|
||||
call change_task
|
||||
mov eax, [timer_ticks]
|
||||
sub eax, [TickCounter]
|
||||
cmp eax, 50 ;10
|
||||
jb @@dT
|
||||
; Read results of RESET command
|
||||
push 4
|
||||
; DEBUGF 1,'K : floppy reset results:'
|
||||
@@:
|
||||
mov al, 8
|
||||
call FDCDataOutput
|
||||
call FDCDataInput
|
||||
; DEBUGF 1,' %x',al
|
||||
call FDCDataInput
|
||||
; DEBUGF 1,' %x',al
|
||||
dec dword [esp]
|
||||
jnz @b
|
||||
; DEBUGF 1,'\n'
|
||||
pop eax
|
||||
cmp [flp_number], 1
|
||||
jne fdd_motor_on_B
|
||||
mov [fdd_motor_status], 1
|
||||
jmp fdd_motor_on
|
||||
fdd_motor_on_B:
|
||||
mov [fdd_motor_status], 2
|
||||
fdd_motor_on:
|
||||
call save_timer_fdd_motor
|
||||
popa
|
||||
ret
|
||||
|
||||
;*****************************************
|
||||
;* SAVING TIME STAMP *
|
||||
;*****************************************
|
||||
save_timer_fdd_motor:
|
||||
mov eax, [timer_ticks]
|
||||
mov [timer_fdd_motor], eax
|
||||
ret
|
||||
|
||||
;*****************************************
|
||||
;* CHECK THE MOTOR SHUTDOWN DELAY *
|
||||
;*****************************************
|
||||
proc check_fdd_motor_status_has_work?
|
||||
cmp [fdd_motor_status], 0
|
||||
jz .no
|
||||
mov eax, [timer_ticks]
|
||||
sub eax, [timer_fdd_motor]
|
||||
cmp eax, 500
|
||||
jb .no
|
||||
.yes:
|
||||
xor eax, eax
|
||||
inc eax
|
||||
ret
|
||||
.no:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
align 4
|
||||
check_fdd_motor_status:
|
||||
cmp [fdd_motor_status], 0
|
||||
je end_check_fdd_motor_status_1
|
||||
mov eax, [timer_ticks]
|
||||
sub eax, [timer_fdd_motor]
|
||||
cmp eax, 500
|
||||
jb end_check_fdd_motor_status
|
||||
call FDDMotorOFF
|
||||
mov [fdd_motor_status], 0
|
||||
end_check_fdd_motor_status_1:
|
||||
end_check_fdd_motor_status:
|
||||
ret
|
||||
|
||||
;**********************************
|
||||
;* TURN OFF MOTOR OF DRIVE *
|
||||
;**********************************
|
||||
FDDMotorOFF:
|
||||
; dbgstr 'FDDMotorOFF'
|
||||
push AX
|
||||
push DX
|
||||
cmp [flp_number], 1
|
||||
jne FDDMotorOFF_1
|
||||
call FDDMotorOFF_A
|
||||
jmp FDDMotorOFF_2
|
||||
FDDMotorOFF_1:
|
||||
call FDDMotorOFF_B
|
||||
FDDMotorOFF_2:
|
||||
pop DX
|
||||
pop AX
|
||||
; clearing caching flags due to information obsolescence
|
||||
or [floppy_media_flags+0], FLOPPY_MEDIA_NEED_RESCAN
|
||||
or [floppy_media_flags+1], FLOPPY_MEDIA_NEED_RESCAN
|
||||
ret
|
||||
|
||||
FDDMotorOFF_A:
|
||||
mov DX, 3F2h ; motor control port
|
||||
mov AL, 0Ch ; Floppy A
|
||||
out DX, AL
|
||||
ret
|
||||
|
||||
FDDMotorOFF_B:
|
||||
mov DX, 3F2h ; motor control port
|
||||
mov AL, 5h ; Floppy B
|
||||
out DX, AL
|
||||
ret
|
||||
|
||||
;*******************************
|
||||
;* RECALIBRATE DRIVE "A:" *
|
||||
;*******************************
|
||||
RecalibrateFDD:
|
||||
; dbgstr 'RecalibrateFDD'
|
||||
pusha
|
||||
call save_timer_fdd_motor
|
||||
; Clear the interrupt flag
|
||||
mov [FDD_IntFlag], 0
|
||||
; Send the "Recalibration" command
|
||||
mov AL, 07h
|
||||
call FDCDataOutput
|
||||
mov AL, [flp_number]
|
||||
dec AL
|
||||
call FDCDataOutput
|
||||
; Wait for the operation to complete
|
||||
call WaitFDCInterrupt
|
||||
cmp [FDC_Status], 0
|
||||
jne .fail
|
||||
; Read results of RECALIBRATE command
|
||||
; DEBUGF 1,'K : floppy recalibrate results:'
|
||||
mov al, 8
|
||||
call FDCDataOutput
|
||||
call FDCDataInput
|
||||
push eax
|
||||
; DEBUGF 1,' %x',al
|
||||
call FDCDataInput
|
||||
; DEBUGF 1,' %x',al
|
||||
; DEBUGF 1,'\n'
|
||||
pop eax
|
||||
test al, 0xC0
|
||||
jz @f
|
||||
mov [FDC_Status], FDC_DiskNotFound
|
||||
@@:
|
||||
.fail:
|
||||
call save_timer_fdd_motor
|
||||
popa
|
||||
ret
|
||||
|
||||
;*****************************************************
|
||||
;* TRACK SEARCH *
|
||||
;* Parameters are passed through global variables: *
|
||||
;* FDD_Track - track number (0-79); *
|
||||
;* FDD_Head - head number (0-1). *
|
||||
;* Result of operation is written to FDC_Status. *
|
||||
;*****************************************************
|
||||
SeekTrack:
|
||||
; dbgstr 'SeekTrack'
|
||||
pusha
|
||||
call save_timer_fdd_motor
|
||||
; Clear the interrupt flag
|
||||
mov [FDD_IntFlag], 0
|
||||
; Send "Search" command
|
||||
mov AL, 0Fh
|
||||
call FDCDataOutput
|
||||
; Send head / drive number byte
|
||||
mov AL, [FDD_Head]
|
||||
shl AL, 2
|
||||
call FDCDataOutput
|
||||
; Send track number byte
|
||||
mov AL, [FDD_Track]
|
||||
call FDCDataOutput
|
||||
; Wait for the operation to complete
|
||||
call WaitFDCInterrupt
|
||||
cmp [FDC_Status], FDC_Normal
|
||||
jne @@Exit
|
||||
; Save search result
|
||||
mov AL, 08h
|
||||
call FDCDataOutput
|
||||
call FDCDataInput
|
||||
mov [FDC_ST0], AL
|
||||
call FDCDataInput
|
||||
mov [FDC_C], AL
|
||||
; Check search result
|
||||
; Is search finished?
|
||||
test [FDC_ST0], 100000b
|
||||
je @@Err
|
||||
; Is the specified track found?
|
||||
mov AL, [FDC_C]
|
||||
cmp AL, [FDD_Track]
|
||||
jne @@Err
|
||||
; Does the head number match the specified one?
|
||||
; The H bit (Head Address) in ST0 will always return a "0" (c) 82077AA datasheet,
|
||||
; description of SEEK command. So we can not verify the proper head.
|
||||
; mov AL, [FDC_ST0]
|
||||
; and AL, 100b
|
||||
; shr AL, 2
|
||||
; cmp AL, [FDD_Head]
|
||||
; jne @@Err
|
||||
; Operation completed successfully
|
||||
; dbgstr 'SeekTrack: FDC_Normal'
|
||||
mov [FDC_Status], FDC_Normal
|
||||
jmp @@Exit
|
||||
@@Err: ; Track not found
|
||||
; dbgstr 'SeekTrack: FDC_TrackNotFound'
|
||||
mov [FDC_Status], FDC_TrackNotFound
|
||||
@@Exit:
|
||||
call save_timer_fdd_motor
|
||||
popa
|
||||
ret
|
||||
|
||||
;*******************************************************
|
||||
;* READING A DATA SECTOR *
|
||||
;* Parameters are passed through global variables: *
|
||||
;* FDD_Track - track number (0-79); *
|
||||
;* FDD_Head - head number (0-1); *
|
||||
;* FDD_Sector - sector number (1-18). *
|
||||
;* Result of operation is written to FDC_Status. *
|
||||
;* If the read operation is successful, the contents *
|
||||
;* of the sector will be written to FDD_DataBuffer. *
|
||||
;*******************************************************
|
||||
ReadSector:
|
||||
; dbgstr 'ReadSector'
|
||||
pushad
|
||||
call save_timer_fdd_motor
|
||||
; Clear the interrupt flag
|
||||
mov [FDD_IntFlag], 0
|
||||
; Set transmit speed to 500 Kb / s
|
||||
mov AX, 0
|
||||
mov DX, 03F7h
|
||||
out DX, AL
|
||||
; Initialize the DMA channel
|
||||
mov [dmamode], 0x46
|
||||
call Init_FDC_DMA
|
||||
; Send "Data read" command
|
||||
mov AL, 0E6h ; reading in multi-track mode
|
||||
call FDCDataOutput
|
||||
mov AL, [FDD_Head]
|
||||
shl AL, 2
|
||||
or AL, [flp_number]
|
||||
dec AL
|
||||
call FDCDataOutput
|
||||
mov AL, [FDD_Track]
|
||||
call FDCDataOutput
|
||||
mov AL, [FDD_Head]
|
||||
call FDCDataOutput
|
||||
mov AL, [FDD_Sector]
|
||||
call FDCDataOutput
|
||||
mov AL, 2 ; sector size code (512 byte)
|
||||
call FDCDataOutput
|
||||
mov AL, 18 ;+1; 3Fh ;number of sectors per track
|
||||
call FDCDataOutput
|
||||
mov AL, 1Bh ; GPL value
|
||||
call FDCDataOutput
|
||||
mov AL, 0FFh; DTL value
|
||||
call FDCDataOutput
|
||||
; Waiting for an interrupt at the end of the operation
|
||||
call WaitFDCInterrupt
|
||||
cmp [FDC_Status], FDC_Normal
|
||||
jne @@Exit_1
|
||||
; Read the operation completion status
|
||||
call GetStatusInfo
|
||||
test [FDC_ST0], 11011000b
|
||||
jnz @@Err_1
|
||||
; dbgstr 'ReadSector: FDC_Normal'
|
||||
mov [FDC_Status], FDC_Normal
|
||||
jmp @@Exit_1
|
||||
@@Err_1:
|
||||
; dbgstr 'ReadSector: FDC_SectorNotFound'
|
||||
mov [FDC_Status], FDC_SectorNotFound
|
||||
@@Exit_1:
|
||||
call save_timer_fdd_motor
|
||||
popad
|
||||
ret
|
||||
|
||||
;*******************************************************
|
||||
;* READ SECTOR (WITH RETRY OF OPERATION ON FAILURE) *
|
||||
;* Parameters are passed through global variables: *
|
||||
;* FDD_Track - track number (0-79); *
|
||||
;* FDD_Head - head number (0-1); *
|
||||
;* FDD_Sector - sector number (1-18). *
|
||||
;* Result of operation is written to FDC_Status. *
|
||||
;* If the read operation is successful, the contents *
|
||||
;* of the sector will be written to FDD_DataBuffer. *
|
||||
;*******************************************************
|
||||
ReadSectWithRetr:
|
||||
pusha
|
||||
; Reset the recalibration repetition counter
|
||||
mov [RecalRepCounter], 0
|
||||
@@TryAgain:
|
||||
; Reset the read operation retry counter
|
||||
mov [ReadRepCounter], 0
|
||||
@@ReadSector_1:
|
||||
call ReadSector
|
||||
cmp [FDC_Status], 0
|
||||
je @@Exit_2
|
||||
cmp [FDC_Status], 1
|
||||
je @@Err_3
|
||||
; Three times repeat reading
|
||||
inc [ReadRepCounter]
|
||||
cmp [ReadRepCounter], 3
|
||||
jb @@ReadSector_1
|
||||
; Three times repeat recalibration
|
||||
call RecalibrateFDD
|
||||
call SeekTrack
|
||||
inc [RecalRepCounter]
|
||||
cmp [RecalRepCounter], 3
|
||||
jb @@TryAgain
|
||||
@@Exit_2:
|
||||
popa
|
||||
ret
|
||||
@@Err_3:
|
||||
popa
|
||||
ret
|
||||
|
||||
;*******************************************************
|
||||
;* WRITE DATA SECTOR *
|
||||
;* Parameters are passed through global variables: *
|
||||
;* FDD_Track - track number (0-79); *
|
||||
;* FDD_Head - head number (0-1); *
|
||||
;* FDD_Sector - sector number (1-18). *
|
||||
;* Result of operation is written to FDC_Status. *
|
||||
;* If the write operation is successful, the contents *
|
||||
;* of FDD_DataBuffer will be written to the sector *
|
||||
;*******************************************************
|
||||
WriteSector:
|
||||
; dbgstr 'WriteSector'
|
||||
pushad
|
||||
call save_timer_fdd_motor
|
||||
; Clear the interrupt flag
|
||||
mov [FDD_IntFlag], 0
|
||||
; Set transmit speed to 500 Kb / s
|
||||
mov AX, 0
|
||||
mov DX, 03F7h
|
||||
out DX, AL
|
||||
; Initialize the DMA channel
|
||||
mov [dmamode], 0x4A
|
||||
call Init_FDC_DMA
|
||||
; Send "Write data" command
|
||||
mov AL, 0xC5 ;0x45 ; write in multi-track mode
|
||||
call FDCDataOutput
|
||||
mov AL, [FDD_Head]
|
||||
shl AL, 2
|
||||
or AL, [flp_number]
|
||||
dec AL
|
||||
call FDCDataOutput
|
||||
mov AL, [FDD_Track]
|
||||
call FDCDataOutput
|
||||
mov AL, [FDD_Head]
|
||||
call FDCDataOutput
|
||||
mov AL, [FDD_Sector]
|
||||
call FDCDataOutput
|
||||
mov AL, 2 ; sector size code (512 bytes)
|
||||
call FDCDataOutput
|
||||
mov AL, 18; 3Fh ; sectors per track
|
||||
call FDCDataOutput
|
||||
mov AL, 1Bh ; GPL value
|
||||
call FDCDataOutput
|
||||
mov AL, 0FFh; DTL value
|
||||
call FDCDataOutput
|
||||
; Waiting for an interrupt at the end of the operation
|
||||
call WaitFDCInterrupt
|
||||
cmp [FDC_Status], FDC_Normal
|
||||
jne @@Exit_3
|
||||
; Reading the completion status of the operation
|
||||
call GetStatusInfo
|
||||
test [FDC_ST0], 11000000b ;11011000b
|
||||
jnz @@Err_2
|
||||
mov [FDC_Status], FDC_Normal
|
||||
jmp @@Exit_3
|
||||
@@Err_2:
|
||||
mov [FDC_Status], FDC_SectorNotFound
|
||||
@@Exit_3:
|
||||
call save_timer_fdd_motor
|
||||
popad
|
||||
ret
|
||||
|
||||
;*******************************************************
|
||||
;* WRITE SECTOR (WITH REPEAT ON FAILURE) *
|
||||
;* Parameters are passed through global variables: *
|
||||
;* FDD_Track - track number (0-79); *
|
||||
;* FDD_Head - head number (0-1); *
|
||||
;* FDD_Sector - sector number (1-18). *
|
||||
;* Result of operation is written to FDC_Status. *
|
||||
;* If the write operation is successful, the contents *
|
||||
;* of FDD_DataBuffer will be written to the sector *
|
||||
;*******************************************************
|
||||
WriteSectWithRetr:
|
||||
pusha
|
||||
; Reset the recalibration repetition counter
|
||||
mov [RecalRepCounter], 0
|
||||
@@TryAgain_1:
|
||||
; Reset the read operation retry counter
|
||||
mov [ReadRepCounter], 0
|
||||
@@WriteSector_1:
|
||||
call WriteSector
|
||||
cmp [FDC_Status], 0
|
||||
je @@Exit_4
|
||||
cmp [FDC_Status], 1
|
||||
je @@Err_4
|
||||
; Three times repeat writing
|
||||
inc [ReadRepCounter]
|
||||
cmp [ReadRepCounter], 3
|
||||
jb @@WriteSector_1
|
||||
; Three times repeat recalibration
|
||||
call RecalibrateFDD
|
||||
call SeekTrack
|
||||
inc [RecalRepCounter]
|
||||
cmp [RecalRepCounter], 3
|
||||
jb @@TryAgain_1
|
||||
@@Exit_4:
|
||||
popa
|
||||
ret
|
||||
@@Err_4:
|
||||
popa
|
||||
ret
|
||||
|
||||
;*********************************************
|
||||
;* GET INFORMATION ABOUT THE RESULT OF THE OPERATION
|
||||
;*********************************************
|
||||
GetStatusInfo:
|
||||
push AX
|
||||
call FDCDataInput
|
||||
mov [FDC_ST0], AL
|
||||
call FDCDataInput
|
||||
mov [FDC_ST1], AL
|
||||
call FDCDataInput
|
||||
mov [FDC_ST2], AL
|
||||
call FDCDataInput
|
||||
mov [FDC_C], AL
|
||||
call FDCDataInput
|
||||
mov [FDC_H], AL
|
||||
call FDCDataInput
|
||||
mov [FDC_R], AL
|
||||
call FDCDataInput
|
||||
mov [FDC_N], AL
|
||||
pop AX
|
||||
ret
|
||||
|
||||
; Interface for disk subsystem.
|
||||
; Assume fixed capacity for 1.44M.
|
||||
FLOPPY_CAPACITY = 2880 ; in sectors
|
||||
|
||||
iglobal
|
||||
align 4
|
||||
floppy_functions:
|
||||
dd .size
|
||||
dd 0 ; no close() function
|
||||
dd 0 ; no closemedia() function
|
||||
dd floppy_querymedia
|
||||
dd floppy_read
|
||||
dd floppy_write
|
||||
dd 0 ; no flush() function
|
||||
dd 0 ; no adjust_cache_size() function
|
||||
.size = $ - floppy_functions
|
||||
endg
|
||||
|
||||
uglobal
|
||||
floppy_media_flags rb 2
|
||||
n_sector dd 0 ; temporary save for sector value
|
||||
flp_number db 0 ; 1- Floppy A, 2-Floppy B
|
||||
old_track db 0 ; old value track
|
||||
flp_label rb 15*2 ; Label and ID of inserted floppy disk
|
||||
align 4
|
||||
; Hardware does not allow to work with two floppies in parallel,
|
||||
; so there is one mutex guarding access to any floppy.
|
||||
floppy_mutex MUTEX
|
||||
endg
|
||||
; Meaning of bits in floppy_media_flags
|
||||
FLOPPY_MEDIA_PRESENT = 1 ; media was present when last asked
|
||||
FLOPPY_MEDIA_NEED_RESCAN = 2 ; media was possibly changed, need to rescan
|
||||
FLOPPY_MEDIA_LABEL_CHANGED = 4 ; temporary state
|
||||
|
||||
iglobal
|
||||
floppy1_name db 'fd',0
|
||||
floppy2_name db 'fd2',0
|
||||
endg
|
||||
|
||||
; This function is called in boot process.
|
||||
; It creates filesystems /fd and/or /fd2, if the system has one/two floppy drives.
|
||||
proc floppy_init
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_init
|
||||
; First floppy is present if [DRIVE_DATA] and 0xF0 is nonzero.
|
||||
test byte [DRIVE_DATA], 0xF0
|
||||
jz .no1
|
||||
stdcall disk_add, floppy_functions, floppy1_name, 1, DISK_NO_INSERT_NOTIFICATION
|
||||
.no1:
|
||||
; Second floppy is present if [DRIVE_DATA] and 0x0F is nonzero.
|
||||
test byte [DRIVE_DATA], 0x0F
|
||||
jz .no2
|
||||
stdcall disk_add, floppy_functions, floppy2_name, 2, DISK_NO_INSERT_NOTIFICATION
|
||||
.no2:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Returns information about disk media.
|
||||
; Floppy drives do not support insert notifications,
|
||||
; DISK_NO_INSERT_NOTIFICATION is set,
|
||||
; the disk subsystem calls this function before each filesystem operation.
|
||||
; If the media has changed, return error for the first call as signal
|
||||
; to finalize work with old media and the true geometry for the second call.
|
||||
; Assume that media is (possibly) changed anytime when motor is off.
|
||||
proc floppy_querymedia
|
||||
virtual at esp+4
|
||||
.userdata dd ?
|
||||
.info dd ?
|
||||
end virtual
|
||||
; 1. Acquire the global lock.
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_lock
|
||||
mov edx, [.userdata] ; 1 for /fd, 2 for /fd2
|
||||
; 2. If the media was reported and has been changed, forget it and report an error.
|
||||
mov al, [floppy_media_flags+edx-1]
|
||||
and al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
|
||||
cmp al, FLOPPY_MEDIA_PRESENT + FLOPPY_MEDIA_NEED_RESCAN
|
||||
jnz .not_reported
|
||||
.no_media:
|
||||
mov [floppy_media_flags+edx-1], 0
|
||||
.return_no_media:
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_unlock
|
||||
mov eax, DISK_STATUS_NO_MEDIA
|
||||
retn 8
|
||||
.not_reported:
|
||||
; 3. If we are in the temporary state LABEL_CHANGED, this is the second call
|
||||
; after intermediate DISK_STATUS_NO_MEDIA due to media change;
|
||||
; clear the flag and return the current geometry without rereading the bootsector.
|
||||
cmp [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
|
||||
jz .report_geometry
|
||||
; 4. Try to read the bootsector.
|
||||
mov [flp_number], dl
|
||||
mov [FDC_Status], 0
|
||||
call floppy_read_bootsector
|
||||
; 5. If reading bootsector failed, assume that media is not present.
|
||||
mov edx, [.userdata]
|
||||
cmp [FDC_Status], 0
|
||||
jnz .no_media
|
||||
; 6. Check whether the previous status is "present". If not, go to 10.
|
||||
push esi edi
|
||||
imul edi, edx, 15
|
||||
add edi, flp_label-15
|
||||
mov esi, FDD_BUFF+39
|
||||
mov ecx, 15
|
||||
test [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
|
||||
jz .set_label
|
||||
; 7. Compare the old label with the current one.
|
||||
rep cmpsb
|
||||
; 8. If the label has not changed, go to 11.
|
||||
jz .ok
|
||||
; 9. If the label has changed, store it, enter temporary state LABEL_CHANGED
|
||||
; and report DISK_STATUS_NO_MEDIA.
|
||||
; dbgstr 'floppy label changed'
|
||||
add esi, ecx
|
||||
add edi, ecx
|
||||
mov ecx, 15
|
||||
sub esi, ecx
|
||||
sub edi, ecx
|
||||
rep movsb
|
||||
mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_LABEL_CHANGED
|
||||
pop edi esi
|
||||
jmp .return_no_media
|
||||
.set_label:
|
||||
; 10. The previous state was "not present". Copy the label.
|
||||
rep movsb
|
||||
.ok:
|
||||
pop edi esi
|
||||
.report_geometry:
|
||||
; 11. Fill DISKMEDIAINFO structure.
|
||||
mov ecx, [.info]
|
||||
and [ecx+DISKMEDIAINFO.Flags], 0
|
||||
mov [ecx+DISKMEDIAINFO.SectorSize], 512
|
||||
mov dword [ecx+DISKMEDIAINFO.Capacity], FLOPPY_CAPACITY
|
||||
and dword [ecx+DISKMEDIAINFO.Capacity+4], 0
|
||||
; 12. Update state: media is present, data are actual.
|
||||
mov [floppy_media_flags+edx-1], FLOPPY_MEDIA_PRESENT
|
||||
; 13. Release the global lock and return successful status.
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
retn 8
|
||||
endp
|
||||
|
||||
proc floppy_read_bootsector
|
||||
pushad
|
||||
mov [FDD_Track], 0 ; Cylinder
|
||||
mov [FDD_Head], 0 ; Head
|
||||
mov [FDD_Sector], 1 ; Sector
|
||||
call FDDMotorON
|
||||
call RecalibrateFDD
|
||||
cmp [FDC_Status], 0
|
||||
jne .nothing
|
||||
call SeekTrack
|
||||
cmp [FDC_Status], 0
|
||||
jne .nothing
|
||||
call ReadSectWithRetr
|
||||
.nothing:
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
read_chs_sector:
|
||||
call calculate_chs
|
||||
call ReadSectWithRetr
|
||||
ret
|
||||
|
||||
save_chs_sector:
|
||||
call calculate_chs
|
||||
call WriteSectWithRetr
|
||||
ret
|
||||
|
||||
calculate_chs:
|
||||
mov bl, [FDD_Track]
|
||||
mov [old_track], bl
|
||||
mov ebx, 18
|
||||
xor edx, edx
|
||||
div ebx
|
||||
inc edx
|
||||
mov [FDD_Sector], dl
|
||||
mov edx, eax
|
||||
shr eax, 1
|
||||
and edx, 1
|
||||
mov [FDD_Track], al
|
||||
mov [FDD_Head], dl
|
||||
mov dl, [old_track]
|
||||
cmp dl, [FDD_Track]
|
||||
je no_seek_track_1
|
||||
call SeekTrack
|
||||
no_seek_track_1:
|
||||
ret
|
||||
|
||||
; Writes one or more sectors to the device.
|
||||
proc floppy_write
|
||||
mov dl, 1
|
||||
jmp floppy_read_write
|
||||
endp
|
||||
|
||||
; Reads one or more sectors from the device.
|
||||
proc floppy_read
|
||||
mov dl, 0
|
||||
endp
|
||||
|
||||
; Common part of floppy_read and floppy_write.
|
||||
proc floppy_read_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
|
||||
virtual at ebp-8
|
||||
.sectors_todo dd ?
|
||||
.operation db ?
|
||||
end virtual
|
||||
push edx ; save operation code to [.operation]
|
||||
; 1. Get number of sectors to read/write
|
||||
; and zero number of sectors that were actually read/written.
|
||||
mov eax, [numsectors_ptr]
|
||||
push dword [eax] ; initialize [.sectors_todo]
|
||||
and dword [eax], 0
|
||||
push ebx esi edi ; save used registers to be stdcall
|
||||
; 2. Acquire the global lock.
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_lock
|
||||
; 3. Set floppy number for this operation.
|
||||
mov edx, [userdata]
|
||||
mov [flp_number], dl
|
||||
; 4. Read/write sector-by-sector.
|
||||
.operation_loop:
|
||||
; 4a. Check that the sector is inside the media.
|
||||
cmp dword [start_sector+4], 0
|
||||
jnz .end_of_media
|
||||
mov eax, dword [start_sector]
|
||||
cmp eax, FLOPPY_CAPACITY
|
||||
jae .end_of_media
|
||||
; 4b. For read operation, call read_chs_sector and then move data from FDD_BUFF to [buffer].
|
||||
; For write operation, move data from [buffer] to FDD_BUFF and then call save_chs_sector.
|
||||
cmp [.operation], 0
|
||||
jz .read
|
||||
mov esi, [buffer]
|
||||
mov edi, FDD_BUFF
|
||||
mov ecx, 512/4
|
||||
rep movsd
|
||||
mov [buffer], esi
|
||||
call save_chs_sector
|
||||
jmp @f
|
||||
.read:
|
||||
call read_chs_sector
|
||||
mov esi, FDD_BUFF
|
||||
mov edi, [buffer]
|
||||
mov ecx, 512/4
|
||||
rep movsd
|
||||
mov [buffer], edi
|
||||
@@:
|
||||
; 4c. If there was an error, propagate it to the caller.
|
||||
cmp [FDC_Status], 0
|
||||
jnz .fail
|
||||
; 4d. Otherwise, increment number of sectors processed and continue the loop.
|
||||
mov eax, [numsectors_ptr]
|
||||
inc dword [eax]
|
||||
inc dword [start_sector]
|
||||
dec [.sectors_todo]
|
||||
jnz .operation_loop
|
||||
; 5. Release the global lock and return with the correct status.
|
||||
push 0
|
||||
.return:
|
||||
mov ecx, floppy_mutex
|
||||
call mutex_unlock
|
||||
pop eax
|
||||
pop edi esi ebx ; restore used registers to be stdcall
|
||||
ret ; this translates to leave/retn N and purges local variables
|
||||
.fail:
|
||||
push -1
|
||||
jmp .return
|
||||
.end_of_media:
|
||||
push DISK_STATUS_END_OF_MEDIA
|
||||
jmp .return
|
||||
endp
|
||||
568
kernel/branches/kolibri-lldw/blkdev/hd_drv.inc
Normal file
568
kernel/branches/kolibri-lldw/blkdev/hd_drv.inc
Normal file
@@ -0,0 +1,568 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
; HDD driver
|
||||
|
||||
struct HD_DATA
|
||||
hdpos dw ?
|
||||
hdid dw ?
|
||||
hdbase dw ?
|
||||
hd48 dw ?
|
||||
sectors dq ?
|
||||
ends
|
||||
;-----------------------------------------------------------------
|
||||
iglobal
|
||||
align 4
|
||||
ide_callbacks:
|
||||
dd ide_callbacks.end - ide_callbacks
|
||||
dd 0 ; no close function
|
||||
dd 0 ; no closemedia function
|
||||
dd ide_querymedia
|
||||
dd ide_read
|
||||
dd ide_write
|
||||
dd 0 ; no flush function
|
||||
dd 0 ; use default cache size
|
||||
.end:
|
||||
|
||||
hd0_data HD_DATA 1, 0
|
||||
hd1_data HD_DATA 2, 16
|
||||
hd2_data HD_DATA 3, 0
|
||||
hd3_data HD_DATA 4, 16
|
||||
hd4_data HD_DATA 5, 0
|
||||
hd5_data HD_DATA 6, 16
|
||||
hd6_data HD_DATA 7, 0
|
||||
hd7_data HD_DATA 8, 16
|
||||
hd8_data HD_DATA 9, 0
|
||||
hd9_data HD_DATA 10, 16
|
||||
hd10_data HD_DATA 11, 0
|
||||
hd11_data HD_DATA 12, 16
|
||||
|
||||
ide_mutex_table:
|
||||
dd ide_channel1_mutex
|
||||
dd ide_channel2_mutex
|
||||
dd ide_channel3_mutex
|
||||
dd ide_channel4_mutex
|
||||
dd ide_channel5_mutex
|
||||
dd ide_channel6_mutex
|
||||
endg
|
||||
;-----------------------------------------------------------------
|
||||
uglobal
|
||||
ide_mutex MUTEX
|
||||
ide_channel1_mutex MUTEX
|
||||
ide_channel2_mutex MUTEX
|
||||
ide_channel3_mutex MUTEX
|
||||
ide_channel4_mutex MUTEX
|
||||
ide_channel5_mutex MUTEX
|
||||
ide_channel6_mutex MUTEX
|
||||
blockSize:
|
||||
rb 4
|
||||
sector:
|
||||
rb 6
|
||||
allow_dma_access db ?
|
||||
IDE_common_irq_param db ?
|
||||
eventPointer dd ?
|
||||
eventID dd ?
|
||||
endg
|
||||
;-----------------------------------------------------------------
|
||||
ide_read:
|
||||
mov al, 25h ; READ DMA EXT
|
||||
jmp ide_read_write
|
||||
|
||||
ide_write:
|
||||
mov al, 35h ; WRITE DMA EXT
|
||||
proc ide_read_write stdcall uses esi edi ebx, \
|
||||
hd_data, buffer, startsector:qword, numsectors
|
||||
; hd_data = pointer to hd*_data
|
||||
; buffer = pointer to buffer with/for data
|
||||
; startsector = 64-bit start sector
|
||||
; numsectors = pointer to number of sectors on input,
|
||||
; must be filled with number of sectors really read/written
|
||||
locals
|
||||
sectors_todo dd ?
|
||||
channel_lock dd ?
|
||||
endl
|
||||
mov bl, al
|
||||
; get number of requested sectors and say that no sectors were read yet
|
||||
mov ecx, [numsectors]
|
||||
mov eax, [ecx]
|
||||
mov dword [ecx], 0
|
||||
mov [sectors_todo], eax
|
||||
; acquire the global lock
|
||||
mov ecx, ide_mutex
|
||||
call mutex_lock
|
||||
mov ecx, [hd_data]
|
||||
movzx ecx, [ecx+HD_DATA.hdpos]
|
||||
dec ecx
|
||||
shr ecx, 1
|
||||
shl ecx, 2
|
||||
mov ecx, [ecx + ide_mutex_table]
|
||||
mov [channel_lock], ecx
|
||||
call mutex_lock
|
||||
; prepare worker procedures variables
|
||||
mov esi, [buffer]
|
||||
mov edi, esi
|
||||
mov ecx, [hd_data]
|
||||
movzx eax, [ecx+HD_DATA.hdbase]
|
||||
mov [hdbase], eax
|
||||
mov ax, [ecx+HD_DATA.hdid]
|
||||
mov [hdid], eax
|
||||
mov eax, dword [startsector]
|
||||
mov [sector], eax
|
||||
cmp [ecx+HD_DATA.hd48], 0
|
||||
jz .LBA28
|
||||
mov ax, word [startsector+4]
|
||||
mov [sector+4], ax
|
||||
movzx ecx, [ecx+HD_DATA.hdpos]
|
||||
mov [hdpos], ecx
|
||||
dec ecx
|
||||
shr ecx, 2
|
||||
imul ecx, sizeof.IDE_DATA
|
||||
add ecx, IDE_controller_1
|
||||
mov [IDE_controller_pointer], ecx
|
||||
mov eax, [hdpos]
|
||||
dec eax
|
||||
and eax, 11b
|
||||
shr eax, 1
|
||||
add eax, ecx
|
||||
cmp [eax+IDE_DATA.dma_hdd_channel_1], 1
|
||||
jz .next
|
||||
dec ebx ; READ/WRITE SECTOR(S) EXT
|
||||
; LBA48 supports max 10000h sectors per time
|
||||
; loop until all sectors will be processed
|
||||
.next:
|
||||
mov ecx, 8000h
|
||||
cmp ecx, [sectors_todo]
|
||||
jbe @f
|
||||
mov ecx, [sectors_todo]
|
||||
@@:
|
||||
mov [blockSize], ecx
|
||||
push ecx
|
||||
call IDE_transfer
|
||||
pop ecx
|
||||
jc .out
|
||||
mov eax, [numsectors]
|
||||
add [eax], ecx
|
||||
sub [sectors_todo], ecx
|
||||
jz .out
|
||||
add [sector], ecx
|
||||
adc word [sector+4], 0
|
||||
jmp .next
|
||||
|
||||
.LBA28:
|
||||
add eax, [sectors_todo]
|
||||
add eax, 0xF0000000
|
||||
jc .out
|
||||
sub bl, 5 ; READ/WRITE SECTOR(S)
|
||||
; LBA28 supports max 256 sectors per time
|
||||
; loop until all sectors will be processed
|
||||
.next28:
|
||||
mov ecx, 256
|
||||
cmp ecx, [sectors_todo]
|
||||
jbe @f
|
||||
mov ecx, [sectors_todo]
|
||||
@@:
|
||||
mov [blockSize], ecx
|
||||
push ecx
|
||||
call IDE_transfer.LBA28
|
||||
pop ecx
|
||||
jc .out
|
||||
mov eax, [numsectors]
|
||||
add [eax], ecx
|
||||
sub [sectors_todo], ecx
|
||||
jz .out
|
||||
add [sector], ecx
|
||||
jmp .next28
|
||||
|
||||
; loop is done, either due to error or because everything is done
|
||||
; release the global lock and return the corresponding status
|
||||
.out:
|
||||
sbb eax, eax
|
||||
push eax
|
||||
mov ecx, [channel_lock]
|
||||
call mutex_unlock
|
||||
mov ecx, ide_mutex
|
||||
call mutex_unlock
|
||||
pop eax
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------
|
||||
proc ide_querymedia stdcall, hd_data, mediainfo
|
||||
mov eax, [mediainfo]
|
||||
mov edx, [hd_data]
|
||||
mov [eax+DISKMEDIAINFO.Flags], 0
|
||||
mov [eax+DISKMEDIAINFO.SectorSize], 512
|
||||
mov ecx, dword[edx+HD_DATA.sectors]
|
||||
mov dword[eax+DISKMEDIAINFO.Capacity], ecx
|
||||
mov ecx, dword[edx+HD_DATA.sectors+4]
|
||||
mov dword[eax+DISKMEDIAINFO.Capacity+4], ecx
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
;-----------------------------------------------------------------
|
||||
; input: esi -> buffer, bl = command, [sector], [blockSize]
|
||||
; output: esi -> next block in buffer
|
||||
; for pio read esi equal edi
|
||||
IDE_transfer:
|
||||
mov edx, [hdbase]
|
||||
add edx, 6
|
||||
mov al, byte [hdid]
|
||||
add al, 224
|
||||
out dx, al ; select the desired drive
|
||||
call save_hd_wait_timeout
|
||||
inc edx
|
||||
@@:
|
||||
call check_hd_wait_timeout
|
||||
jc .hd_error
|
||||
in al, dx
|
||||
test al, 128 ; ready for command?
|
||||
jnz @b
|
||||
pushfd ; fill the ports
|
||||
cli
|
||||
mov edx, [hdbase]
|
||||
inc edx
|
||||
inc edx
|
||||
mov al, [blockSize+1]
|
||||
out dx, al ; Sector count (15:8)
|
||||
inc edx
|
||||
mov eax, [sector+3]
|
||||
out dx, al ; LBA (31:24)
|
||||
inc edx
|
||||
shr eax, 8
|
||||
out dx, al ; LBA (39:32)
|
||||
inc edx
|
||||
shr eax, 8
|
||||
out dx, al ; LBA (47:40)
|
||||
sub edx, 3
|
||||
mov al, [blockSize]
|
||||
out dx, al ; Sector count (7:0)
|
||||
inc edx
|
||||
mov eax, [sector]
|
||||
out dx, al ; LBA (7:0)
|
||||
inc edx
|
||||
shr eax, 8
|
||||
out dx, al ; LBA (15:8)
|
||||
inc edx
|
||||
shr eax, 8
|
||||
out dx, al ; LBA (23:16)
|
||||
inc edx
|
||||
mov al, byte [hdid]
|
||||
add al, 224
|
||||
out dx, al
|
||||
test bl, 1
|
||||
jz .PIO
|
||||
; DMA
|
||||
mov dword [esp], 0x1000
|
||||
call kernel_alloc
|
||||
mov edi, eax
|
||||
push eax
|
||||
shl dword [blockSize], 9
|
||||
mov eax, esi
|
||||
add eax, [blockSize]
|
||||
push eax
|
||||
; check buffer pages physical addresses and fill the scatter-gather list
|
||||
; buffer may be not aligned and may have size not divisible by page size
|
||||
; [edi] = block physical address, [edi+4] = block size in bytes
|
||||
; block addresses can not cross 10000h borders
|
||||
mov ecx, esi
|
||||
and ecx, 0xFFF
|
||||
jz .aligned
|
||||
mov eax, esi
|
||||
call get_pg_addr
|
||||
add eax, ecx
|
||||
neg ecx
|
||||
add ecx, 0x1000
|
||||
mov [edi], eax
|
||||
cmp ecx, [blockSize]
|
||||
jnc .end
|
||||
mov [edi+4], ecx
|
||||
add esi, 0x1000
|
||||
add edi, 8
|
||||
sub [blockSize], ecx
|
||||
.aligned:
|
||||
mov eax, esi
|
||||
call get_pg_addr
|
||||
mov ecx, eax
|
||||
mov [edi], eax
|
||||
and ecx, 0xFFFF
|
||||
neg ecx
|
||||
add ecx, 0x10000
|
||||
cmp [blockSize], ecx
|
||||
jnc @f
|
||||
mov ecx, [blockSize]
|
||||
and ecx, 0xF000
|
||||
jz .end
|
||||
@@:
|
||||
push ecx
|
||||
@@:
|
||||
add esi, 0x1000
|
||||
add eax, 0x1000
|
||||
sub ecx, 0x1000
|
||||
jz @f
|
||||
mov edx, eax
|
||||
mov eax, esi
|
||||
call get_pg_addr
|
||||
cmp eax, edx
|
||||
jz @b
|
||||
@@:
|
||||
pop edx
|
||||
sub edx, ecx
|
||||
mov [edi+4], edx
|
||||
add edi, 8
|
||||
sub [blockSize], edx
|
||||
jnz .aligned
|
||||
sub edi, 8
|
||||
jmp @f
|
||||
|
||||
.end:
|
||||
mov ecx, [blockSize]
|
||||
mov [edi+4], ecx
|
||||
@@:
|
||||
mov byte [edi+7], 80h ; list end
|
||||
pop esi
|
||||
pop edi
|
||||
; select controller Primary or Secondary
|
||||
mov ecx, [IDE_controller_pointer]
|
||||
mov dx, [ecx+IDE_DATA.RegsBaseAddres]
|
||||
mov eax, [hdpos]
|
||||
dec eax
|
||||
test eax, 10b
|
||||
jz @f
|
||||
add edx, 8
|
||||
@@:
|
||||
add edx, 2 ; Bus Master IDE Status register
|
||||
mov al, 6
|
||||
out dx, al ; clear Error bit and Interrupt bit
|
||||
|
||||
add edx, 2 ; Bus Master IDE PRD Table Address
|
||||
mov eax, edi
|
||||
call get_pg_addr
|
||||
out dx, eax ; send scatter-gather list physical address
|
||||
|
||||
push edx
|
||||
mov edx, [hdbase]
|
||||
add edx, 7 ; ATACommand
|
||||
mov al, bl
|
||||
out dx, al ; Start hard drive
|
||||
pop edx
|
||||
|
||||
sub edx, 4 ; Bus Master IDE Command register
|
||||
mov al, 1 ; set direction
|
||||
cmp bl, 35h ; write
|
||||
jz @f
|
||||
add al, 8 ; read
|
||||
@@:
|
||||
out dx, al ; Start Bus Master
|
||||
mov [IDE_common_irq_param], 14
|
||||
mov eax, [hdpos]
|
||||
dec eax
|
||||
test eax, 10b
|
||||
jz @f
|
||||
inc [IDE_common_irq_param]
|
||||
@@:
|
||||
push edi esi ebx
|
||||
xor ecx, ecx
|
||||
xor esi, esi
|
||||
call create_event
|
||||
mov [eventPointer], eax
|
||||
mov [eventID], edx
|
||||
sti
|
||||
mov ebx, edx
|
||||
mov ecx, 300
|
||||
call wait_event_timeout
|
||||
test eax, eax
|
||||
jnz @f
|
||||
dbgstr 'IDE DMA IRQ timeout'
|
||||
mov [IDE_common_irq_param], 0
|
||||
mov eax, [eventPointer]
|
||||
mov ebx, [eventID]
|
||||
call destroy_event
|
||||
mov [eventPointer], 0
|
||||
@@:
|
||||
pop ebx esi
|
||||
call kernel_free
|
||||
cmp [eventPointer], 0
|
||||
jz .hd_error
|
||||
ret
|
||||
|
||||
.LBA28:
|
||||
mov edx, [hdbase]
|
||||
add edx, 6
|
||||
mov al, byte [hdid]
|
||||
add al, 224
|
||||
out dx, al ; select the desired drive
|
||||
call save_hd_wait_timeout
|
||||
inc edx
|
||||
@@:
|
||||
call check_hd_wait_timeout
|
||||
jc .hd_error
|
||||
in al, dx
|
||||
test al, 128 ; ready for command?
|
||||
jnz @b
|
||||
pushfd ; fill the ports
|
||||
cli
|
||||
mov edx, [hdbase]
|
||||
inc edx
|
||||
inc edx
|
||||
mov al, [blockSize]
|
||||
out dx, al ; Sector count (7:0)
|
||||
inc edx
|
||||
mov eax, [sector]
|
||||
out dx, al ; LBA (7:0)
|
||||
inc edx
|
||||
shr eax, 8
|
||||
out dx, al ; LBA (15:8)
|
||||
inc edx
|
||||
shr eax, 8
|
||||
out dx, al ; LBA (23:16)
|
||||
inc edx
|
||||
shr eax, 8
|
||||
add al, byte [hdid]
|
||||
add al, 224
|
||||
out dx, al ; LBA (27:24)
|
||||
.PIO:
|
||||
inc edx ; ATACommand
|
||||
mov al, bl
|
||||
out dx, al ; Start hard drive
|
||||
popfd
|
||||
.sectorTransfer:
|
||||
call save_hd_wait_timeout
|
||||
in al, dx
|
||||
in al, dx
|
||||
in al, dx
|
||||
in al, dx
|
||||
@@:
|
||||
call check_hd_wait_timeout
|
||||
jc .hd_error
|
||||
in al, dx
|
||||
test al, 8 ; ready for transfer?
|
||||
jz @b
|
||||
cmp [hd_setup], 1 ; do not mark error for setup request
|
||||
jz @f
|
||||
test al, 1 ; previous command ended up with an error
|
||||
jnz .pio_error
|
||||
@@:
|
||||
pushfd
|
||||
cli
|
||||
cld
|
||||
mov ecx, 256
|
||||
mov edx, [hdbase]
|
||||
cmp bl, 30h
|
||||
jnc .write
|
||||
rep insw
|
||||
jmp @f
|
||||
|
||||
.write:
|
||||
rep outsw
|
||||
@@:
|
||||
popfd
|
||||
add edx, 7
|
||||
dec dword [blockSize]
|
||||
jnz .sectorTransfer
|
||||
ret
|
||||
|
||||
.pio_error:
|
||||
dbgstr 'IDE PIO transfer error'
|
||||
.hd_error:
|
||||
cmp bl, 30h
|
||||
jnc hd_write_error
|
||||
;-----------------------------------------------------------------
|
||||
hd_read_error:
|
||||
dbgstr 'HD read error'
|
||||
stc
|
||||
ret
|
||||
;-----------------------------------------------------------------
|
||||
hd_write_error:
|
||||
dbgstr 'HD write error'
|
||||
stc
|
||||
ret
|
||||
;-----------------------------------------------------------------
|
||||
save_hd_wait_timeout:
|
||||
mov eax, [timer_ticks]
|
||||
add eax, 300 ; 3 sec timeout
|
||||
mov [hd_wait_timeout], eax
|
||||
ret
|
||||
;-----------------------------------------------------------------
|
||||
check_hd_wait_timeout:
|
||||
mov eax, [timer_ticks]
|
||||
cmp [hd_wait_timeout], eax
|
||||
jc @f
|
||||
ret
|
||||
|
||||
@@:
|
||||
dbgstr 'IDE device timeout'
|
||||
stc
|
||||
ret
|
||||
;-----------------------------------------------------------------
|
||||
align 4
|
||||
IDE_irq_14_handler:
|
||||
IDE_irq_15_handler:
|
||||
IDE_common_irq_handler:
|
||||
; Most of the time, we are here because we have requested
|
||||
; a DMA transfer for the corresponding drive.
|
||||
; However,
|
||||
; a) we can be here because IDE IRQ is shared with some other device,
|
||||
; that device has actually raised IRQ,
|
||||
; it has nothing to do with IDE;
|
||||
; b) we can be here because IDE controller just does not want
|
||||
; to be silent and reacts to something even though
|
||||
; we have, in theory, disabled IRQs.
|
||||
; If the interrupt corresponds to our current request,
|
||||
; remove the interrupt request and raise the event for the waiting code.
|
||||
; In the case a), just return zero - not our interrupt.
|
||||
; In the case b), remove the interrupt request and hope for the best.
|
||||
; DEBUGF 1, 'K : IDE_irq_handler %x\n', [IDE_common_irq_param]:2
|
||||
mov ecx, [esp+4]
|
||||
mov dx, [ecx+IDE_DATA.RegsBaseAddres]
|
||||
add edx, 2 ; Bus Master IDE Status register
|
||||
in al, dx
|
||||
test al, 4
|
||||
jnz .interrupt_from_primary
|
||||
add edx, 8
|
||||
in al, dx
|
||||
test al, 4
|
||||
jnz .interrupt_from_secondary
|
||||
xor eax, eax ; not our interrupt
|
||||
ret
|
||||
|
||||
.interrupt_from_primary:
|
||||
out dx, al ; clear Interrupt bit
|
||||
sub edx, 2
|
||||
xor eax, eax
|
||||
out dx, al ; clear Bus Master IDE Command register
|
||||
mov dx, [ecx+IDE_DATA.BAR0_val]
|
||||
add edx, 7
|
||||
in al, dx ; read status register
|
||||
cmp [IDE_common_irq_param], 14
|
||||
jz .raise
|
||||
.exit_our:
|
||||
mov al, 1
|
||||
ret
|
||||
|
||||
.interrupt_from_secondary:
|
||||
out dx, al ; clear Interrupt bit
|
||||
sub edx, 2
|
||||
xor eax, eax
|
||||
out dx, al ; clear Bus Master IDE Command register
|
||||
mov dx, [ecx+IDE_DATA.BAR2_val]
|
||||
add edx, 7
|
||||
in al, dx ; read status register
|
||||
cmp [IDE_common_irq_param], 15
|
||||
jnz .exit_our
|
||||
.raise:
|
||||
cmp ecx, [IDE_controller_pointer]
|
||||
jnz .exit_our
|
||||
pushad
|
||||
mov eax, [eventPointer]
|
||||
mov ebx, [eventID]
|
||||
xor edx, edx
|
||||
xor esi, esi
|
||||
call raise_event
|
||||
popad
|
||||
mov al, 1 ; remove the interrupt request
|
||||
ret
|
||||
202
kernel/branches/kolibri-lldw/blkdev/ide_cache.inc
Normal file
202
kernel/branches/kolibri-lldw/blkdev/ide_cache.inc
Normal file
@@ -0,0 +1,202 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;**************************************************************************
|
||||
;
|
||||
; [cache_ide[X]_pointer]
|
||||
; or [cache_ide[X]_data_pointer] first entry in cache list
|
||||
;
|
||||
; +0 - lba sector
|
||||
; +4 - state of cache sector
|
||||
; 0 = empty
|
||||
; 1 = used for read ( same as in hd )
|
||||
; 2 = used for write ( differs from hd )
|
||||
;
|
||||
; [cache_ide[X]_system_data]
|
||||
; or [cache_ide[x]_appl_data] - cache entries
|
||||
;
|
||||
;**************************************************************************
|
||||
|
||||
$Revision$
|
||||
|
||||
align 4
|
||||
find_empty_slot_CD_cache:
|
||||
;-----------------------------------------------------------
|
||||
; find empty or read slot, flush cache if next 10% is used by write
|
||||
; output : edi = cache slot
|
||||
;-----------------------------------------------------------
|
||||
.search_again:
|
||||
call cd_calculate_cache_3
|
||||
.search_for_empty:
|
||||
inc edi
|
||||
call cd_calculate_cache_4
|
||||
jbe .inside_cache
|
||||
mov edi, 1
|
||||
.inside_cache:
|
||||
call cd_calculate_cache_5
|
||||
ret
|
||||
;--------------------------------------------------------------------
|
||||
clear_CD_cache:
|
||||
DEBUGF 1, 'K : clear_CD_cache\n'
|
||||
pusha
|
||||
|
||||
mov esi, [cdpos]
|
||||
dec esi
|
||||
imul esi, sizeof.IDE_CACHE
|
||||
add esi, cache_ide0
|
||||
|
||||
xor eax, eax
|
||||
|
||||
mov [esi+IDE_CACHE.search_start], eax
|
||||
mov ecx, [esi+IDE_CACHE.system_sad_size]
|
||||
mov edi, [esi+IDE_CACHE.pointer]
|
||||
call .clear
|
||||
|
||||
mov [esi+IDE_CACHE.appl_search_start], eax
|
||||
mov ecx, [esi+IDE_CACHE.appl_sad_size]
|
||||
mov edi, [esi+IDE_CACHE.data_pointer]
|
||||
call .clear
|
||||
|
||||
popa
|
||||
ret
|
||||
;--------------------------------------
|
||||
.clear:
|
||||
shl ecx, 1
|
||||
cld
|
||||
rep stosd
|
||||
ret
|
||||
;--------------------------------------------------------------------
|
||||
align 4
|
||||
cd_calculate_cache:
|
||||
; 1 - IDE0 ... 12 - IDE11
|
||||
push eax
|
||||
|
||||
mov eax, [cdpos]
|
||||
dec eax
|
||||
imul eax, sizeof.IDE_CACHE
|
||||
add eax, cache_ide0
|
||||
|
||||
cmp [cd_appl_data], 0
|
||||
jne @f
|
||||
|
||||
mov ecx, [eax+IDE_CACHE.system_sad_size]
|
||||
mov esi, [eax+IDE_CACHE.pointer]
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------
|
||||
@@:
|
||||
mov ecx, [eax+IDE_CACHE.appl_sad_size]
|
||||
mov esi, [eax+IDE_CACHE.data_pointer]
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------------------------------------
|
||||
align 4
|
||||
cd_calculate_cache_1:
|
||||
; 1 - IDE0 ... 12 - IDE11
|
||||
push eax
|
||||
|
||||
mov eax, [cdpos]
|
||||
dec eax
|
||||
imul eax, sizeof.IDE_CACHE
|
||||
add eax, cache_ide0
|
||||
|
||||
cmp [cd_appl_data], 0
|
||||
jne @f
|
||||
|
||||
mov esi, [eax+IDE_CACHE.pointer]
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------
|
||||
@@:
|
||||
mov esi, [eax+IDE_CACHE.data_pointer]
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------------------------------------
|
||||
align 4
|
||||
cd_calculate_cache_2:
|
||||
; 1 - IDE0 ... 12 - IDE11
|
||||
mov eax, [cdpos]
|
||||
dec eax
|
||||
imul eax, sizeof.IDE_CACHE
|
||||
add eax, cache_ide0
|
||||
|
||||
cmp [cd_appl_data], 0
|
||||
jne @f
|
||||
|
||||
mov eax, [eax+IDE_CACHE.system_data]
|
||||
ret
|
||||
;--------------------------------------
|
||||
@@:
|
||||
mov eax, [eax+IDE_CACHE.appl_data]
|
||||
ret
|
||||
;--------------------------------------------------------------------
|
||||
align 4
|
||||
cd_calculate_cache_3:
|
||||
; 1 - IDE0 ... 12 - IDE11
|
||||
push eax
|
||||
|
||||
mov eax, [cdpos]
|
||||
dec eax
|
||||
imul eax, sizeof.IDE_CACHE
|
||||
add eax, cache_ide0
|
||||
|
||||
cmp [cd_appl_data], 0
|
||||
jne @f
|
||||
|
||||
mov edi, [eax+IDE_CACHE.search_start]
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------
|
||||
@@:
|
||||
mov edi, [eax+IDE_CACHE.appl_search_start]
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------------------------------------
|
||||
align 4
|
||||
cd_calculate_cache_4:
|
||||
; 1 - IDE0 ... 12 - IDE11
|
||||
push eax
|
||||
|
||||
mov eax, [cdpos]
|
||||
dec eax
|
||||
imul eax, sizeof.IDE_CACHE
|
||||
add eax, cache_ide0
|
||||
|
||||
cmp [cd_appl_data], 0
|
||||
jne @f
|
||||
|
||||
cmp edi, [eax+IDE_CACHE.system_sad_size]
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------
|
||||
@@:
|
||||
cmp edi, [eax+IDE_CACHE.appl_sad_size]
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------------------------------------
|
||||
align 4
|
||||
cd_calculate_cache_5:
|
||||
; 1 - IDE0 ... 12 - IDE11
|
||||
push eax
|
||||
|
||||
mov eax, [cdpos]
|
||||
dec eax
|
||||
imul eax, sizeof.IDE_CACHE
|
||||
add eax, cache_ide0
|
||||
|
||||
cmp [cd_appl_data], 0
|
||||
jne @f
|
||||
|
||||
mov [eax+IDE_CACHE.search_start], edi
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------
|
||||
@@:
|
||||
mov [eax+IDE_CACHE.appl_search_start], edi
|
||||
pop eax
|
||||
ret
|
||||
;--------------------------------------------------------------------
|
||||
192
kernel/branches/kolibri-lldw/blkdev/rd.inc
Normal file
192
kernel/branches/kolibri-lldw/blkdev/rd.inc
Normal file
@@ -0,0 +1,192 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; RAMDISK functions ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
iglobal
|
||||
align 4
|
||||
ramdisk_functions:
|
||||
dd .size
|
||||
dd 0 ; no close() function
|
||||
dd 0 ; no closemedia() function
|
||||
dd ramdisk_querymedia
|
||||
dd ramdisk_read
|
||||
dd ramdisk_write
|
||||
dd 0 ; no flush() function
|
||||
dd ramdisk_adjust_cache_size
|
||||
.size = $ - ramdisk_functions
|
||||
endg
|
||||
|
||||
iglobal
|
||||
align 4
|
||||
ramdisk_actual_size dd RAMDISK_CAPACITY
|
||||
endg
|
||||
|
||||
; This function is called early in boot process.
|
||||
; It creates filesystem /rd/1 based on raw image data loaded by somebody before
|
||||
; to memory named as RAMDISK with max size RAMDISK_CAPACITY, may be less.
|
||||
proc ramdisk_init
|
||||
iglobal
|
||||
ramdisk_name db 'rd',0
|
||||
endg
|
||||
push ebx esi ; save used registers to be stdcall
|
||||
; 1. Register the device and the (always inserted) media in the disk subsystem.
|
||||
stdcall disk_add, ramdisk_functions, ramdisk_name, 0, 0
|
||||
test eax, eax
|
||||
jz .fail
|
||||
mov ebx, eax
|
||||
stdcall disk_media_changed, eax, 1
|
||||
; 2. We don't know actual size of loaded image,
|
||||
; so try to calculate it using partition structure,
|
||||
; assuming that file systems fill the real size based on contents of the partition.
|
||||
; 2a. Prepare for loop over partitions.
|
||||
xor eax, eax
|
||||
xor ecx, ecx
|
||||
xor edx, edx
|
||||
; 2b. Check that at least one partition was recognized.
|
||||
cmp [ebx+DISK.NumPartitions], ecx
|
||||
jz .fail
|
||||
; 2c. Loop over partitions.
|
||||
.partitions:
|
||||
; For every partition, set edx to maximum between edx and end of partition.
|
||||
mov esi, [ebx+DISK.Partitions]
|
||||
mov esi, [esi+ecx*4]
|
||||
mov eax, dword [esi+PARTITION.FirstSector]
|
||||
add eax, dword [esi+PARTITION.Length]
|
||||
cmp eax, edx
|
||||
jb @f
|
||||
mov edx, eax
|
||||
@@:
|
||||
inc ecx
|
||||
cmp ecx, [ebx+DISK.NumPartitions]
|
||||
jb .partitions
|
||||
; 3. Reclaim unused memory, if any.
|
||||
mov [ramdisk_actual_size], edx
|
||||
add edx, 7 ; aligning up
|
||||
shr edx, 3 ; 512-byte sectors -> 4096-byte pages
|
||||
mov esi, RAMDISK_CAPACITY / 8 ; aligning down
|
||||
sub esi, edx
|
||||
jbe .no_reclaim
|
||||
shl edx, 12
|
||||
add edx, RAMDISK - OS_BASE
|
||||
@@:
|
||||
mov eax, edx
|
||||
call free_page
|
||||
add edx, 0x1000
|
||||
dec esi
|
||||
jnz @b
|
||||
.no_reclaim:
|
||||
mov eax, ebx
|
||||
pop esi ebx ; restore used registers to be stdcall
|
||||
ret
|
||||
.fail:
|
||||
dbgstr 'Failed to initialize ramdisk'
|
||||
pop esi ebx ; restore used registers to be stdcall
|
||||
ret
|
||||
endp
|
||||
|
||||
; Returns information about disk media.
|
||||
proc ramdisk_querymedia
|
||||
virtual at esp+4
|
||||
.userdata dd ?
|
||||
.info dd ?
|
||||
end virtual
|
||||
; Media is always present, sector size is always 512 bytes.
|
||||
mov edx, [.userdata]
|
||||
mov ecx, [.info]
|
||||
mov [ecx+DISKMEDIAINFO.Flags], 0
|
||||
mov [ecx+DISKMEDIAINFO.SectorSize], 512
|
||||
mov eax, [ramdisk_actual_size]
|
||||
mov dword [ecx+DISKMEDIAINFO.Capacity], eax
|
||||
mov dword [ecx+DISKMEDIAINFO.Capacity+4], 0
|
||||
; Return zero as an indicator of success.
|
||||
xor eax, eax
|
||||
retn 8
|
||||
endp
|
||||
|
||||
; Common procedure for reading and writing.
|
||||
; operation = 0 for reading, operation = 1 for writing.
|
||||
; Arguments of ramdisk_read and ramdisk_write are the same.
|
||||
macro ramdisk_read_write operation
|
||||
{
|
||||
push esi edi ; save used registers to be stdcall
|
||||
mov esi, [userdata]
|
||||
mov edi, [numsectors_ptr]
|
||||
; 1. Determine number of sectors to be transferred.
|
||||
; This is either the requested number of sectors or number of sectors
|
||||
; up to the disk boundary, depending of what is less.
|
||||
xor ecx, ecx
|
||||
; 1a. Test whether [start_sector] is less than RAMDISK_CAPACITY.
|
||||
; If so, calculate number of sectors between [start_sector] and RAMDISK_CAPACITY.
|
||||
; Otherwise, the actual number of sectors is zero.
|
||||
cmp dword [start_sector+4], ecx
|
||||
jnz .got_number
|
||||
mov eax, [ramdisk_actual_size]
|
||||
sub eax, dword [start_sector]
|
||||
jbe .got_number
|
||||
; 1b. Get the requested number of sectors.
|
||||
mov ecx, [edi]
|
||||
; 1c. If it is greater than number of sectors calculated in 1a, use the value
|
||||
; from 1a.
|
||||
cmp ecx, eax
|
||||
jb .got_number
|
||||
mov ecx, eax
|
||||
.got_number:
|
||||
; 2. Compare the actual number of sectors with requested. If they are
|
||||
; equal, set eax (it will be the returned value) to zero. Otherwise,
|
||||
; use DISK_STATUS_END_OF_MEDIA.
|
||||
xor eax, eax
|
||||
cmp ecx, [edi]
|
||||
jz @f
|
||||
mov al, DISK_STATUS_END_OF_MEDIA
|
||||
@@:
|
||||
; 3. Store the actual number of sectors.
|
||||
mov [edi], ecx
|
||||
; 4. Calculate source and destination addresses.
|
||||
if operation = 0 ; reading?
|
||||
mov esi, dword [start_sector]
|
||||
shl esi, 9
|
||||
add esi, RAMDISK
|
||||
mov edi, [buffer]
|
||||
else ; writing?
|
||||
mov edi, dword [start_sector]
|
||||
shl edi, 9
|
||||
add edi, RAMDISK
|
||||
mov esi, [buffer]
|
||||
end if
|
||||
; 5. Calculate number of dwords to be transferred.
|
||||
shl ecx, 9-2
|
||||
; 6. Copy data.
|
||||
rep movsd
|
||||
; 7. Return. The value in eax was calculated in step 2.
|
||||
pop edi esi ; restore used registers to be stdcall
|
||||
}
|
||||
|
||||
; Reads one or more sectors from the device.
|
||||
proc ramdisk_read userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
|
||||
ramdisk_read_write 0
|
||||
ret
|
||||
endp
|
||||
|
||||
; Writes one or more sectors to the device.
|
||||
proc ramdisk_write userdata:dword, buffer:dword, start_sector:qword, numsectors_ptr:dword
|
||||
ramdisk_read_write 1
|
||||
ret
|
||||
endp
|
||||
|
||||
; The kernel calls this function when initializing cache subsystem for
|
||||
; the media. This call allows the driver to adjust the cache size.
|
||||
proc ramdisk_adjust_cache_size
|
||||
virtual at esp+4
|
||||
.userdata dd ?
|
||||
.suggested_size dd ?
|
||||
end virtual
|
||||
; Since ramdisk does not need cache, just return 0.
|
||||
xor eax, eax
|
||||
retn 8
|
||||
endp
|
||||
33
kernel/branches/kolibri-lldw/blkdev/rdsave.inc
Normal file
33
kernel/branches/kolibri-lldw/blkdev/rdsave.inc
Normal file
@@ -0,0 +1,33 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
iglobal
|
||||
saverd_fileinfo:
|
||||
dd 2 ; subfunction: write
|
||||
dd 0 ; (reserved)
|
||||
dd 0 ; (reserved)
|
||||
.size:
|
||||
dd 0
|
||||
dd RAMDISK
|
||||
db 0
|
||||
.name:
|
||||
dd ?
|
||||
endg
|
||||
sysfn_saveramdisk: ; 18.6 = SAVE FLOPPY IMAGE (HD version only)
|
||||
mov ebx, saverd_fileinfo
|
||||
mov [ebx+21], ecx
|
||||
mov eax, [ramdisk_actual_size]
|
||||
shl eax, 9
|
||||
mov [ebx+12], eax
|
||||
pushad
|
||||
call file_system_lfn_protected ;in ebx
|
||||
popad
|
||||
mov [esp+32], eax
|
||||
ret
|
||||
BIN
kernel/branches/kolibri-lldw/boot/ETFONT.FNT
Normal file
BIN
kernel/branches/kolibri-lldw/boot/ETFONT.FNT
Normal file
Binary file not shown.
1400
kernel/branches/kolibri-lldw/boot/bootcode.inc
Normal file
1400
kernel/branches/kolibri-lldw/boot/bootcode.inc
Normal file
File diff suppressed because it is too large
Load Diff
107
kernel/branches/kolibri-lldw/boot/booten.inc
Normal file
107
kernel/branches/kolibri-lldw/boot/booten.inc
Normal file
@@ -0,0 +1,107 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;======================================================================
|
||||
;
|
||||
; BOOT DATA
|
||||
;
|
||||
;======================================================================
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
d80x25_bottom:
|
||||
db 186,' KolibriOS comes with ABSOLUTELY NO WARRANTY. See file COPYING for details ',186
|
||||
db 186,' If you find any bugs, please report them at: http://board.kolibrios.org ',186
|
||||
line_full_bottom
|
||||
d80x25_bottom_num = 3
|
||||
|
||||
msg_apm db " APM x.x ", 0
|
||||
novesa db "Display: EGA/CGA",13,10,0
|
||||
s_vesa db "Version of VESA: "
|
||||
.ver db "?.?",13,10,0
|
||||
|
||||
gr_mode db "Select a videomode: ",13,10,0
|
||||
|
||||
ask_bd db "Add disks visible by BIOS emulated in V86-mode? [1-yes, 2-no]: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
bdev db "Load ramdisk from [1-floppy; 2-kolibri.img; 3-don't load]: ",0
|
||||
else
|
||||
bdev db "Load ramdisk from [1-floppy; 2-C:\kolibri.img (FAT32);"
|
||||
db 13,10,186," "
|
||||
db "3-use preloaded ram-image from kernel restart;"
|
||||
db 13,10,186," "
|
||||
db "4-create blank image]: ",0
|
||||
end if
|
||||
|
||||
prnotfnd db "Fatal - Videomode not found.",0
|
||||
|
||||
not386 db "Fatal - CPU 386+ required.",0
|
||||
fatalsel db "Fatal - Graphics mode not supported by hardware.",0
|
||||
pres_key db "Press any key to choose a new videomode.",0
|
||||
badsect db 13,10,186," Fatal - Bad sector. Replace floppy.",0
|
||||
memmovefailed db 13,10,186," Fatal - Int 0x15 move failed.",0
|
||||
okt db " ... OK"
|
||||
linef db 13,10,0
|
||||
diskload db "Loading diskette: 00 %",8,8,8,8,0
|
||||
pros db "00"
|
||||
backspace2 db 8,8,0
|
||||
boot_dev db 0 ; 0=floppy, 1=hd
|
||||
start_msg db "Press [abcde] to change settings, press [Enter] to continue booting",13,10,0
|
||||
time_msg db " or wait "
|
||||
time_str db " 5 seconds"
|
||||
db " to continue automatically",13,10,0
|
||||
current_cfg_msg db "Current settings:",13,10,0
|
||||
curvideo_msg db " [a] Videomode: ",0
|
||||
|
||||
mode0 db "320x200, EGA/CGA 256 colors",13,10,0
|
||||
mode9 db "640x480, VGA 16 colors",13,10,0
|
||||
|
||||
usebd_msg db " [b] Add disks visible by BIOS:",0
|
||||
on_msg db " on",13,10,0
|
||||
off_msg db " off",13,10,0
|
||||
|
||||
debug_mode_msg db " [c] Duplicate debug output to the screen:",0
|
||||
ask_debug db "Duplicate debug output to the screen? [1-yes, 2-no]: ",0
|
||||
|
||||
launcher_msg db " [d] Start LAUNCHER after kernel is loaded:",0
|
||||
ask_launcher db "Start first application (LAUNCHER) after kernel is loaded? [1-yes, 2-no]: ",0
|
||||
|
||||
preboot_device_msg db " [e] Floppy image: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,pdm3,0
|
||||
pdm1 db "real floppy",13,10,0
|
||||
pdm2 db "C:\kolibri.img (FAT32)",13,10,0
|
||||
pdm3 db "do not use floppy image",13,10,0
|
||||
else
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0
|
||||
pdm1 db "real floppy",13,10,0
|
||||
pdm2 db "C:\kolibri.img (FAT32)",13,10,0
|
||||
pdm3 db "use already loaded image",13,10,0
|
||||
pdm4 db "create blank image",13,10,0
|
||||
end if
|
||||
|
||||
loading_msg db "Loading KolibriOS...",0
|
||||
|
||||
if ~ defined extended_primary_loader
|
||||
save_quest db "Remember current settings? [y/n]: ",0
|
||||
loader_block_error db "Bootloader data invalid, I cannot continue. Stopped.",0
|
||||
end if
|
||||
|
||||
_st latin1 '║ ┌───────────────────────────────┬─┐',13,10,0
|
||||
_r1 latin1 '║ │ 320x200 EGA/CGA 256 colors │ │',13,10,0
|
||||
_r2 latin1 '║ │ 640x480 VGA 16 colors │ │',13,10,0
|
||||
_rs latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0
|
||||
_bt latin1 '║ └───────────────────────────────┴─┘',13,10,0
|
||||
|
||||
remark1 db "Default values were selected to match most of configurations, but not all.",0
|
||||
remark2 db "If the system does not boot, try to disable option [b]. If the system gets",0
|
||||
remark3 db "stuck after booting, enable option [c], disable option [d] and make photo.",0
|
||||
remarks dw remark1, remark2, remark3
|
||||
num_remarks = 3
|
||||
106
kernel/branches/kolibri-lldw/boot/bootet.inc
Normal file
106
kernel/branches/kolibri-lldw/boot/bootet.inc
Normal file
@@ -0,0 +1,106 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;======================================================================
|
||||
;
|
||||
; BOOT DATA
|
||||
;
|
||||
;======================================================================
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
d80x25_bottom:
|
||||
latin1 '║ KolibriOS on IGASUGUSE GARANTIITA. Vaata faili COPYING info saamiseks. Kui ║'
|
||||
latin1 '║ leiate vigu, anna neist palun teada aadressil: http://board.kolibrios.org ║'
|
||||
line_full_bottom
|
||||
d80x25_bottom_num = 3
|
||||
|
||||
msg_apm latin1 " APM x.x ", 0
|
||||
novesa latin1 "Ekraan: EGA/CGA",13,10,0
|
||||
s_vesa latin1 "Vesa versioon: "
|
||||
.ver db "?.?",13,10,0
|
||||
|
||||
gr_mode latin1 "Vali video resolutsioon: ",13,10,0
|
||||
|
||||
ask_bd latin1 "Lisa V86 reziimis BIOSle nähtavad kettad? [1-jah, 2-ei]: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
bdev latin1 "Paigalda mäluketas [1-diskett; 2-kolibri.img]: ",0
|
||||
else
|
||||
bdev latin1 "Paigalda mäluketas [1-diskett; 2-C:\kolibri.img (FAT32);"
|
||||
latin1 13,10,"║ "
|
||||
latin1 "3-kasuta eellaaditud mäluketast kerneli restardist;"
|
||||
latin1 13,10,"║ "
|
||||
latin1 "4-loo tühi pilt]: ",0
|
||||
end if
|
||||
|
||||
prnotfnd latin1 "Fataalne - Video resolutsiooni ei leitud.",0
|
||||
|
||||
not386 latin1 "Fataalne - CPU 386+ on vajalik.",0
|
||||
fatalsel latin1 "Fataalne - Riistvara ei toeta graafilist resolutsiooni.",0
|
||||
pres_key latin1 "Vajutage suvalist klahvi, et valida uus videomode.",0
|
||||
badsect latin1 13,10,"║ Fataalne - Vigane sektor. Asenda diskett.",0
|
||||
memmovefailed latin1 13,10,"║ Fataalne - Int 0x15 liigutamine ebaõnnestus.",0
|
||||
okt latin1 " ... OK"
|
||||
linef latin1 13,10,0
|
||||
diskload latin1 "Loen disketti: 00 %",8,8,8,8,0
|
||||
pros latin1 "00"
|
||||
backspace2 latin1 8,8,0
|
||||
boot_dev db 0 ; 0=floppy, 1=hd
|
||||
start_msg latin1 "Vajuta [abcde] seadete muutmiseks, vajuta [Enter] laadimise jätkamiseks",13,10,0
|
||||
time_msg latin1 " või oota "
|
||||
time_str latin1 " 5 sekundit"
|
||||
latin1 " automaatseks jätkamiseks",13,10,0
|
||||
current_cfg_msg latin1 "Praegused seaded:",13,10,0
|
||||
curvideo_msg latin1 " [a] Video resolutsioon: ",0
|
||||
|
||||
mode0 latin1 "320x200, EGA/CGA 256 värvi",0
|
||||
mode9 latin1 "640x480, VGA 16 värvi",0
|
||||
|
||||
usebd_msg latin1 " [b] Lisa BIOSle nähtavad kettad:",0
|
||||
on_msg latin1 " sees",13,10,0
|
||||
off_msg latin1 " väljas",13,10,0
|
||||
|
||||
debug_mode_msg latin1 " [c] Dubleeri silumisinfo ekraanile:",0
|
||||
ask_debug latin1 "Dubleeri silumisinfo ekraanile? [1-jah, 2-ei]: ",0
|
||||
|
||||
launcher_msg latin1 " [d] Käivita LAUNCHER pärast kerneli laadimist:",0
|
||||
ask_launcher latin1 "Käivita esimese programm (LAUNCHER) peale kerneli laadimist? [1-jah, 2-ei]: ",0
|
||||
|
||||
preboot_device_msg latin1 " [e] Disketi kujutis: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,0
|
||||
pdm1 latin1 "reaalne diskett",13,10,0
|
||||
pdm2 latin1 "kolibri.img",13,10,0
|
||||
else
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0
|
||||
pdm1 latin1 "reaalne diskett",13,10,0
|
||||
pdm2 latin1 "C:\kolibri.img (FAT32)",13,10,0
|
||||
pdm3 latin1 "kasuta juba laaditud kujutist",13,10,0
|
||||
pdm4 latin1 "loo tühi pilt",13,10,0
|
||||
end if
|
||||
|
||||
loading_msg latin1 "Laadin KolibriOS...",0
|
||||
|
||||
if ~ defined extended_primary_loader
|
||||
save_quest latin1 "Jäta meelde praegused seaded? [y/n]: ",0
|
||||
loader_block_error latin1 "Alglaaduri andmed vigased, ei saa jätkata. Peatatud.",0
|
||||
end if
|
||||
|
||||
_st latin1 '║ ┌───────────────────────────────┬─┐',13,10,0
|
||||
_r1 latin1 '║ │ 320x200 EGA/CGA 256 värvi │ │',13,10,0
|
||||
_r2 latin1 '║ │ 640x480 VGA 16 värvi │ │',13,10,0
|
||||
_rs latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0
|
||||
_bt latin1 '║ └───────────────────────────────┴─┘',13,10,0
|
||||
|
||||
remark1 latin1 "Vaikimisi väärtused on kasutatavad enamikes arvutites, kuid mitte kõigis.",0
|
||||
remark2 latin1 "Kui süsteem ei käivitu, proovige lülitada kirje [b] välja. Kui see läheb",0
|
||||
remark3 latin1 "kinni pärast käivitamist, võimaldama valik [c], keelake [d] ja teha foto.",0
|
||||
remarks dw remark1, remark2, remark3
|
||||
num_remarks = 3
|
||||
107
kernel/branches/kolibri-lldw/boot/bootge.inc
Normal file
107
kernel/branches/kolibri-lldw/boot/bootge.inc
Normal file
@@ -0,0 +1,107 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;======================================================================
|
||||
;
|
||||
; BOOT DATA
|
||||
;
|
||||
;======================================================================
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
d80x25_bottom:
|
||||
db 186,' KolibriOS wird ohne jegliche Garantie vertrieben. Details stehen in der ',186
|
||||
db 186,' Datei COPYING. Bitte melden Sie Fehler bei: http://board.kolibrios.org ',186
|
||||
line_full_bottom
|
||||
d80x25_bottom_num = 3
|
||||
|
||||
msg_apm db " APM x.x ", 0
|
||||
novesa db "Anzeige: EGA/CGA ",13,10,0
|
||||
s_vesa db "Vesa-Version: "
|
||||
.ver db "?.?",13,10,0
|
||||
|
||||
gr_mode db "Wahlen Sie einen videomode: ",13,10,0
|
||||
|
||||
ask_bd db "Add-Festplatten sichtbar BIOS in V86-Modus emuliert? [1-ja, 2 nein]: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
bdev db "Lade die Ramdisk von [1-Diskette; 2-kolibri.img]: ",0
|
||||
else
|
||||
bdev db "Lade die Ramdisk von [1-Diskette; 2-C:\kolibri.img (FAT32);"
|
||||
db 13,10,186," "
|
||||
db "3-benutze ein bereits geladenes Kernel image;"
|
||||
db 13,10,186," "
|
||||
db "4-create blank image]: ",0
|
||||
end if
|
||||
|
||||
prnotfnd db "Fatal - Videomodus nicht gefunden.",0
|
||||
|
||||
not386 db "Fatal - CPU 386+ benoetigt.",0
|
||||
fatalsel db "Fatal - Grafikmodus nicht unterstuetzt.",0
|
||||
pres_key db "Drucken Sie eine beliebige Taste, um eine neue videomode wahlen.",0
|
||||
badsect db 13,10,186," Fatal - Sektorfehler, Andere Diskette neutzen.",0
|
||||
memmovefailed db 13,10,186," Fatal - Int 0x15 Fehler.",0
|
||||
okt db " ... OK"
|
||||
linef db 13,10,0
|
||||
diskload db "Lade Diskette: 00 %",8,8,8,8,0
|
||||
pros db "00"
|
||||
backspace2 db 8,8,0
|
||||
boot_dev db 0 ; 0=floppy, 1=hd
|
||||
start_msg db "Druecke [abcde], um die Einstellungen zu aendern, druecke [Enter] zum starten",13,10,0
|
||||
time_msg db " oder warte "
|
||||
time_str db " 5 Sekunden"
|
||||
db " bis zum automatischen Start",13,10,0
|
||||
current_cfg_msg db "Aktuelle Einstellungen:",13,10,0
|
||||
curvideo_msg db " [a] Videomodus: ",0
|
||||
|
||||
mode0 db "320x200, EGA/CGA 256 colors",13,10,0
|
||||
mode9 db "640x480, VGA 16 colors",13,10,0
|
||||
|
||||
usebd_msg db " [b] Add-Festplatten sichtbar durch das BIOS:",0
|
||||
on_msg db " an",13,10,0
|
||||
off_msg db " aus",13,10,0
|
||||
|
||||
debug_mode_msg db " [c] Duplizieren debuggen Ausgabe auf dem Bildschirm:",0
|
||||
ask_debug db "Duplizieren debuggen Ausgabe auf dem Bildschirm? [1-ja, 2 nein]: ",0
|
||||
|
||||
launcher_msg db " [d] Start LAUNCHER nach Kernel geladen wird:",0
|
||||
ask_launcher db "Starten erste Anwendung nach Kernel geladen wird? [1-ja, 2 nein]: ",0
|
||||
|
||||
preboot_device_msg db " [e] Diskettenimage: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,0
|
||||
pdm1 db "Echte Diskette",13,10,0
|
||||
pdm2 db "kolibri.img",13,10,0
|
||||
else
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0
|
||||
pdm1 db "Echte Diskette",13,10,0
|
||||
pdm2 db "C:\kolibri.img (FAT32)",13,10,0
|
||||
pdm3 db "Nutze bereits geladenes Image",13,10,0
|
||||
pdm4 db "create blank image",13,10,0
|
||||
end if
|
||||
|
||||
loading_msg db "Lade KolibriOS...",0
|
||||
|
||||
if ~ defined extended_primary_loader
|
||||
save_quest db "Aktuelle Einstellungen speichern? [y/n]: ",0
|
||||
loader_block_error db "Bootloader Daten ungueltig, Kann nicht fortfahren. Angehalten.",0
|
||||
end if
|
||||
|
||||
_st latin1 '║ ┌───────────────────────────────┬─┐',13,10,0
|
||||
_r1 latin1 '║ │ 320x200 EGA/CGA 256 colors │ │',13,10,0
|
||||
_r2 latin1 '║ │ 640x480 VGA 16 colors │ │',13,10,0
|
||||
_rs latin1 '║ │ ????x????@?? SVGA VESA │ │',13,10,0
|
||||
_bt latin1 '║ └───────────────────────────────┴─┘',13,10,0
|
||||
|
||||
remark1 db "Die Standardwerte sind fur die meisten gewahlt, aber nicht fur jedermann.",0
|
||||
remark2 db "Wenn das System nicht bootet, das Option [b] deaktivieren versuchen. Wenn es",0
|
||||
remark3 db "nach dem Booten hangen bleibt, aktivieren Sie Option [c], deaktivieren [d]",0
|
||||
remark4 db "und machen Fotos.",0
|
||||
remarks dw remark1, remark2, remark3, remark4
|
||||
num_remarks = 4
|
||||
106
kernel/branches/kolibri-lldw/boot/bootru.inc
Normal file
106
kernel/branches/kolibri-lldw/boot/bootru.inc
Normal file
@@ -0,0 +1,106 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;=================================================================
|
||||
;
|
||||
; BOOT DATA
|
||||
;
|
||||
;=================================================================
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
d80x25_bottom:
|
||||
cp866 '║ KolibriOS НЕ ПРЕДОСТАВЛЯЕТ НИКАКИХ ГАРAНТИЙ. Подробнее смотрите в файле ║'
|
||||
cp866 '║ COPYING.TXT. О найденных ошибках сообщайте на http://board.kolibrios.org ║'
|
||||
line_full_bottom
|
||||
d80x25_bottom_num = 3
|
||||
|
||||
msg_apm cp866 " APM x.x ", 0
|
||||
novesa cp866 "Видеокарта: EGA/CGA",13,10,0
|
||||
s_vesa cp866 "Версия VESA: "
|
||||
.ver db "?.?",13,10,0
|
||||
|
||||
gr_mode cp866 "Выберите видеорежим: ",13,10,0
|
||||
|
||||
ask_bd cp866 "Добавить диски, видимые через BIOS в режиме V86? [1-да, 2-нет]: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
bdev cp866 "Загрузить образ из [1-дискета; 2-kolibri.img из папки загрузки;",13,10
|
||||
cp866 "║ 3-не загружать]: ",0
|
||||
else
|
||||
bdev cp866 "Загрузить образ из [1-дискета; 2-C:\kolibri.img (FAT32);",13,10
|
||||
cp866 "║ 3-использовать уже загруженный образ;",13,10
|
||||
cp866 "║ 4-создать чистый образ]: ",0
|
||||
end if
|
||||
|
||||
prnotfnd cp866 "Ошибка - Видеорежим не найден.",0
|
||||
|
||||
not386 cp866 "Ошибка - Требуется процессор 386+.",0
|
||||
fatalsel cp866 "Ошибка - Выбранный видеорежим не поддерживается.",0
|
||||
pres_key cp866 "Нажимите любую клавишу, для перехода в выбор режимов.",0
|
||||
badsect cp866 13,10,"║ Ошибка - Дискета повреждена. Попробуйте другую.",0
|
||||
memmovefailed cp866 13,10,"║ Ошибка - Int 0x15 move failed.",0
|
||||
okt cp866 " ... OK"
|
||||
linef cp866 13,10,0
|
||||
diskload cp866 "Загрузка дискеты: 00 %",8,8,8,8,0
|
||||
pros cp866 "00"
|
||||
backspace2 cp866 8,8,0
|
||||
boot_dev db 0
|
||||
start_msg cp866 "Нажмите [abcde] для изменения настроек, [Enter] для продолжения загрузки",13,10,0
|
||||
time_msg cp866 " или подождите "
|
||||
time_str cp866 " 5 секунд "
|
||||
cp866 " до автоматического продолжения",13,10,0
|
||||
current_cfg_msg cp866 "Текущие настройки:",13,10,0
|
||||
curvideo_msg cp866 " [a] Видеорежим: ",0
|
||||
|
||||
mode0 cp866 "320x200, EGA/CGA 256 цветов",13,10,0
|
||||
mode9 cp866 "640x480, VGA 16 цветов",13,10,0
|
||||
|
||||
usebd_msg cp866 " [b] Добавить диски, видимые через BIOS:",0
|
||||
on_msg cp866 " вкл",13,10,0
|
||||
off_msg cp866 " выкл",13,10,0
|
||||
|
||||
debug_mode_msg cp866 " [c] Дублировать дебаг-вывод на экран монитора:",0
|
||||
ask_debug cp866 "Дублировать дебаг-вывод на экран монитора? [1-да, 2-нет]: ",0
|
||||
|
||||
launcher_msg cp866 " [d] Запустить программу LAUNCHER после загрузки ядра:",0
|
||||
ask_launcher cp866 "Запустить первую программу (LAUNCHER) после загрузки ядра? [1-да, 2-нет]: ",0
|
||||
|
||||
preboot_device_msg cp866 " [e] Образ дискеты: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,pdm3,0
|
||||
pdm1 cp866 "настоящая дискета",13,10,0
|
||||
pdm2 cp866 "kolibri.img из папки загрузки",13,10,0
|
||||
pdm3 cp866 "не загружать образ рамдиска",13,10,0
|
||||
else
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0
|
||||
pdm1 cp866 "настоящая дискета",13,10,0
|
||||
pdm2 cp866 "C:\kolibri.img (FAT32)",13,10,0
|
||||
pdm3 cp866 "использовать уже загруженный образ",13,10,0
|
||||
pdm4 cp866 "создать чистый образ",13,10,0
|
||||
end if
|
||||
|
||||
loading_msg cp866 "Идёт загрузка KolibriOS...",0
|
||||
|
||||
if ~ defined extended_primary_loader ; saving not supported in this case
|
||||
save_quest cp866 "Запомнить текущие настройки? [y/n]: ",0
|
||||
loader_block_error cp866 "Ошибка в данных начального загрузчика, продолжение невозможно.",0
|
||||
end if
|
||||
|
||||
_st cp866 '║ ┌───────────────────────────────┬─┐ ',13,10,0
|
||||
_r1 cp866 '║ │ 320x200 EGA/CGA 256 цветов │ │ ',13,10,0
|
||||
_r2 cp866 '║ │ 640x480 VGA 16 цветов │ │ ',13,10,0
|
||||
_rs cp866 '║ │ ????x????@?? SVGA VESA │ │ ',13,10,0
|
||||
_bt cp866 '║ └───────────────────────────────┴─┘ ',13,10,0
|
||||
|
||||
remark1 cp866 "Значения по умолчанию выбраны для удобства большинства, но не всех. Если у",0
|
||||
remark2 cp866 "Вас не грузится система, попробуйте отключить пункт [b]. Если она зависла",0
|
||||
remark3 cp866 "после запуска, включите пункт [c], отключите пункт [d] и сделайте фото лога.",0
|
||||
remarks dw remark1, remark2, remark3
|
||||
num_remarks = 3
|
||||
108
kernel/branches/kolibri-lldw/boot/bootsp.inc
Normal file
108
kernel/branches/kolibri-lldw/boot/bootsp.inc
Normal file
@@ -0,0 +1,108 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;======================================================================
|
||||
;
|
||||
; BOOT DATA
|
||||
;
|
||||
;======================================================================
|
||||
|
||||
; Para modificar éste archivo es necesario abrirlo con codificación CP850
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
d80x25_bottom:
|
||||
cp850 '║ KolibriOS viene ABSOLUTAMENTE SIN GARANTíA. Lee el archivo COPYING por más ║'
|
||||
cp850 '║ detalles. Por favor, informar de los errores en: http://board.kolibrios.org ║'
|
||||
line_full_bottom
|
||||
d80x25_bottom_num = 3
|
||||
|
||||
msg_apm cp850 " APM x.x ", 0
|
||||
novesa cp850 "Monitor: EGA/CGA",13,10,0
|
||||
s_vesa cp850 "Versión de VESA: "
|
||||
.ver db "?.?",13,10,0
|
||||
|
||||
gr_mode cp850 "Selecciona un modo de video: ",13,10,0
|
||||
|
||||
ask_bd cp850 "¿Agregar discos visibles por el BIOS emulados en modo V86? [1-si, 2-no]: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
bdev cp850 "Cargar unidad ram desde [1-disquete; 2-kolibri.img]: ",0
|
||||
else
|
||||
bdev cp850 "Cargar unidad ram desde [1-disquete; 2-C:\kolibri.img (FAT32);"
|
||||
cp850 13,10,"║ "
|
||||
cp850 "3-usar imagen precargada en el reinicio del núcleo;"
|
||||
cp850 13,10,"║ "
|
||||
cp850 "4-crear imagen vacía]: ",0
|
||||
end if
|
||||
|
||||
prnotfnd cp850 "Fatal - Modo de video no encontrado.",0
|
||||
|
||||
not386 cp850 "Fatal - CPU 386+ requerido.",0
|
||||
fatalsel cp850 "Fatal - Modo de gráficos no soportado por hardware.",0
|
||||
pres_key cp850 "Presiona una tecla para seleccionar otro modo de video.",0
|
||||
badsect cp850 13,10,"║ Fatal - Sector mal. Reemplaze el disquete.",0
|
||||
memmovefailed cp850 13,10,"║ Fatal - Int 0x15 move failed.",0
|
||||
okt cp850 " ... BIEN"
|
||||
linef cp850 13,10,0
|
||||
diskload cp850 "Cargando disquete: 00 %",8,8,8,8,0
|
||||
pros cp850 "00"
|
||||
backspace2 cp850 8,8,0
|
||||
boot_dev db 0 ; 0=floppy, 1=hd
|
||||
start_msg cp850 "Presiona [abcde] para cambiar la configuración, [Enter] para continuar",13,10,0
|
||||
time_msg cp850 " o espera "
|
||||
time_str cp850 " 5 segundos"
|
||||
cp850 " para que inicie automáticamente",13,10,0
|
||||
current_cfg_msg cp850 "Configuración actual:",13,10,0
|
||||
curvideo_msg cp850 " [a] Modo de video: ",0
|
||||
|
||||
mode0 cp850 "320x200, EGA/CGA 256 colores",13,10,0
|
||||
mode9 cp850 "640x480, VGA 16 colores",13,10,0
|
||||
|
||||
usebd_msg cp850 " [b] Agregar discos visibles por el BIOS:",0
|
||||
on_msg cp850 " activado",13,10,0
|
||||
off_msg cp850 " desactivado",13,10,0
|
||||
|
||||
debug_mode_msg cp850 " [c] Duplicar depurar salida a la pantalla:",0
|
||||
ask_debug cp850 "¿Duplicar depurar la salida a la pantalla? [1-si, 2-no]: ",0
|
||||
|
||||
launcher_msg cp850 " [d] Iniciar LAUNCHER después de cargar kernel:",0
|
||||
ask_launcher cp850 "¿Inicie la primera aplicación después de cargar el kernel? [1-si, 2-no]: ",0
|
||||
|
||||
preboot_device_msg cp850 " [e] Imagen de disquete: ",0
|
||||
|
||||
if defined extended_primary_loader
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,0
|
||||
pdm1 cp850 "disquete real",13,10,0
|
||||
pdm2 cp850 "C:\kolibri.img (FAT32)",13,10,0
|
||||
else
|
||||
preboot_device_msgs dw 0,pdm1,pdm2,pdm3,pdm4,0
|
||||
pdm1 cp850 "disquete real",13,10,0
|
||||
pdm2 cp850 "C:\kolibri.img (FAT32)",13,10,0
|
||||
pdm3 cp850 "usar imagen ya cargada",13,10,0
|
||||
pdm4 cp850 "crear imagen vacía",13,10,0
|
||||
end if
|
||||
|
||||
loading_msg cp850 "Cargando KolibriOS...",0
|
||||
|
||||
if ~ defined extended_primary_loader
|
||||
save_quest cp850 "¿Recordar configuración actual? [s/n]: ",0
|
||||
loader_block_error cp850 "Bootloader inválido, no puedo continuar. Detenido.",0
|
||||
end if
|
||||
|
||||
_st cp850 '║ ┌───────────────────────────────┬─┐',13,10,0
|
||||
_r1 cp850 '║ │ 320x200 EGA/CGA 256 colores │ │',13,10,0
|
||||
_r2 cp850 '║ │ 640x480 VGA 16 colores │ │',13,10,0
|
||||
_rs cp850 '║ │ ????x????@?? SVGA VESA │ │',13,10,0
|
||||
_bt cp850 '║ └───────────────────────────────┴─┘',13,10,0
|
||||
|
||||
remark1 cp850 "Los valores por defecto puede que no funcionen en algunas configuraciones.",0
|
||||
remark2 cp850 "Si el sistema no inicia, prueba deshabilitar la opción [b]. Si se bloquea",0
|
||||
remark3 cp850 "después de arrancar, habilite la opción [c], desactivar [d] y hacer fotos.",0
|
||||
remarks dw remark1, remark2, remark3
|
||||
num_remarks = 3
|
||||
56
kernel/branches/kolibri-lldw/boot/bootstr.inc
Normal file
56
kernel/branches/kolibri-lldw/boot/bootstr.inc
Normal file
@@ -0,0 +1,56 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
; boot data: common strings (for all languages)
|
||||
macro line_full_top {
|
||||
db 201
|
||||
times 78 db 205
|
||||
db 187
|
||||
}
|
||||
macro line_full_bottom {
|
||||
db 200
|
||||
times 78 db 205
|
||||
db 188
|
||||
}
|
||||
macro line_half {
|
||||
db 186,' '
|
||||
times 76 db 0xc4
|
||||
db ' ',186
|
||||
}
|
||||
macro line_space {
|
||||
db 186
|
||||
times 78 db 32
|
||||
db 186
|
||||
}
|
||||
d80x25_top:
|
||||
line_full_top
|
||||
cur_line_pos = 72
|
||||
; this signature will be replaced with revision number (in kernel.asm)
|
||||
store dword '****' at d80x25_top + cur_line_pos
|
||||
|
||||
space_msg:
|
||||
line_space
|
||||
verstr:
|
||||
; line_space
|
||||
; version string
|
||||
db 186,32
|
||||
repeat 78
|
||||
load a byte from version+%-1
|
||||
if a = 13
|
||||
break
|
||||
end if
|
||||
db a
|
||||
end repeat
|
||||
repeat 78 - ($-verstr)
|
||||
db ' '
|
||||
end repeat
|
||||
db 32,186
|
||||
line_half
|
||||
d80x25_top_num = 4
|
||||
801
kernel/branches/kolibri-lldw/boot/bootvesa.inc
Normal file
801
kernel/branches/kolibri-lldw/boot/bootvesa.inc
Normal file
@@ -0,0 +1,801 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
struc VBE_VGAInfo {
|
||||
.VESASignature dd ? ; char
|
||||
.VESAVersion dw ? ; short
|
||||
.OemStringPtr dd ? ; char *
|
||||
.Capabilities dd ? ; ulong
|
||||
.VideoModePtr dd ? ; ulong
|
||||
.TotalMemory dw ? ; short
|
||||
; VBE 2.0+
|
||||
.OemSoftwareRev db ? ; short
|
||||
.OemVendorNamePtr dw ? ; char *
|
||||
.OemProductNamePtr dw ? ; char *
|
||||
.OemProductRevPtr dw ? ; char *
|
||||
.reserved rb 222 ; char
|
||||
.OemData rb 256 ; char
|
||||
}
|
||||
|
||||
struc VBE_ModeInfo {
|
||||
.ModeAttributes dw ? ; short
|
||||
.WinAAttributes db ? ; char
|
||||
.WinBAttributes db ? ; char
|
||||
.WinGranularity dw ? ; short
|
||||
.WinSize dw ? ; short
|
||||
.WinASegment dw ? ; ushort
|
||||
.WinBSegment dw ? ; ushort
|
||||
.WinFuncPtr dd ? ; void *
|
||||
.BytesPerScanLine dw ? ; short
|
||||
.XRes dw ? ; short
|
||||
.YRes dw ? ; short
|
||||
.XCharSize db ? ; char
|
||||
.YCharSize db ? ; char
|
||||
.NumberOfPlanes db ? ; char
|
||||
.BitsPerPixel db ? ; char
|
||||
.NumberOfBanks db ? ; char
|
||||
.MemoryModel db ? ; char
|
||||
.BankSize db ? ; char
|
||||
.NumberOfImagePages db ? ; char
|
||||
.res1 db ? ; char
|
||||
.RedMaskSize db ? ; char
|
||||
.RedFieldPosition db ? ; char
|
||||
.GreenMaskSize db ? ; char
|
||||
.GreenFieldPosition db ? ; char
|
||||
.BlueMaskSize db ? ; char
|
||||
.BlueFieldPosition db ? ; char
|
||||
.RsvedMaskSize db ? ; char
|
||||
.RsvedFieldPosition db ? ; char
|
||||
.DirectColorModeInfo db ? ; char ; MISSED IN THIS TUTORIAL!! SEE ABOVE
|
||||
; VBE 2.0+
|
||||
.PhysBasePtr dd ? ; ulong
|
||||
.OffScreenMemOffset dd ? ; ulong
|
||||
.OffScreenMemSize dw ? ; short
|
||||
; VBE 3.0+
|
||||
.LinbytesPerScanLine dw ? ; short
|
||||
.BankNumberOfImagePages db ? ; char
|
||||
.LinNumberOfImagePages db ? ; char
|
||||
.LinRedMaskSize db ? ; char
|
||||
.LinRedFieldPosition db ? ; char
|
||||
.LingreenMaskSize db ? ; char
|
||||
.LinGreenFieldPosition db ? ; char
|
||||
.LinBlueMaskSize db ? ; char
|
||||
.LinBlueFieldPosition db ? ; char
|
||||
.LinRsvdMaskSize db ? ; char
|
||||
.LinRsvdFieldPosition db ? ; char
|
||||
.MaxPixelClock dd ? ; ulong
|
||||
.res2 rb 190 ; char
|
||||
}
|
||||
|
||||
virtual at $A000
|
||||
vi VBE_VGAInfo
|
||||
mi VBE_ModeInfo
|
||||
modes_table:
|
||||
end virtual
|
||||
cursor_pos dw 0 ;временное хранение курсора.
|
||||
cursor_pos_old dw 0
|
||||
home_cursor dw 0 ;current shows rows a table
|
||||
end_cursor dw 0 ;end of position current shows rows a table
|
||||
scroll_start dw 0 ;start position of scroll bar
|
||||
scroll_end dw 0 ;end position of scroll bar
|
||||
long_v_table = 9 ;long of visible video table
|
||||
size_of_step = 10
|
||||
scroll_area_size = long_v_table - 2
|
||||
int2str:
|
||||
dec bl
|
||||
jz @f
|
||||
xor edx, edx
|
||||
div ecx
|
||||
push edx
|
||||
call int2str
|
||||
pop eax
|
||||
@@:
|
||||
or al, 0x30
|
||||
mov [ds:di], al
|
||||
inc di
|
||||
ret
|
||||
|
||||
int2strnz:
|
||||
cmp eax, ecx
|
||||
jb @f
|
||||
xor edx, edx
|
||||
div ecx
|
||||
push edx
|
||||
call int2strnz
|
||||
pop eax
|
||||
@@:
|
||||
or al, 0x30
|
||||
mov [es:di], al
|
||||
inc di
|
||||
ret
|
||||
|
||||
;-------------------------------------------------------
|
||||
;Write message about incorrect v_mode and write message about jmp on swith v_mode
|
||||
v_mode_error:
|
||||
_setcursor 19,2
|
||||
mov si, fatalsel
|
||||
call printplain
|
||||
_setcursor 20,2
|
||||
mov si, pres_key
|
||||
call printplain
|
||||
xor eax, eax
|
||||
int 16h
|
||||
jmp cfgmanager.d
|
||||
;-------------------------------------------------------
|
||||
;
|
||||
|
||||
|
||||
|
||||
;-------------------------------------------------------
|
||||
print_vesa_info:
|
||||
_setcursor 5,2
|
||||
|
||||
mov [es:vi.VESASignature], 'VBE2'
|
||||
mov ax, 0x4F00
|
||||
mov di, vi ;0xa000
|
||||
int 0x10
|
||||
or ah, ah
|
||||
jz @f
|
||||
mov [es:vi.VESASignature], 'VESA'
|
||||
mov ax, $4F00
|
||||
mov di, vi
|
||||
int 0x10
|
||||
or ah, ah
|
||||
jnz .exit
|
||||
@@:
|
||||
cmp [es:vi.VESASignature], 'VESA'
|
||||
jne .exit
|
||||
cmp [es:vi.VESAVersion], 0x0100
|
||||
jb .exit
|
||||
jmp .vesaok2
|
||||
|
||||
.exit:
|
||||
mov si, novesa
|
||||
call printplain
|
||||
ret
|
||||
|
||||
.vesaok2:
|
||||
mov ax, [es:vi.VESAVersion]
|
||||
add ax, '00'
|
||||
|
||||
mov [s_vesa.ver], ah
|
||||
mov [s_vesa.ver+2], al
|
||||
mov si, s_vesa
|
||||
call printplain
|
||||
|
||||
_setcursor 4,2
|
||||
mov si, word[es:vi.OemStringPtr]
|
||||
mov di, si
|
||||
|
||||
push ds
|
||||
mov ds, word[es:vi.OemStringPtr+2]
|
||||
call printplain
|
||||
pop ds
|
||||
|
||||
ret
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
calc_vmodes_table:
|
||||
pushad
|
||||
|
||||
; push 0
|
||||
; pop es
|
||||
|
||||
lfs si, [es:vi.VideoModePtr]
|
||||
|
||||
mov bx, modes_table
|
||||
;save no vesa mode of work 320x200, EGA/CGA 256 梥⮢ and 640x480, VGA 16 梥⮢
|
||||
mov word [es:bx], 640
|
||||
mov word [es:bx+2], 480
|
||||
mov word [es:bx+6], 0x13
|
||||
|
||||
mov word [es:bx+10], 640
|
||||
mov word [es:bx+12], 480
|
||||
mov word [es:bx+16], 0x12
|
||||
add bx, 20
|
||||
.next_mode:
|
||||
mov cx, word [fs:si]; mode number
|
||||
cmp cx, -1
|
||||
je .modes_ok.2
|
||||
|
||||
mov ax, 0x4F01
|
||||
mov di, mi
|
||||
int 0x10
|
||||
|
||||
or ah, ah
|
||||
jnz .modes_ok.2;vesa_info.exit
|
||||
|
||||
test [es:mi.ModeAttributes], 00000001b ;videomode support ?
|
||||
jz @f
|
||||
test [es:mi.ModeAttributes], 00010000b ;picture ?
|
||||
jz @f
|
||||
test [es:mi.ModeAttributes], 10000000b ;LFB ?
|
||||
jz @f
|
||||
|
||||
cmp [es:mi.BitsPerPixel], 16 ;List only supported videomodes (16, 24 and 32 bpp)
|
||||
jb @f
|
||||
|
||||
; 16 bpp might actually be 15 bpp
|
||||
cmp [es:mi.BitsPerPixel], 16
|
||||
jne .l0
|
||||
cmp [es:mi.GreenMaskSize], 5
|
||||
jne .l0
|
||||
; mov [es:mi.BitsPerPixel],15
|
||||
jmp @f ; 15 bpp isnt supported ATM
|
||||
|
||||
|
||||
.l0:
|
||||
cmp [es:mi.XRes], 640
|
||||
jb @f
|
||||
cmp [es:mi.YRes], 480
|
||||
jb @f
|
||||
; cmp [es:mi.BitsPerPixel],8
|
||||
; jb @f
|
||||
|
||||
mov ax, [es:mi.XRes]
|
||||
mov [es:bx+0], ax ; +0[2] : resolution X
|
||||
mov ax, [es:mi.YRes]
|
||||
mov [es:bx+2], ax ; +2[2] : resolution Y
|
||||
mov ax, [es:mi.ModeAttributes]
|
||||
mov [es:bx+4], ax ; +4[2] : attributes
|
||||
|
||||
cmp [s_vesa.ver], '2'
|
||||
; jb .lp1
|
||||
jb @f ; We do not use Vesa 1.2 mode is now
|
||||
|
||||
or cx, 0x4000 ; use LFB
|
||||
.lp1:
|
||||
mov [es:bx+6], cx ; +6 : mode number
|
||||
movzx ax, byte [es:mi.BitsPerPixel]
|
||||
mov word [es:bx+8], ax ; +8 : bits per pixel
|
||||
add bx, size_of_step ; size of record
|
||||
|
||||
@@:
|
||||
add si, 2
|
||||
jmp .next_mode
|
||||
|
||||
.modes_ok.2:
|
||||
|
||||
mov word[es:bx], -1 ;end video table
|
||||
mov word[end_cursor], bx ;save end cursor position
|
||||
;;;;;;;;;;;;;;;;;;
|
||||
;Sort array
|
||||
; mov si,modes_table
|
||||
;.new_mode:
|
||||
; mov ax,word [es:si]
|
||||
; cmp ax,-1
|
||||
; je .exxit
|
||||
; add ax,word [es:si+2]
|
||||
; add ax,word [es:si+8]
|
||||
; mov bp,si
|
||||
;.again:
|
||||
; add bp,12
|
||||
; mov bx,word [es:bp]
|
||||
; cmp bx,-1
|
||||
; je .exit
|
||||
; add bx,word [es:bp+2]
|
||||
; add bx,word [es:bp+8]
|
||||
;
|
||||
; cmp ax,bx
|
||||
; ja .loops
|
||||
; jmp .again
|
||||
;.loops:
|
||||
; push dword [es:si]
|
||||
; push dword [es:si+4]
|
||||
; push dword [es:si+8]
|
||||
; push dword [es:bp]
|
||||
; push dword [es:bp+4]
|
||||
; push dword [es:bp+8]
|
||||
;
|
||||
; pop dword [es:si+8]
|
||||
; pop dword [es:si+4]
|
||||
; pop dword [es:si]
|
||||
; pop dword [es:bp+8]
|
||||
; pop dword [es:bp+4]
|
||||
; pop dword [es:bp]
|
||||
; jmp .new_mode
|
||||
;
|
||||
;.exit: add si,12
|
||||
; jmp .new_mode
|
||||
;.exxit:
|
||||
popad
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
draw_current_vmode:
|
||||
push 0
|
||||
pop es
|
||||
|
||||
mov si, word [cursor_pos]
|
||||
|
||||
cmp word [es:si+6], 0x12
|
||||
je .no_vesa_0x12
|
||||
|
||||
cmp word [es:si+6], 0x13
|
||||
je .no_vesa_0x13
|
||||
|
||||
if defined extended_primary_loader
|
||||
mov di, config_file_variables
|
||||
else
|
||||
mov di, loader_block_error
|
||||
end if
|
||||
movzx eax, word[es:si+0]
|
||||
mov ecx, 10
|
||||
call int2strnz
|
||||
mov byte[es:di], 'x'
|
||||
inc di
|
||||
movzx eax, word[es:si+2]
|
||||
call int2strnz
|
||||
mov byte[es:di], 'x'
|
||||
inc di
|
||||
movzx eax, word[es:si+8]
|
||||
call int2strnz
|
||||
mov dword[es:di], 0x00000d0a
|
||||
if defined extended_primary_loader
|
||||
mov si, config_file_variables
|
||||
else
|
||||
mov si, loader_block_error
|
||||
end if
|
||||
push ds
|
||||
push es
|
||||
pop ds
|
||||
call printplain
|
||||
pop ds
|
||||
ret
|
||||
.no_vesa_0x13:
|
||||
mov si, mode0
|
||||
jmp .print
|
||||
.no_vesa_0x12:
|
||||
mov si, mode9
|
||||
.print:
|
||||
call printplain
|
||||
ret
|
||||
;-----------------------------------------------------------------------------
|
||||
check_first_parm:
|
||||
if defined extended_primary_loader
|
||||
mov cx, [number_vm]
|
||||
jcxz .novbemode
|
||||
mov si, modes_table
|
||||
.findvbemode:
|
||||
cmp [es:si+6], cx
|
||||
jnz @f
|
||||
cmp word [es:si+8], 32
|
||||
je .ok_found_mode
|
||||
cmp word [es:si+8], 24
|
||||
je .ok_found_mode
|
||||
cmp word [es:si+8], 16
|
||||
je .ok_found_mode
|
||||
@@:
|
||||
add si, size_of_step
|
||||
cmp word [es:si], -1
|
||||
jnz .findvbemode
|
||||
.novbemode:
|
||||
mov ax, [x_save]
|
||||
test ax, ax
|
||||
jz .zerro
|
||||
mov bx, [y_save]
|
||||
mov si, modes_table
|
||||
call .loops
|
||||
test ax, ax
|
||||
jz .ok_found_mode
|
||||
else
|
||||
mov si, word [preboot_graph]
|
||||
test si, si
|
||||
jnz .no_zero ;if no zero
|
||||
end if
|
||||
.zerro:
|
||||
; mov ax,modes_table
|
||||
; mov word [cursor_pos],ax
|
||||
; mov word [home_cursor],ax
|
||||
; mov word [preboot_graph],ax
|
||||
;SET default video of mode first probe will fined a move of work 1024x768@32
|
||||
mov cx, 32
|
||||
.find_mode:
|
||||
mov ax, 1024
|
||||
mov bx, 768
|
||||
mov si, modes_table
|
||||
call .loops
|
||||
test ax, ax
|
||||
jz .ok_found_mode
|
||||
mov ax, 800
|
||||
mov bx, 600
|
||||
mov si, modes_table
|
||||
call .loops
|
||||
test ax, ax
|
||||
jz .ok_found_mode
|
||||
mov ax, 640
|
||||
mov bx, 480
|
||||
mov si, modes_table
|
||||
call .loops
|
||||
test ax, ax
|
||||
jz .ok_found_mode
|
||||
sub cx, 8
|
||||
jnz .find_mode
|
||||
|
||||
mov si, modes_table
|
||||
if ~ defined extended_primary_loader
|
||||
jmp .ok_found_mode
|
||||
|
||||
|
||||
|
||||
.no_zero:
|
||||
mov bp, word [number_vm]
|
||||
cmp bp, word [es:si+6]
|
||||
jz .ok_found_mode
|
||||
mov ax, word [x_save]
|
||||
mov bx, word [y_save]
|
||||
mov si, modes_table
|
||||
call .loops
|
||||
test ax, ax
|
||||
jz .ok_found_mode
|
||||
|
||||
mov si, modes_table
|
||||
; cmp ax,modes_table
|
||||
; jb .zerro ;check on correct if bellow
|
||||
; cmp ax,word [end_cursor]
|
||||
; ja .zerro ;check on correct if anymore
|
||||
end if
|
||||
|
||||
.ok_found_mode:
|
||||
mov word [home_cursor], si
|
||||
; mov word [cursor_pos],si
|
||||
mov word [preboot_graph], si
|
||||
mov ax, si
|
||||
|
||||
mov ecx, long_v_table
|
||||
|
||||
.loop:
|
||||
add ax, size_of_step
|
||||
cmp ax, word [end_cursor]
|
||||
jae .next_step
|
||||
loop .loop
|
||||
.next_step:
|
||||
sub ax, size_of_step*long_v_table
|
||||
cmp ax, modes_table
|
||||
jae @f
|
||||
mov ax, modes_table
|
||||
@@:
|
||||
|
||||
mov word [home_cursor], ax
|
||||
mov si, [preboot_graph]
|
||||
mov word [cursor_pos], si
|
||||
|
||||
push word [es:si]
|
||||
pop word [x_save]
|
||||
push word [es:si+2]
|
||||
pop word [y_save]
|
||||
push word [es:si+6]
|
||||
pop word [number_vm]
|
||||
|
||||
ret
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
.loops:
|
||||
cmp ax, word [es:si]
|
||||
jne .next
|
||||
cmp bx, word [es:si+2]
|
||||
jne .next
|
||||
jcxz @f
|
||||
cmp cx, word [es:si+8]
|
||||
jne .next
|
||||
@@:
|
||||
xor ax, ax
|
||||
ret
|
||||
.next:
|
||||
add si, size_of_step
|
||||
cmp word [es:si], -1
|
||||
je .exit
|
||||
jmp .loops
|
||||
.exit:
|
||||
or ax, -1
|
||||
ret
|
||||
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
;default_vmode:
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
draw_vmodes_table:
|
||||
_setcursor 9, 2
|
||||
mov si, gr_mode
|
||||
call printplain
|
||||
|
||||
mov si, _st
|
||||
call printplain
|
||||
|
||||
push word [cursor_pos]
|
||||
pop ax
|
||||
push word [home_cursor]
|
||||
pop si
|
||||
mov cx, si
|
||||
|
||||
cmp ax, si
|
||||
je .ok
|
||||
jb .low
|
||||
|
||||
|
||||
add cx, size_of_step*long_v_table
|
||||
|
||||
cmp ax, cx
|
||||
jb .ok
|
||||
|
||||
sub cx, size_of_step*long_v_table
|
||||
add cx, size_of_step
|
||||
cmp cx, word[end_cursor]
|
||||
jae .ok
|
||||
add si, size_of_step
|
||||
push si
|
||||
pop word [home_cursor]
|
||||
jmp .ok
|
||||
|
||||
|
||||
.low:
|
||||
sub cx, size_of_step
|
||||
cmp cx, modes_table
|
||||
jb .ok
|
||||
push cx
|
||||
push cx
|
||||
pop word [home_cursor]
|
||||
pop si
|
||||
|
||||
|
||||
.ok:
|
||||
; calculate scroll position
|
||||
push si
|
||||
mov ax, [end_cursor]
|
||||
sub ax, modes_table
|
||||
mov bx, size_of_step
|
||||
cwd
|
||||
div bx
|
||||
mov si, ax ; si = size of list
|
||||
mov ax, [home_cursor]
|
||||
sub ax, modes_table
|
||||
cwd
|
||||
div bx
|
||||
mov di, ax
|
||||
mov ax, scroll_area_size*long_v_table
|
||||
cwd
|
||||
div si
|
||||
test ax, ax
|
||||
jnz @f
|
||||
inc ax
|
||||
@@:
|
||||
cmp al, scroll_area_size
|
||||
jb @f
|
||||
mov al, scroll_area_size
|
||||
@@:
|
||||
mov cx, ax
|
||||
; cx = scroll height
|
||||
; calculate scroll pos
|
||||
xor bx, bx ; initialize scroll pos
|
||||
sub al, scroll_area_size+1
|
||||
neg al
|
||||
sub si, long_v_table-1
|
||||
jbe @f
|
||||
mul di
|
||||
div si
|
||||
mov bx, ax
|
||||
@@:
|
||||
inc bx
|
||||
imul ax, bx, size_of_step
|
||||
add ax, [home_cursor]
|
||||
mov [scroll_start], ax
|
||||
imul cx, size_of_step
|
||||
add ax, cx
|
||||
mov [scroll_end], ax
|
||||
pop si
|
||||
mov bp, long_v_table ;show rows
|
||||
.@@_next_bit:
|
||||
;clear cursor
|
||||
mov ax, ' '
|
||||
mov word[ds:_r1+21], ax
|
||||
mov word[ds:_r1+50], ax
|
||||
|
||||
mov word[ds:_r2+21], ax
|
||||
mov word[ds:_r2+45], ax
|
||||
|
||||
mov word[ds:_rs+21], ax
|
||||
mov word[ds:_rs+46], ax
|
||||
; draw string
|
||||
cmp word [es:si+6], 0x12
|
||||
je .show_0x12
|
||||
cmp word [es:si+6], 0x13
|
||||
je .show_0x13
|
||||
|
||||
movzx eax, word[es:si]
|
||||
cmp ax, -1
|
||||
je .@@_end
|
||||
mov di, _rs+23
|
||||
mov ecx, 10
|
||||
mov bl, 4
|
||||
call int2str
|
||||
movzx eax, word[es:si+2]
|
||||
inc di
|
||||
mov bl, 4
|
||||
call int2str
|
||||
|
||||
movzx eax, word[es:si+8]
|
||||
inc di
|
||||
mov bl, 2
|
||||
call int2str
|
||||
|
||||
cmp si, word [cursor_pos]
|
||||
jne .next
|
||||
;draw cursor
|
||||
mov word[ds:_rs+21], '>>'
|
||||
mov word[ds:_rs+46], '<<'
|
||||
|
||||
|
||||
|
||||
.next:
|
||||
push si
|
||||
mov si, _rs
|
||||
.@@_sh:
|
||||
; add to the string pseudographics for scrollbar
|
||||
pop bx
|
||||
push bx
|
||||
mov byte [si+53], ' '
|
||||
cmp bx, [scroll_start]
|
||||
jb @f
|
||||
cmp bx, [scroll_end]
|
||||
jae @f
|
||||
mov byte [si+53], 0xDB ; filled bar
|
||||
@@:
|
||||
push bx
|
||||
add bx, size_of_step
|
||||
cmp bx, [end_cursor]
|
||||
jnz @f
|
||||
mov byte [si+53], 31 ; 'down arrow' symbol
|
||||
@@:
|
||||
sub bx, [home_cursor]
|
||||
cmp bx, size_of_step*long_v_table
|
||||
jnz @f
|
||||
mov byte [si+53], 31 ; 'down arrow' symbol
|
||||
@@:
|
||||
pop bx
|
||||
cmp bx, [home_cursor]
|
||||
jnz @f
|
||||
mov byte [si+53], 30 ; 'up arrow' symbol
|
||||
@@:
|
||||
call printplain
|
||||
pop si
|
||||
add si, size_of_step
|
||||
|
||||
dec bp
|
||||
jnz .@@_next_bit
|
||||
|
||||
.@@_end:
|
||||
mov si, _bt
|
||||
call printplain
|
||||
ret
|
||||
.show_0x13:
|
||||
push si
|
||||
|
||||
cmp si, word [cursor_pos]
|
||||
jne @f
|
||||
mov word[ds:_r1+21], '>>'
|
||||
mov word[ds:_r1+50], '<<'
|
||||
@@:
|
||||
mov si, _r1
|
||||
jmp .@@_sh
|
||||
.show_0x12:
|
||||
push si
|
||||
cmp si, word [cursor_pos]
|
||||
jne @f
|
||||
|
||||
mov word[ds:_r2+21], '>>'
|
||||
mov word[ds:_r2+45], '<<'
|
||||
@@:
|
||||
mov si, _r2
|
||||
jmp .@@_sh
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
;Clear arrea of current video page (0xb800)
|
||||
clear_vmodes_table:
|
||||
pusha
|
||||
; draw frames
|
||||
push es
|
||||
push 0xb800
|
||||
pop es
|
||||
mov di, 1444
|
||||
xor ax, ax
|
||||
mov ah, 1*16+15
|
||||
mov cx, 77
|
||||
mov bp, 12
|
||||
.loop_start:
|
||||
rep stosw
|
||||
mov cx, 77
|
||||
add di, 6
|
||||
dec bp
|
||||
jns .loop_start
|
||||
pop es
|
||||
popa
|
||||
ret
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
|
||||
set_vmode:
|
||||
push 0 ;0;x1000
|
||||
pop es
|
||||
|
||||
mov si, word [preboot_graph] ;[preboot_graph]
|
||||
mov cx, word [es:si+6] ; number of mode
|
||||
|
||||
|
||||
mov ax, word [es:si+0] ; resolution X
|
||||
mov bx, word [es:si+2] ; resolution Y
|
||||
|
||||
|
||||
mov word [es:BOOT_LO.x_res], ax ; resolution X
|
||||
mov word [es:BOOT_LO.y_res], bx ; resolution Y
|
||||
mov word [es:BOOT_LO.vesa_mode], cx ; number of mode
|
||||
|
||||
cmp cx, 0x12
|
||||
je .mode0x12_0x13
|
||||
cmp cx, 0x13
|
||||
je .mode0x12_0x13
|
||||
|
||||
|
||||
; cmp byte [s_vesa.ver], '2'
|
||||
; jb .vesa12
|
||||
|
||||
; VESA 2 and Vesa 3
|
||||
|
||||
mov ax, 0x4f01
|
||||
and cx, 0xfff
|
||||
mov di, mi;0xa000
|
||||
int 0x10
|
||||
; LFB
|
||||
mov eax, [es:mi.PhysBasePtr];di+0x28]
|
||||
mov [es:BOOT_LO.lfb], eax
|
||||
; ---- vbe voodoo
|
||||
BytesPerLine = 0x10
|
||||
mov ax, [es:di+BytesPerLine]
|
||||
mov [es:BOOT_LO.pitch], ax
|
||||
; BPP
|
||||
cmp [es:mi.BitsPerPixel], 16
|
||||
jne .l0
|
||||
cmp [es:mi.GreenMaskSize], 5
|
||||
jne .l0
|
||||
mov [es:mi.BitsPerPixel], 15
|
||||
.l0:
|
||||
mov al, byte [es:di+0x19]
|
||||
mov [es:BOOT_LO.bpp], al
|
||||
jmp .exit
|
||||
|
||||
.mode0x12_0x13:
|
||||
mov byte [es:BOOT_LO.bpp], 32
|
||||
or dword [es:BOOT_LO.lfb], 0xFFFFFFFF; 0x800000
|
||||
|
||||
|
||||
; VESA 1.2 PM BANK SWITCH ADDRESS
|
||||
|
||||
;.vesa12:
|
||||
; mov ax, 0x4f0A
|
||||
; xor bx, bx
|
||||
; int 0x10
|
||||
; xor eax, eax
|
||||
; xor ebx, ebx
|
||||
; mov ax, es
|
||||
; shl eax, 4
|
||||
; mov bx, di
|
||||
; add eax, ebx
|
||||
; movzx ebx, word[es:di]
|
||||
; add eax, ebx
|
||||
; push 0x0000
|
||||
; pop es
|
||||
; mov [es:BOOT_LO.bank_sw], eax
|
||||
.exit:
|
||||
ret
|
||||
|
||||
;=============================================================================
|
||||
;=============================================================================
|
||||
;=============================================================================
|
||||
|
||||
16
kernel/branches/kolibri-lldw/boot/et.inc
Normal file
16
kernel/branches/kolibri-lldw/boot/et.inc
Normal file
@@ -0,0 +1,16 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
; Full ASCII code font
|
||||
; only õ,ä,ü added
|
||||
; Kaitz
|
||||
ET_FNT:
|
||||
fontfile file "ETFONT.FNT"
|
||||
|
||||
172
kernel/branches/kolibri-lldw/boot/parsers.inc
Normal file
172
kernel/branches/kolibri-lldw/boot/parsers.inc
Normal file
@@ -0,0 +1,172 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2011-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
; All parsers are called with ds:si -> value of the variable,
|
||||
; possibly with spaces before, and dx = limit of config file.
|
||||
|
||||
; Three subroutines parse_char, parse_number and parse_bool set CF
|
||||
; if something has failed, otherwise return the value in al/ax.
|
||||
|
||||
parse_timeout:
|
||||
; timeout is a number not greater than 9
|
||||
call parse_number
|
||||
jc .nothing
|
||||
cmp ax, 9
|
||||
jbe @f
|
||||
mov ax, 9
|
||||
@@:
|
||||
imul ax, 18
|
||||
mov [es:preboot_timeout], ax
|
||||
.nothing:
|
||||
ret
|
||||
|
||||
parse_resolution:
|
||||
; resolution is <width>*<height>, 'x' can be used instead of '*'
|
||||
; parse width
|
||||
call parse_number
|
||||
jc .nothing
|
||||
; save width
|
||||
xchg ax, bx
|
||||
; test for 'x' or '*'
|
||||
call parse_char
|
||||
cmp al, 'x'
|
||||
jz @f
|
||||
cmp al, '*'
|
||||
jnz .nothing
|
||||
@@:
|
||||
; parse height
|
||||
call parse_number
|
||||
jc .nothing
|
||||
; write width and height
|
||||
mov [es:x_save], bx
|
||||
mov [es:y_save], ax
|
||||
.nothing:
|
||||
ret
|
||||
|
||||
parse_vbemode:
|
||||
; vbemode is a number
|
||||
call parse_number
|
||||
jc .nothing
|
||||
mov [es:number_vm], ax
|
||||
.nothing:
|
||||
ret
|
||||
|
||||
parse_biosdisks:
|
||||
; using biosdisks is a boolean setting
|
||||
call parse_bool
|
||||
jc .nothing
|
||||
; convert 0 to 2, 1 to 1
|
||||
inc ax
|
||||
xor al, 3
|
||||
mov [es:preboot_biosdisk], al
|
||||
.nothing:
|
||||
ret
|
||||
|
||||
parse_imgfrom:
|
||||
; boot device (1-floppy 2-kolibri.img using primary loader, 3-don't use ramdisk)
|
||||
call parse_number
|
||||
jc .nothing
|
||||
cmp al, 1
|
||||
jb .nothing
|
||||
cmp al, 3
|
||||
ja .nothing
|
||||
mov [es:preboot_device], al
|
||||
.nothing:
|
||||
ret
|
||||
|
||||
parse_syspath:
|
||||
; everything except spaces
|
||||
mov bx, preboot_syspath
|
||||
.next_char:
|
||||
call parse_char
|
||||
jc .done
|
||||
mov [es:bx], al
|
||||
inc bx
|
||||
jmp .next_char
|
||||
.done:
|
||||
mov byte[es:bx], 0 ; terminator
|
||||
ret
|
||||
|
||||
parse_char:
|
||||
; skip spaces and return the next character or CF if EOF.
|
||||
cmp si, dx
|
||||
jae .eof
|
||||
lodsb
|
||||
cmp al, ' '
|
||||
jbe parse_char
|
||||
ret
|
||||
.eof:
|
||||
stc
|
||||
ret
|
||||
|
||||
parse_number:
|
||||
; initialize high part of ax to zero
|
||||
xor ax, ax
|
||||
; skip spaces
|
||||
call parse_char
|
||||
jc .bad
|
||||
; al should be a digit
|
||||
sub al, '0'
|
||||
cmp al, 9
|
||||
ja .bad
|
||||
; accumulate the value in cx
|
||||
xchg cx, ax
|
||||
@@:
|
||||
cmp si, dx
|
||||
jae .eof
|
||||
lodsb
|
||||
sub al, '0'
|
||||
cmp al, 9
|
||||
ja .end
|
||||
imul cx, 10
|
||||
add cx, ax
|
||||
jmp @b
|
||||
; if the end is caused by non-digit, unwind the last character
|
||||
.end:
|
||||
dec si
|
||||
.eof:
|
||||
xchg cx, ax
|
||||
clc
|
||||
ret
|
||||
.bad:
|
||||
stc
|
||||
ret
|
||||
|
||||
parse_bool:
|
||||
; skip spaces
|
||||
call parse_char
|
||||
jc .bad
|
||||
; Boolean false can be represented as 0=no=off,
|
||||
; boolean true can be represented as 1=yes=on.
|
||||
cmp al, '0'
|
||||
jz .false
|
||||
cmp al, '1'
|
||||
jz .true
|
||||
mov ah, al
|
||||
cmp si, dx
|
||||
jae .bad
|
||||
lodsb
|
||||
cmp ax, 'n'*256 + 'o'
|
||||
jz .false
|
||||
cmp ax, 'o'*256 + 'f'
|
||||
jz .false
|
||||
cmp ax, 'y'*256 + 'e'
|
||||
jz .true
|
||||
cmp ax, 'o'*256 + 'n'
|
||||
jz .true
|
||||
.bad:
|
||||
stc
|
||||
ret
|
||||
.true:
|
||||
xor ax, ax
|
||||
inc ax
|
||||
ret
|
||||
.false:
|
||||
xor ax, ax
|
||||
ret
|
||||
46
kernel/branches/kolibri-lldw/boot/preboot.inc
Normal file
46
kernel/branches/kolibri-lldw/boot/preboot.inc
Normal file
@@ -0,0 +1,46 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
display_modechg db 0 ; display mode change for text, yes/no (0 or 2)
|
||||
;
|
||||
; !! Important note !!
|
||||
;
|
||||
; Must be set to 2, to avoid two screenmode
|
||||
; changes within a very short period of time.
|
||||
|
||||
display_atboot db 0 ; show boot screen messages ( 2-no )
|
||||
|
||||
preboot_graph dw 0 ; graph mode
|
||||
x_save dw 0 ; x
|
||||
y_save dw 0 ; y
|
||||
number_vm dw 0 ;
|
||||
;pixel_save dw 0 ; per to pixel
|
||||
preboot_gprobe db 0 ; probe vesa3 videomodes (1-no, 2-yes)
|
||||
preboot_debug db 0 ; load kernel in debug mode? (1-yes, 2-no)
|
||||
preboot_launcher db 0 ; start launcher after kernel is loaded? (1-yes, 2-no)
|
||||
preboot_dma db 0 ; use DMA for access to HDD (1-always, 2-only for read, 3-never)
|
||||
preboot_device db 0 ; device to load ramdisk from
|
||||
; 1-floppy 2-harddisk 3-kernel restart
|
||||
; 4-format ram disk 5-don't use ramdisk
|
||||
; !!!! 0 - autodetect !!!!
|
||||
preboot_biosdisk db 0 ; use V86 to access disks through BIOS (1-yes, 2-no)
|
||||
preboot_syspath db '/RD/1',0 ; path to /sys dir
|
||||
rb 20-($-preboot_syspath)
|
||||
if defined extended_primary_loader
|
||||
; timeout in 1/18th of second for config settings screen
|
||||
preboot_timeout dw PREBOOT_TIMEOUT*18
|
||||
end if
|
||||
|
||||
if $>0x200
|
||||
ERROR:
|
||||
prebooting parameters must fit in first sector!!!
|
||||
end if
|
||||
hdsysimage db 'KOLIBRI.IMG',0 ; load from
|
||||
image_save db 'KOLIBRI.IMG',0 ; save to
|
||||
128
kernel/branches/kolibri-lldw/boot/rdload.inc
Normal file
128
kernel/branches/kolibri-lldw/boot/rdload.inc
Normal file
@@ -0,0 +1,128 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
read_ramdisk:
|
||||
; READ RAMDISK IMAGE FROM HD (only for IDE0, IDE1, IDE2, IDE3)
|
||||
|
||||
cmp byte [BOOT.rd_load_from], RD_LOAD_FROM_HD
|
||||
jne no_sys_on_hd.1
|
||||
|
||||
xor ebp, ebp
|
||||
.hd_loop:
|
||||
lea eax, [ebp+'0']
|
||||
mov [read_image_fsinfo.name_digit], al
|
||||
movzx eax, byte [DRIVE_DATA+2+ebp]
|
||||
test eax, eax
|
||||
jz .next_hd
|
||||
push eax
|
||||
mov esi, 1
|
||||
.partition_loop:
|
||||
mov eax, esi
|
||||
push -'0'
|
||||
@@:
|
||||
xor edx, edx
|
||||
div [_10]
|
||||
push edx
|
||||
test eax, eax
|
||||
jnz @b
|
||||
mov edi, read_image_fsinfo.partition
|
||||
@@:
|
||||
pop eax
|
||||
add al, '0'
|
||||
stosb
|
||||
jnz @b
|
||||
mov byte [edi-1], '/'
|
||||
push esi edi
|
||||
mov esi, bootpath1
|
||||
mov ecx, bootpath1.len
|
||||
rep movsb
|
||||
call read_image
|
||||
test eax, eax
|
||||
jz .yes
|
||||
cmp eax, 6
|
||||
jz .yes
|
||||
pop edi
|
||||
push edi
|
||||
mov esi, bootpath2
|
||||
mov ecx, bootpath2.len
|
||||
rep movsb
|
||||
call read_image
|
||||
test eax, eax
|
||||
jz .yes
|
||||
cmp eax, 6
|
||||
jz .yes
|
||||
pop edi esi
|
||||
inc esi
|
||||
cmp esi, [esp]
|
||||
jbe .partition_loop
|
||||
pop eax
|
||||
.next_hd:
|
||||
inc ebp
|
||||
cmp ebp, 4
|
||||
jb .hd_loop
|
||||
jmp no_sys_on_hd
|
||||
.yes:
|
||||
DEBUGF 1, "K : RD found: %s\n", read_image_fsinfo.name
|
||||
pop edi esi eax
|
||||
|
||||
call register_ramdisk
|
||||
jmp yes_sys_on_hd
|
||||
;-----------------------------------------------------------------------------
|
||||
iglobal
|
||||
align 4
|
||||
read_image_fsinfo:
|
||||
dd 0 ; function: read
|
||||
dq 0 ; offset: zero
|
||||
dd 1474560 ; size
|
||||
dd RAMDISK ; buffer
|
||||
.name db '/hd'
|
||||
.name_digit db '0'
|
||||
db '/'
|
||||
.partition:
|
||||
rb 64 ; should be enough for '255/KOLIBRI/KOLIBRI.IMG'
|
||||
|
||||
bootpath1 db 'KOLIBRI.IMG',0
|
||||
.len = $ - bootpath1
|
||||
bootpath2 db 'KOLIBRI/KOLIBRI.IMG',0
|
||||
.len = $ - bootpath2
|
||||
endg
|
||||
|
||||
read_image:
|
||||
mov ebx, read_image_fsinfo
|
||||
pushad
|
||||
call file_system_lfn_protected
|
||||
popad
|
||||
ret
|
||||
|
||||
no_sys_on_hd:
|
||||
DEBUGF 1, "K : RD not found\n"
|
||||
.1:
|
||||
; test_to_format_ram_disk (need if not using ram disk)
|
||||
cmp byte [BOOT.rd_load_from], RD_LOAD_FROM_FORMAT
|
||||
jne not_format_ram_disk
|
||||
; format_ram_disk
|
||||
mov edi, RAMDISK
|
||||
mov ecx, 0x1080
|
||||
xor eax, eax
|
||||
@@:
|
||||
stosd
|
||||
loop @b
|
||||
|
||||
mov ecx, 0x58F7F
|
||||
mov eax, 0xF6F6F6F6
|
||||
@@:
|
||||
stosd
|
||||
loop @b
|
||||
|
||||
mov [RAMDISK+0x200], dword 0xFFFFF0 ; fat table
|
||||
mov [RAMDISK+0x4200], dword 0xFFFFF0
|
||||
|
||||
not_format_ram_disk:
|
||||
yes_sys_on_hd:
|
||||
102
kernel/branches/kolibri-lldw/boot/ru.inc
Normal file
102
kernel/branches/kolibri-lldw/boot/ru.inc
Normal file
@@ -0,0 +1,102 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
; Generated by RUFNT.EXE
|
||||
; By BadBugsKiller (C)
|
||||
; Modifyed by BadBugsKiller 12.01.2004 17:45
|
||||
; Шрифт уменьшен в размере и теперь состоит из 2-ух частей,
|
||||
; содержащих только символы русского алфавита.
|
||||
; символы в кодировке ASCII (ДОС'овская), кодовая страница 866.
|
||||
RU_FNT1:
|
||||
db 0x00, 0x00, 0x1E, 0x36, 0x66, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xFE, 0x62, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xFE, 0x66, 0x62, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xFF, 0xC3, 0x81, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xDB, 0xDB, 0x5A, 0x5A, 0x7E, 0x7E, 0x5A, 0xDB, 0xDB, 0xDB, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x06, 0x3C, 0x06, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x6C, 0x38, 0xC6, 0xC6, 0xC6, 0xCE, 0xDE, 0xF6, 0xE6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xE6, 0x66, 0x6C, 0x6C, 0x78, 0x78, 0x6C, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x1F, 0x36, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xCF, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
db 0x00, 0x00, 0xFC, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC0, 0xC0, 0xC0, 0xC0, 0xC2, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xFF, 0xDB, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x7E, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xC6, 0xC6, 0x6C, 0x7C, 0x38, 0x38, 0x7C, 0x6C, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xFF, 0x03, 0x03, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xFE, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xFF, 0x03, 0x03, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xF8, 0xF0, 0xB0, 0x30, 0x3E, 0x33, 0x33, 0x33, 0x33, 0x7E, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xC3, 0xC3, 0xC3, 0xC3, 0xF3, 0xDB, 0xDB, 0xDB, 0xDB, 0xF3, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xF0, 0x60, 0x60, 0x60, 0x7C, 0x66, 0x66, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x26, 0x3E, 0x26, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xCE, 0xDB, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xDB, 0xDB, 0xCE, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x3F, 0x66, 0x66, 0x66, 0x3E, 0x3E, 0x66, 0x66, 0x66, 0xE7, 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0C, 0x7C, 0xCC, 0xCC, 0xCC, 0x76, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x02, 0x06, 0x7C, 0xC0, 0xC0, 0xFC, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x66, 0x66, 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x62, 0x62, 0x60, 0x60, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0xFF, 0xC3, 0xC3, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xFE, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0x54, 0x7C, 0x54, 0xD6, 0xD6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x3C, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xCE, 0xD6, 0xE6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x6C, 0x38, 0xC6, 0xC6, 0xCE, 0xD6, 0xE6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x6C, 0x78, 0x78, 0x6C, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x36, 0x66, 0x66, 0x66, 0x66, 0xE6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xEE, 0xFE, 0xFE, 0xD6, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xFE, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
RU_FNT2:
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x66, 0x66, 0x66, 0x66, 0x66, 0x7C, 0x60, 0x60, 0xF0, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x5A, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x3C, 0x18, 0x7E, 0xDB, 0xDB, 0xDB, 0xDB, 0xDB, 0x7E, 0x18, 0x18, 0x3C, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0x6C, 0x38, 0x38, 0x38, 0x6C, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xFF, 0x03, 0x03, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xFE, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xD6, 0xFE, 0x03, 0x03, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB0, 0xB0, 0x3E, 0x33, 0x33, 0x7E, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xF6, 0xDE, 0xDE, 0xF6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x60, 0x7C, 0x66, 0x66, 0xFC, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0x06, 0x3E, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xDB, 0xDB, 0xFB, 0xDB, 0xDB, 0xCE, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xC6, 0xC6, 0x7E, 0x36, 0x66, 0xE7, 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
db 0x6C, 0x00, 0xFE, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xFE, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x6C, 0x00, 0x7C, 0xC6, 0xC6, 0xFC, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xC8, 0xF8, 0xC8, 0xC0, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0xC6, 0xC0, 0xF8, 0xC0, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x66, 0x00, 0x3C, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x6C, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x6C, 0x38, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x6C, 0x38, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7E, 0x06, 0x06, 0xC6, 0x7C, 0x00
|
||||
db 0x00, 0x38, 0x6C, 0x6C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0xEC, 0x6C, 0x3C, 0x1C, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0xCF, 0xCD, 0xEF, 0xEC, 0xFF, 0xDC, 0xDC, 0xCC, 0xCC, 0xCC, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0xC6, 0x7C, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x7C, 0xC6, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
408
kernel/branches/kolibri-lldw/boot/shutdown.inc
Normal file
408
kernel/branches/kolibri-lldw/boot/shutdown.inc
Normal file
@@ -0,0 +1,408 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; Shutdown for Menuet ;;
|
||||
;; ;;
|
||||
;; Distributed under General Public License ;;
|
||||
;; See file COPYING for details. ;;
|
||||
;; Copyright 2003 Ville Turjanmaa ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
align 4
|
||||
system_shutdown: ; shut down the system
|
||||
|
||||
cmp [BOOT.shutdown_type], SYSTEM_SHUTDOWN
|
||||
jb @F
|
||||
cmp [BOOT.shutdown_type], SYSTEM_RESTART
|
||||
jbe .valid
|
||||
@@:
|
||||
ret
|
||||
.valid:
|
||||
call stop_all_services
|
||||
|
||||
yes_shutdown_param:
|
||||
; Shutdown other CPUs, if initialized
|
||||
cmp [ap_initialized], 0
|
||||
jz .no_shutdown_cpus
|
||||
mov edi, [LAPIC_BASE]
|
||||
add edi, 300h
|
||||
mov esi, smpt+4
|
||||
mov ebx, [cpu_count]
|
||||
dec ebx
|
||||
.shutdown_cpus_loop:
|
||||
lodsd
|
||||
push esi
|
||||
xor esi, esi
|
||||
inc esi
|
||||
shl eax, 24
|
||||
mov [edi+10h], eax
|
||||
; assert INIT IPI
|
||||
mov dword [edi], 0C500h
|
||||
call delay_ms
|
||||
@@:
|
||||
test dword [edi], 1000h
|
||||
jnz @b
|
||||
; deassert INIT IPI
|
||||
mov dword [edi], 8500h
|
||||
call delay_ms
|
||||
@@:
|
||||
test dword [edi], 1000h
|
||||
jnz @b
|
||||
; don't send STARTUP IPI: let other CPUs be in wait-for-startup state
|
||||
pop esi
|
||||
dec ebx
|
||||
jnz .shutdown_cpus_loop
|
||||
.no_shutdown_cpus:
|
||||
|
||||
cli
|
||||
call IRQ_mask_all
|
||||
|
||||
movzx eax, [BOOT.shutdown_type]
|
||||
cmp al, SYSTEM_RESTART
|
||||
jne @F
|
||||
|
||||
; load kernel.mnt to _CLEAN_ZONE
|
||||
mov ebx, kernel_file_load
|
||||
pushad
|
||||
call file_system_lfn
|
||||
popad
|
||||
@@:
|
||||
mov esi, OS_BASE+restart_code_start ; move kernel re-starter to 0x5000:0
|
||||
mov edi, OS_BASE+0x50000
|
||||
mov ecx, (restart_code_end - restart_code_start)/4
|
||||
rep movsd
|
||||
|
||||
cmp [BOOT.shutdown_type], SYSTEM_SHUTDOWN
|
||||
jne not_power_off
|
||||
|
||||
; system_power_off
|
||||
|
||||
mov ebx, [acpi_fadt_base]
|
||||
test ebx, ebx
|
||||
jz no_acpi
|
||||
cmp [ebx+ACPI_TABLE.Signature], 'FACP'
|
||||
jne no_acpi
|
||||
mov esi, [acpi_ssdt_base] ; first SSDT is DSDT
|
||||
test esi, esi
|
||||
jz no_acpi
|
||||
cmp [esi+ACPI_TABLE.Signature], 'DSDT'
|
||||
jne no_acpi
|
||||
mov eax, [esi+ACPI_TABLE.Length]
|
||||
sub eax, 36+4
|
||||
jbe no_acpi
|
||||
add esi, 36
|
||||
.scan_dsdt:
|
||||
cmp dword [esi], '_S5_'
|
||||
jnz .scan_dsdt_cont
|
||||
cmp byte [esi+4], 12h ; DefPackage opcode
|
||||
jnz .scan_dsdt_cont
|
||||
mov dl, [esi+6]
|
||||
cmp dl, 4 ; _S5_ package must contain 4 bytes
|
||||
; ...in theory; in practice, VirtualBox has 2 bytes
|
||||
ja .scan_dsdt_cont
|
||||
cmp dl, 1
|
||||
jb .scan_dsdt_cont
|
||||
lea esi, [esi+7]
|
||||
xor ecx, ecx
|
||||
cmp byte [esi], 0 ; 0 means zero byte, 0Ah xx means byte xx
|
||||
jz @f
|
||||
cmp byte [esi], 0xA
|
||||
jnz no_acpi
|
||||
inc esi
|
||||
mov cl, [esi]
|
||||
@@:
|
||||
inc esi
|
||||
cmp dl, 2
|
||||
jb @f
|
||||
cmp byte [esi], 0
|
||||
jz @f
|
||||
cmp byte [esi], 0xA
|
||||
jnz no_acpi
|
||||
inc esi
|
||||
mov ch, [esi]
|
||||
@@:
|
||||
jmp do_acpi_power_off
|
||||
.scan_dsdt_cont:
|
||||
inc esi
|
||||
dec eax
|
||||
jnz .scan_dsdt
|
||||
jmp no_acpi
|
||||
do_acpi_power_off:
|
||||
mov edx, [ebx+ACPI_FADT.SMI_CMD]
|
||||
test edx, edx
|
||||
jz .nosmi
|
||||
mov al, [ebx+ACPI_FADT.ACPI_ENABLE]
|
||||
out dx, al
|
||||
mov edx, [ebx+ACPI_FADT.PM1a_CNT_BLK]
|
||||
@@:
|
||||
in ax, dx
|
||||
test al, 1
|
||||
jz @b
|
||||
.nosmi:
|
||||
and cx, 0x0707
|
||||
shl cx, 2
|
||||
or cx, 0x2020
|
||||
mov edx, [ebx+ACPI_FADT.PM1a_CNT_BLK]
|
||||
in ax, dx
|
||||
and ax, 203h
|
||||
or ah, cl
|
||||
out dx, ax
|
||||
mov edx, [ebx+ACPI_FADT.PM1b_CNT_BLK]
|
||||
test edx, edx
|
||||
jz @f
|
||||
in ax, dx
|
||||
and ax, 203h
|
||||
or ah, ch
|
||||
out dx, ax
|
||||
@@:
|
||||
jmp no_acpi
|
||||
|
||||
not_power_off:
|
||||
cmp [BOOT.shutdown_type], SYSTEM_REBOOT
|
||||
jnz not_reboot
|
||||
; try to reboot via ACPI fixed features
|
||||
mov ebx, [acpi_fadt_base]
|
||||
test ebx, ebx
|
||||
jz no_acpi
|
||||
cmp [ebx+ACPI_TABLE.Signature], 'FACP'
|
||||
jne no_acpi
|
||||
cmp [ebx+ACPI_FADT.Length], ACPI_FADT.RESET_VALUE
|
||||
jbe no_acpi
|
||||
test [ebx+ACPI_FADT.Flags], 1 SHL 10 ; reset_reg_supported
|
||||
jz no_acpi
|
||||
cmp [ebx+ACPI_FADT.RESET_REG.ASID], ASID.SYSTEM_IO
|
||||
jnz no_acpi
|
||||
cmp [ebx+ACPI_FADT.RESET_REG.BitWidth], 8
|
||||
jnz no_acpi
|
||||
cmp [ebx+ACPI_FADT.RESET_REG.BitOffset], 0
|
||||
jnz no_acpi
|
||||
cmp [ebx+ACPI_FADT.RESET_REG.AccessSize], ACCESS_SIZE.BYTE
|
||||
ja no_acpi
|
||||
cmp [ebx+ACPI_FADT.RESET_REG.Address.hi], 0
|
||||
jnz no_acpi
|
||||
; 'enable' ACPI
|
||||
mov edx, [ebx+ACPI_FADT.SMI_CMD]
|
||||
test edx, edx
|
||||
jz .nosmi
|
||||
mov al, [ebx+ACPI_FADT.ACPI_ENABLE]
|
||||
out dx, al
|
||||
mov edx, [ebx+ACPI_FADT.PM1a_CNT_BLK]
|
||||
@@:
|
||||
in ax, dx
|
||||
test al, 1
|
||||
jz @b
|
||||
.nosmi:
|
||||
|
||||
mov edx, [ebx+ACPI_FADT.RESET_REG.Address.lo]
|
||||
movzx eax, [ebx+ACPI_FADT.RESET_VALUE]
|
||||
out dx, al
|
||||
jmp no_acpi
|
||||
|
||||
not_reboot:
|
||||
no_acpi:
|
||||
call create_trampoline_pgmap
|
||||
mov cr3, eax
|
||||
jmp @F
|
||||
org $-OS_BASE
|
||||
@@:
|
||||
|
||||
;disable paging
|
||||
|
||||
mov eax, cr0
|
||||
and eax, 0x7FFFFFFF
|
||||
mov cr0, eax
|
||||
mov eax, cr3
|
||||
mov cr3, eax
|
||||
|
||||
jmp 0x50000
|
||||
|
||||
align 4
|
||||
restart_code_start:
|
||||
org 0x50000
|
||||
|
||||
cmp [BOOT_LO.shutdown_type], SYSTEM_RESTART
|
||||
jne @F
|
||||
|
||||
mov esi, _CLEAN_ZONE-OS_BASE
|
||||
mov edi, 0x10000
|
||||
mov ecx, 0x31000/4
|
||||
cld
|
||||
rep movsd
|
||||
@@:
|
||||
|
||||
xor ebx, ebx
|
||||
xor edx, edx
|
||||
xor ecx, ecx
|
||||
xor esi, esi
|
||||
xor edi, edi
|
||||
xor ebp, ebp
|
||||
lidt [.idt]
|
||||
lgdt [.gdt]
|
||||
jmp 8:@f
|
||||
align 8
|
||||
.gdt:
|
||||
; selector 0 - not used
|
||||
dw 23
|
||||
dd .gdt
|
||||
dw 0
|
||||
; selector 8 - code from 5000:0000 to 1000:FFFF
|
||||
dw 0FFFFh
|
||||
dw 0
|
||||
db 5
|
||||
db 10011011b
|
||||
db 00000000b
|
||||
db 0
|
||||
; selector 10h - data from 1000:0000 to 1000:FFFF
|
||||
dw 0FFFFh
|
||||
dw 0
|
||||
db 1
|
||||
db 10010011b
|
||||
db 00000000b
|
||||
db 0
|
||||
.idt:
|
||||
dw 256*4
|
||||
dd 0
|
||||
org $ - 0x50000
|
||||
use16
|
||||
@@:
|
||||
mov ax, 10h
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
mov eax, cr0
|
||||
and eax, not 80000001h
|
||||
mov cr0, eax
|
||||
jmp 0x5000:.real_mode
|
||||
|
||||
align 4
|
||||
.real_mode:
|
||||
|
||||
; setup stack
|
||||
|
||||
mov ax, (TMP_STACK_TOP and 0xF0000) shr 4
|
||||
mov ss, ax
|
||||
mov esp, TMP_STACK_TOP and 0xFFFF
|
||||
|
||||
;remap IRQs
|
||||
mov al, 0x11
|
||||
out 0x20, al
|
||||
out 0xA0, al
|
||||
|
||||
mov al, 0x08
|
||||
out 0x21, al
|
||||
mov al, 0x70
|
||||
out 0xA1, al
|
||||
|
||||
mov al, 0x04
|
||||
out 0x21, al
|
||||
mov al, 0x02
|
||||
out 0xA1, al
|
||||
|
||||
mov al, 0x01
|
||||
out 0x21, al
|
||||
out 0xA1, al
|
||||
|
||||
mov al, 0xB8
|
||||
out 0x21, al
|
||||
mov al, 0xBD
|
||||
out 0xA1, al
|
||||
|
||||
mov al, 00110100b
|
||||
out 43h, al
|
||||
mov al, 0xFF
|
||||
out 40h, al
|
||||
out 40h, al
|
||||
|
||||
xor ax, ax
|
||||
mov ds, ax
|
||||
mov al, [BOOT_LO.shutdown_type]
|
||||
cmp al, SYSTEM_RESTART
|
||||
je .restart
|
||||
|
||||
cmp al, SYSTEM_SHUTDOWN
|
||||
je .APM_PowerOff
|
||||
|
||||
mov word[0x0472], 0x1234
|
||||
jmp 0xF000:0xFFF0
|
||||
|
||||
.APM_PowerOff:
|
||||
mov ax, 5304h
|
||||
xor bx, bx
|
||||
int 15h
|
||||
;!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
mov ax, 0x5300
|
||||
xor bx, bx
|
||||
int 0x15
|
||||
push ax
|
||||
|
||||
mov ax, 0x5301
|
||||
xor bx, bx
|
||||
int 0x15
|
||||
|
||||
mov ax, 0x5308
|
||||
mov bx, 1
|
||||
mov cx, bx
|
||||
int 0x15
|
||||
|
||||
mov ax, 0x530E
|
||||
xor bx, bx
|
||||
pop cx
|
||||
int 0x15
|
||||
|
||||
mov ax, 0x530D
|
||||
mov bx, 1
|
||||
mov cx, bx
|
||||
int 0x15
|
||||
|
||||
mov ax, 0x530F
|
||||
mov bx, 1
|
||||
mov cx, bx
|
||||
int 0x15
|
||||
|
||||
mov ax, 0x5307
|
||||
mov bx, 1
|
||||
mov cx, 3
|
||||
int 0x15
|
||||
;!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
jmp $
|
||||
|
||||
.restart:
|
||||
|
||||
; (hint by Black_mirror)
|
||||
; We must read data from keyboard port,
|
||||
; because there may be situation when previous keyboard interrupt is lost
|
||||
; (due to return to real mode and IRQ reprogramming)
|
||||
; and next interrupt will not be generated (as keyboard waits for handling)
|
||||
|
||||
mov cx, 16
|
||||
@@:
|
||||
in al, 0x64
|
||||
test al, 1
|
||||
jz @F
|
||||
in al, 0x60
|
||||
loop @B
|
||||
@@:
|
||||
|
||||
; bootloader interface
|
||||
push 0x1000
|
||||
pop ds
|
||||
push 0
|
||||
pop es
|
||||
mov si, [es:BOOT_LO.kernel_restart]
|
||||
mov ax, 'KL'
|
||||
jmp 0x1000:0000
|
||||
|
||||
align 4
|
||||
org restart_code_start + $
|
||||
restart_code_end:
|
||||
|
||||
org $+OS_BASE
|
||||
use32
|
||||
124
kernel/branches/kolibri-lldw/bootbios.asm
Normal file
124
kernel/branches/kolibri-lldw/bootbios.asm
Normal file
@@ -0,0 +1,124 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; 16 BIT ENTRY FROM BOOTSECTOR ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
include 'macros.inc'
|
||||
include 'struct.inc'
|
||||
include 'lang.inc'
|
||||
include 'encoding.inc'
|
||||
include 'const.inc'
|
||||
|
||||
os_code = code_l - tmp_gdt
|
||||
PREBOOT_TIMEOUT = 5 ; seconds
|
||||
|
||||
use16
|
||||
org 0x0
|
||||
jmp start_of_code
|
||||
|
||||
if lang eq sp
|
||||
include "kernelsp.inc" ; spanish kernel messages
|
||||
else if lang eq et
|
||||
version db 'Kolibri OS versioon 0.7.7.0+ ',13,10,13,10,0
|
||||
else
|
||||
version db 'Kolibri OS version 0.7.7.0+ ',13,10,13,10,0
|
||||
end if
|
||||
|
||||
include "boot/bootstr.inc" ; language-independent boot messages
|
||||
include "boot/preboot.inc"
|
||||
|
||||
if lang eq ge
|
||||
include "boot/bootge.inc" ; german system boot messages
|
||||
else if lang eq sp
|
||||
include "boot/bootsp.inc" ; spanish system boot messages
|
||||
else if lang eq ru
|
||||
include "boot/bootru.inc" ; russian system boot messages
|
||||
include "boot/ru.inc" ; Russian font
|
||||
else if lang eq et
|
||||
include "boot/bootet.inc" ; estonian system boot messages
|
||||
include "boot/et.inc" ; Estonian font
|
||||
else
|
||||
include "boot/booten.inc" ; english system boot messages
|
||||
end if
|
||||
|
||||
include "boot/bootcode.inc" ; 16 bit system boot code
|
||||
include "bus/pci/pci16.inc"
|
||||
include "detect/biosdisk.inc"
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; SWITCH TO 32 BIT PROTECTED MODE ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
; CR0 Flags - Protected mode and Paging
|
||||
|
||||
mov ecx, CR0_PE+CR0_AM
|
||||
|
||||
; Enabling 32 bit protected mode
|
||||
|
||||
sidt [cs:old_ints_h]
|
||||
|
||||
cli ; disable all irqs
|
||||
cld
|
||||
mov al, 255 ; mask all irqs
|
||||
out 0xa1, al
|
||||
out 0x21, al
|
||||
l.5:
|
||||
in al, 0x64 ; Enable A20
|
||||
test al, 2
|
||||
jnz l.5
|
||||
mov al, 0xD1
|
||||
out 0x64, al
|
||||
l.6:
|
||||
in al, 0x64
|
||||
test al, 2
|
||||
jnz l.6
|
||||
mov al, 0xDF
|
||||
out 0x60, al
|
||||
l.7:
|
||||
in al, 0x64
|
||||
test al, 2
|
||||
jnz l.7
|
||||
mov al, 0xFF
|
||||
out 0x64, al
|
||||
|
||||
lgdt [cs:tmp_gdt] ; Load GDT
|
||||
mov eax, cr0 ; protected mode
|
||||
or eax, ecx
|
||||
and eax, 10011111b *65536*256 + 0xffffff ; caching enabled
|
||||
mov cr0, eax
|
||||
jmp pword os_code:B32 ; jmp to enable 32 bit mode
|
||||
|
||||
align 8
|
||||
tmp_gdt:
|
||||
|
||||
dw 23
|
||||
dd tmp_gdt+0x10000
|
||||
dw 0
|
||||
code_l:
|
||||
dw 0xffff
|
||||
dw 0x0000
|
||||
db 0x00
|
||||
dw 11011111b *256 +10011010b
|
||||
db 0x00
|
||||
|
||||
dw 0xffff
|
||||
dw 0x0000
|
||||
db 0x00
|
||||
dw 11011111b *256 +10010010b
|
||||
db 0x00
|
||||
|
||||
include "data16.inc"
|
||||
|
||||
if ~ lang eq sp
|
||||
diff16 "end of bootcode",0,$+0x10000
|
||||
end if
|
||||
|
||||
use32
|
||||
org $+0x10000
|
||||
|
||||
align 4
|
||||
B32:
|
||||
3
kernel/branches/kolibri-lldw/bootloader/Tupfile.lua
Normal file
3
kernel/branches/kolibri-lldw/bootloader/Tupfile.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("echo lang fix " .. ((tup.getconfig("LANG") == "") and "en" or tup.getconfig("LANG")) .. " > %o", {"lang.inc"})
|
||||
tup.rule({"boot_fat12.asm", extra_inputs = {"lang.inc"}}, "fasm %f %o", "boot_fat12.bin")
|
||||
304
kernel/branches/kolibri-lldw/bootloader/boot_fat12.asm
Normal file
304
kernel/branches/kolibri-lldw/bootloader/boot_fat12.asm
Normal file
@@ -0,0 +1,304 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; FAT12 boot sector for Kolibri OS
|
||||
;
|
||||
; Copyright (C) Alex Nogueira Teixeira
|
||||
; Copyright (C) Diamond
|
||||
; Copyright (C) Dmitry Kartashov aka shurf
|
||||
;
|
||||
; Distributed under GPL, see file COPYING for details
|
||||
;
|
||||
; Version 1.0
|
||||
|
||||
include "lang.inc"
|
||||
|
||||
lf = 0ah
|
||||
cr = 0dh
|
||||
|
||||
pos_read_tmp = 0700h ;position for temporary read
|
||||
boot_program = 07c00h ;position for boot code
|
||||
seg_read_kernel = 01000h ;segment to kernel read
|
||||
|
||||
jmp start_program
|
||||
nop
|
||||
|
||||
; Boot Sector and BPB Structure
|
||||
include 'floppy1440.inc'
|
||||
;include 'floppy2880.inc'
|
||||
;include 'floppy1680.inc'
|
||||
;include 'floppy1743.inc'
|
||||
|
||||
start_program:
|
||||
; <Efremenkov S.V.>
|
||||
cld ;clear direction flag for Phoenix BIOS, see next "lodsb"
|
||||
xor ax, ax
|
||||
cli
|
||||
mov ss, ax
|
||||
mov sp, boot_program
|
||||
sti
|
||||
; <\Efremenkov S.V.>
|
||||
push ss
|
||||
pop ds
|
||||
|
||||
; print loading string
|
||||
mov si, loading+boot_program
|
||||
loop_loading:
|
||||
lodsb
|
||||
or al, al
|
||||
jz read_root_directory
|
||||
mov ah, 0eh
|
||||
mov bx, 7
|
||||
int 10h
|
||||
jmp loop_loading
|
||||
|
||||
read_root_directory:
|
||||
push ss
|
||||
pop es
|
||||
|
||||
; calculate some disk parameters
|
||||
; - beginning sector of RootDir
|
||||
mov ax, word [BPB_FATSz16+boot_program]
|
||||
xor cx, cx
|
||||
mov cl, byte [BPB_NumFATs+boot_program]
|
||||
mul cx
|
||||
add ax, word [BPB_RsvdSecCnt+boot_program]
|
||||
mov word [FirstRootDirSecNum+boot_program], ax ; 19
|
||||
mov si, ax
|
||||
|
||||
; - count of sectors in RootDir
|
||||
mov bx, word [BPB_BytsPerSec+boot_program]
|
||||
mov cl, 5 ; divide ax by 32
|
||||
shr bx, cl ; bx = directory entries per sector
|
||||
mov ax, word [BPB_RootEntCnt+boot_program]
|
||||
xor dx, dx
|
||||
div bx
|
||||
mov word [RootDirSecs+boot_program], ax ; 14
|
||||
|
||||
; - data start
|
||||
add si, ax ; add beginning sector of RootDir and count sectors in RootDir
|
||||
mov word [data_start+boot_program], si ; 33
|
||||
; reading root directory
|
||||
; al=count root dir sectrors !!!! TODO: al, max 255 sectors !!!!
|
||||
mov ah, 2 ; read
|
||||
push ax
|
||||
|
||||
mov ax, word [FirstRootDirSecNum+boot_program]
|
||||
call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector)
|
||||
pop ax
|
||||
mov bx, pos_read_tmp ; es:bx read buffer
|
||||
call read_sector
|
||||
|
||||
mov si, bx ; read buffer address: es:si
|
||||
mov ax, [RootDirSecs+boot_program]
|
||||
mul word [BPB_BytsPerSec+boot_program]
|
||||
add ax, si ; AX = end of root dir. in buffer pos_read_tmp
|
||||
|
||||
; find kernel file in root directory
|
||||
loop_find_dir_entry:
|
||||
push si
|
||||
mov cx, 11
|
||||
mov di, kernel_name+boot_program
|
||||
rep cmpsb ; compare es:si and es:di, cx bytes long
|
||||
pop si
|
||||
je found_kernel_file
|
||||
add si, 32 ; next dir. entry
|
||||
cmp si, ax ; end of directory
|
||||
jb loop_find_dir_entry
|
||||
|
||||
file_error_message:
|
||||
mov si, error_message+boot_program
|
||||
|
||||
loop_error_message:
|
||||
lodsb
|
||||
or al, al
|
||||
jz freeze_pc
|
||||
mov ah, 0eh
|
||||
mov bx, 7
|
||||
int 10h
|
||||
jmp loop_error_message
|
||||
|
||||
freeze_pc:
|
||||
jmp $ ; endless loop
|
||||
|
||||
; === KERNEL FOUND. LOADING... ===
|
||||
|
||||
found_kernel_file:
|
||||
mov bp, [si+01ah] ; first cluster of kernel file
|
||||
; <diamond>
|
||||
mov [cluster1st+boot_program], bp ; starting cluster of kernel file
|
||||
; <\diamond>
|
||||
|
||||
; reading first FAT table
|
||||
mov ax, word [BPB_RsvdSecCnt+boot_program] ; begin first FAT abs sector number
|
||||
call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector)
|
||||
mov bx, pos_read_tmp ; es:bx read position
|
||||
mov ah, 2 ; ah=2 (read)
|
||||
mov al, byte [BPB_FATSz16+boot_program] ; FAT size in sectors (TODO: max 255 sectors)
|
||||
call read_sector
|
||||
jc file_error_message ; read error
|
||||
|
||||
mov ax, seg_read_kernel
|
||||
mov es, ax
|
||||
xor bx, bx ; es:bx = 1000h:0000h
|
||||
|
||||
|
||||
; reading kernel file
|
||||
loop_obtains_kernel_data:
|
||||
; read one cluster of file
|
||||
call obtain_cluster
|
||||
jc file_error_message ; read error
|
||||
|
||||
; add one cluster length to segment:offset
|
||||
push bx
|
||||
mov bx, es
|
||||
mov ax, word [BPB_BytsPerSec+boot_program] ;\
|
||||
movsx cx, byte [BPB_SecPerClus+boot_program] ; | !!! TODO: !!!
|
||||
mul cx ; | out this from loop !!!
|
||||
shr ax, 4 ;/
|
||||
add bx, ax
|
||||
mov es, bx
|
||||
pop bx
|
||||
|
||||
mov di, bp
|
||||
shr di, 1
|
||||
pushf
|
||||
add di, bp ; di = bp * 1.5
|
||||
add di, pos_read_tmp
|
||||
mov ax, [di] ; read next entry from FAT-chain
|
||||
popf
|
||||
jc move_4_right
|
||||
and ax, 0fffh
|
||||
jmp verify_end_sector
|
||||
move_4_right:
|
||||
mov cl, 4
|
||||
shr ax, cl
|
||||
verify_end_sector:
|
||||
cmp ax, 0ff8h ; last cluster
|
||||
jae execute_kernel
|
||||
mov bp, ax
|
||||
jmp loop_obtains_kernel_data
|
||||
|
||||
execute_kernel:
|
||||
; <diamond>
|
||||
mov ax, 'KL'
|
||||
push 0
|
||||
pop ds
|
||||
mov si, loader_block+boot_program
|
||||
; </diamond>
|
||||
push word seg_read_kernel
|
||||
push word 0
|
||||
retf ; jmp far 1000:0000
|
||||
|
||||
|
||||
;------------------------------------------
|
||||
; loading cluster from file to es:bx
|
||||
obtain_cluster:
|
||||
; bp - cluster number to read
|
||||
; carry = 0 -> read OK
|
||||
; carry = 1 -> read ERROR
|
||||
|
||||
; print one dot
|
||||
push bx
|
||||
mov ax, 0e2eh ; ah=0eh (teletype), al='.'
|
||||
xor bh, bh
|
||||
int 10h
|
||||
pop bx
|
||||
|
||||
writesec:
|
||||
; convert cluster number to sector number
|
||||
mov ax, bp ; data cluster to read
|
||||
sub ax, 2
|
||||
xor dx, dx
|
||||
mov dl, byte [BPB_SecPerClus+boot_program]
|
||||
mul dx
|
||||
add ax, word [data_start+boot_program]
|
||||
|
||||
call conv_abs_to_THS ; convert abs sector (AX) to BIOS T:H:S (track:head:sector)
|
||||
patchhere:
|
||||
mov ah, 2 ; ah=2 (read)
|
||||
mov al, byte [BPB_SecPerClus+boot_program] ; al=(one cluster)
|
||||
call read_sector
|
||||
retn
|
||||
;------------------------------------------
|
||||
|
||||
;------------------------------------------
|
||||
; read sector from disk
|
||||
read_sector:
|
||||
push bp
|
||||
mov bp, 20 ; try 20 times
|
||||
newread:
|
||||
dec bp
|
||||
jz file_error_message
|
||||
push ax bx cx dx
|
||||
int 13h
|
||||
pop dx cx bx ax
|
||||
jc newread
|
||||
pop bp
|
||||
retn
|
||||
;------------------------------------------
|
||||
; convert abs. sector number (AX) to BIOS T:H:S
|
||||
; sector number = (abs.sector%BPB_SecPerTrk)+1
|
||||
; pre.track number = (abs.sector/BPB_SecPerTrk)
|
||||
; head number = pre.track number%BPB_NumHeads
|
||||
; track number = pre.track number/BPB_NumHeads
|
||||
; Return: cl - sector number
|
||||
; ch - track number
|
||||
; dl - drive number (0 = a:)
|
||||
; dh - head number
|
||||
conv_abs_to_THS:
|
||||
push bx
|
||||
mov bx, word [BPB_SecPerTrk+boot_program]
|
||||
xor dx, dx
|
||||
div bx
|
||||
inc dx
|
||||
mov cl, dl ; cl = sector number
|
||||
mov bx, word [BPB_NumHeads+boot_program]
|
||||
xor dx, dx
|
||||
div bx
|
||||
; !!!!!!! ax = track number, dx = head number
|
||||
mov ch, al ; ch=track number
|
||||
xchg dh, dl ; dh=head number
|
||||
mov dl, 0 ; dl=0 (drive 0 (a:))
|
||||
pop bx
|
||||
retn
|
||||
;------------------------------------------
|
||||
|
||||
if lang eq sp
|
||||
loading db cr,lf,'Iniciando el sistema ',00h
|
||||
else
|
||||
loading db cr,lf,'Starting system ',00h
|
||||
end if
|
||||
error_message db 13,10
|
||||
kernel_name db 'KERNEL MNT ?',cr,lf,00h
|
||||
FirstRootDirSecNum dw ?
|
||||
RootDirSecs dw ?
|
||||
data_start dw ?
|
||||
|
||||
; <diamond>
|
||||
write1st:
|
||||
push cs
|
||||
pop ds
|
||||
mov byte [patchhere+1+boot_program], 3 ; change ah=2 to ah=3
|
||||
mov bp, [cluster1st+boot_program]
|
||||
push 1000h
|
||||
pop es
|
||||
xor bx, bx
|
||||
call writesec
|
||||
mov byte [patchhere+1+boot_program], 2 ; change back ah=3 to ah=2
|
||||
retf
|
||||
cluster1st dw ?
|
||||
loader_block:
|
||||
db 1
|
||||
dw 0
|
||||
dw write1st+boot_program
|
||||
dw 0
|
||||
; <\diamond>
|
||||
|
||||
times 0x1fe-$ db 00h
|
||||
|
||||
db 55h,0aah ;boot signature
|
||||
@@ -0,0 +1,2 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("kordldr.win.asm", "fasm %f %o", "kordldr.win.bin")
|
||||
@@ -0,0 +1,2 @@
|
||||
@fasm -m 65535 kordldr.win.asm kordldr.win
|
||||
@pause
|
||||
@@ -0,0 +1,509 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
; in: ss:bp = 0:dat
|
||||
; in: es:bx = address to load file
|
||||
; in: ds:si -> ASCIIZ name
|
||||
; in: cx = limit in sectors
|
||||
; out: bx = status: bx=0 - ok, bx=1 - file is too big, only part of file has been loaded, bx=2 - file not found
|
||||
; out: dx:ax = file size (0xFFFFFFFF if file not found)
|
||||
load_file_fat:
|
||||
mov eax, [bp + root_clus - dat]
|
||||
mov [bp + cur_obj - dat], root_string
|
||||
push es
|
||||
push bx
|
||||
push cx
|
||||
.parse_dir_loop:
|
||||
; convert name to FAT name
|
||||
push [bp + cur_obj - dat]
|
||||
push ax
|
||||
mov [bp + cur_obj - dat], si
|
||||
push ss
|
||||
pop es
|
||||
; convert ASCIIZ filename to FAT name
|
||||
mov di, fat_filename
|
||||
push di
|
||||
mov cx, 8+3
|
||||
mov al, ' '
|
||||
rep stosb
|
||||
pop di
|
||||
mov cl, 8 ; 8 symbols per name
|
||||
mov bl, 1
|
||||
.nameloop:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .namedone
|
||||
cmp al, '/'
|
||||
jz .namedone
|
||||
cmp al, '.'
|
||||
jz .namedot
|
||||
dec cx
|
||||
js .badname
|
||||
cmp al, 'a'
|
||||
jb @f
|
||||
cmp al, 'z'
|
||||
ja @f
|
||||
sub al, 'a'-'A'
|
||||
@@:
|
||||
stosb
|
||||
jmp .nameloop
|
||||
.namedot:
|
||||
inc bx
|
||||
jp .badname
|
||||
add di, cx
|
||||
mov cl, 3
|
||||
jmp .nameloop
|
||||
.badname:
|
||||
mov si, badname_msg
|
||||
jmp find_error_si
|
||||
.namedone:
|
||||
; scan directory
|
||||
pop ax ; eax = cluster of directory
|
||||
; high word of eax is preserved by operations above
|
||||
push ds
|
||||
push si
|
||||
; read a folder sector-by-sector and scan
|
||||
; first, try to use the cache
|
||||
push ss
|
||||
pop ds
|
||||
mov bx, -2
|
||||
mov cx, [bp + rootcache_size - dat]
|
||||
cmp [bp + root_clus - dat], eax
|
||||
jz .lookcache_root
|
||||
mov di, foldcache_mark
|
||||
xor bx, bx
|
||||
mov cx, [bp + cachelimit - dat]
|
||||
@@:
|
||||
lea si, [di+bx]
|
||||
mov edx, dword [foldcache_clus+si-foldcache_mark+bx]
|
||||
cmp edx, eax
|
||||
jz .cacheok
|
||||
test edx, edx
|
||||
jz .cacheadd ; the cache has place for new entry
|
||||
inc bx
|
||||
inc bx
|
||||
dec cx
|
||||
js @b
|
||||
; the folder is not present in the cache, so add it
|
||||
; the cache is full; find the oldest entry and replace it with the new one
|
||||
mov bx, -2
|
||||
mov dx, [bp + cachelimit - dat]
|
||||
@@:
|
||||
inc bx
|
||||
inc bx
|
||||
cmp word [di+bx], dx ; marks have values 0 through [cachelimit]
|
||||
jnz @b
|
||||
.cacheadd:
|
||||
or word [di+bx], 0xFFFF ; very big value, it will be changed soon
|
||||
and [foldcache_size+di-foldcache_mark+bx], 0 ; no folder items yet
|
||||
lea si, [di+bx]
|
||||
mov dword [foldcache_clus+si-foldcache_mark+bx], eax
|
||||
.cacheok:
|
||||
; update cache marks
|
||||
mov dx, [di+bx]
|
||||
mov cx, [foldcache_size+di-foldcache_mark+bx]
|
||||
mov di, [bp + cachelimit - dat]
|
||||
add di, di
|
||||
.cacheupdate:
|
||||
cmp [foldcache_mark+di], dx
|
||||
adc [foldcache_mark+di], 0
|
||||
dec di
|
||||
dec di
|
||||
jns .cacheupdate
|
||||
and [foldcache_mark+bx], 0
|
||||
; done, bx contains (position in cache)*2
|
||||
.lookcache_root:
|
||||
; bx = (position in cache)*2 for non-root folders; bx = -2 for root folder
|
||||
;mov dx, bx
|
||||
;shl dx, 8
|
||||
;add dx, 0x9200
|
||||
lea dx, [bx + 0x92]
|
||||
xchg dl, dh
|
||||
mov ds, dx
|
||||
mov si, fat_filename ; ss:si -> filename in FAT style
|
||||
call fat_scan_for_filename
|
||||
jz .lookup_done
|
||||
; cache miss, read folder data from disk
|
||||
; we are reading parent directory, it can result in disk read errors; restore [cur_obj]
|
||||
mov di, sp
|
||||
mov bx, [bp + cur_obj - dat]
|
||||
xchg bx, [ss:di+4]
|
||||
mov [bp + cur_obj - dat], bx
|
||||
mov bx, cx
|
||||
add bx, 0xF
|
||||
shr bx, 4
|
||||
shl cx, 5
|
||||
mov di, cx ; es:di -> free space in cache entry
|
||||
; external loop: scan clusters
|
||||
.folder_next_cluster:
|
||||
; internal loop: scan sectors in cluster
|
||||
movzx ecx, byte [ss:0x320D] ; BPB_SecPerClus
|
||||
push eax
|
||||
; FAT12/16 root - special handling
|
||||
test eax, eax
|
||||
jnz .folder_notroot
|
||||
mov cx, [ss:0x3211] ; BPB_RootEntCnt
|
||||
mov dx, cx
|
||||
add cx, 0xF
|
||||
rcr cx, 1
|
||||
shr cx, 3
|
||||
mov eax, [bp + root_start - dat]
|
||||
jmp .folder_next_sector
|
||||
.folder_notroot:
|
||||
mul ecx
|
||||
add eax, [bp + data_start - dat]
|
||||
.folder_next_sector:
|
||||
sub dx, 0x10
|
||||
; skip first bx sectors
|
||||
dec bx
|
||||
jns .folder_skip_sector
|
||||
push cx
|
||||
push es di
|
||||
push 0x8000
|
||||
pop es
|
||||
xor bx, bx
|
||||
mov cx, 1
|
||||
push es
|
||||
call read
|
||||
jc ..found_disk_error
|
||||
; copy data to the cache...
|
||||
pop ds
|
||||
pop di es
|
||||
cmp di, 0x2000 ; ...if there is free space, of course
|
||||
jae @f
|
||||
pusha
|
||||
mov cx, 0x100
|
||||
xor si, si
|
||||
rep movsw
|
||||
mov di, es
|
||||
shr di, 8
|
||||
cmp di, 0x90
|
||||
jz .update_rootcache_size
|
||||
add [ss:foldcache_size+di-0x92], 0x10 ; 0x10 new entries in the cache
|
||||
jmp .updated_cachesize
|
||||
.update_rootcache_size:
|
||||
mov cl, 0x10
|
||||
cmp cx, dx
|
||||
jb @f
|
||||
mov cx, dx
|
||||
@@:
|
||||
add [bp + rootcache_size - dat], cx
|
||||
.updated_cachesize:
|
||||
popa
|
||||
@@:
|
||||
push es
|
||||
mov cl, 0x10 ; ch=0 at this point
|
||||
cmp cx, dx
|
||||
jb @f
|
||||
mov cx, dx
|
||||
@@:
|
||||
call fat_scan_for_filename
|
||||
pop es
|
||||
pop cx
|
||||
jz .lookup_done_pop
|
||||
.folder_skip_sector:
|
||||
inc eax
|
||||
loop .folder_next_sector
|
||||
pop eax ; eax = current cluster
|
||||
test eax, eax
|
||||
jz @f
|
||||
call [bp + get_next_cluster_ptr - dat]
|
||||
jc .folder_next_cluster
|
||||
@@:
|
||||
stc
|
||||
push eax
|
||||
.lookup_done_pop:
|
||||
pop eax
|
||||
.lookup_done:
|
||||
pop si
|
||||
; CF=1 <=> failed
|
||||
jnc .found
|
||||
pop ds
|
||||
pop [bp + cur_obj - dat]
|
||||
mov si, error_not_found
|
||||
jmp find_error_si
|
||||
.found:
|
||||
mov eax, [di+20-2]
|
||||
mov edx, [di+28]
|
||||
mov ax, [di+26] ; get cluster
|
||||
test byte [di+11], 10h ; directory?
|
||||
pop ds
|
||||
pop [bp + cur_obj - dat] ; forget old [cur_obj]
|
||||
jz .regular_file
|
||||
cmp byte [si-1], 0
|
||||
jnz .parse_dir_loop
|
||||
..directory_error:
|
||||
mov si, directory_string
|
||||
jmp find_error_si
|
||||
.regular_file:
|
||||
cmp byte [si-1], 0
|
||||
jz @f
|
||||
..notdir_error:
|
||||
mov si, notdir_string
|
||||
jmp find_error_si
|
||||
@@:
|
||||
; ok, we have found a regular file and the caller requested it
|
||||
; parse FAT chunk
|
||||
push ss
|
||||
pop es
|
||||
push ss
|
||||
pop ds
|
||||
mov di, 0x4005
|
||||
mov byte [di-5], 1 ; non-resident attribute
|
||||
mov dword [di-4], 1
|
||||
stosd
|
||||
pop cx
|
||||
push cx
|
||||
.parsefat:
|
||||
call [bp + get_next_cluster_ptr - dat]
|
||||
jnc .done
|
||||
mov esi, [di-8]
|
||||
add esi, [di-4]
|
||||
cmp eax, esi
|
||||
jz .contc
|
||||
mov dword [di], 1
|
||||
scasd
|
||||
stosd
|
||||
jmp @f
|
||||
.contc:
|
||||
inc dword [di-8]
|
||||
@@:
|
||||
sub cl, [0x320D]
|
||||
sbb ch, 0
|
||||
ja .parsefat
|
||||
.done:
|
||||
xor eax, eax
|
||||
stosd
|
||||
mov si, 0x4000
|
||||
load_file_common_end:
|
||||
xor ecx, ecx
|
||||
pop cx
|
||||
pop bx
|
||||
pop es
|
||||
mov [bp + filesize - dat], edx
|
||||
mov [bp + sectors_read - dat], ecx
|
||||
add edx, 0x1FF
|
||||
shr edx, 9
|
||||
mov [bp + filesize_sectors - dat], edx
|
||||
cmp edx, ecx
|
||||
seta al
|
||||
mov ah, 0
|
||||
push ax
|
||||
call read_file_chunk
|
||||
continue_load_common_end:
|
||||
mov [bp + cur_chunk_ptr - dat], si
|
||||
pop bx
|
||||
mov ax, word [bp + filesize - dat]
|
||||
mov dx, word [bp + filesize+2 - dat]
|
||||
jnc @f
|
||||
mov bl, 3 ; read error
|
||||
@@:
|
||||
ret
|
||||
|
||||
continue_load_file:
|
||||
; es:bx -> buffer for output, ecx = cx = number of sectors
|
||||
mov si, [bp + cur_chunk_ptr - dat]
|
||||
push ecx
|
||||
add ecx, [bp + sectors_read - dat]
|
||||
mov [bp + sectors_read - dat], ecx
|
||||
cmp [bp + filesize_sectors - dat], ecx
|
||||
pop ecx
|
||||
seta al
|
||||
mov ah, 0
|
||||
push ax
|
||||
push continue_load_common_end
|
||||
push ss
|
||||
pop ds
|
||||
cmp [bp + cur_chunk_resident - dat], ah
|
||||
jnz .nonresident
|
||||
.resident:
|
||||
mov ax, word [bp + num_sectors - dat]
|
||||
jmp read_file_chunk.resident.continue
|
||||
.nonresident:
|
||||
mov eax, [bp + cur_cluster - dat]
|
||||
mov edx, [bp + num_sectors - dat]
|
||||
add eax, [bp + cur_delta - dat]
|
||||
jmp read_file_chunk.nonresident.continue
|
||||
|
||||
fat_scan_for_filename:
|
||||
; in: ss:si -> 11-bytes FAT name
|
||||
; in: ds:0 -> part of directory data
|
||||
; in: cx = number of entries
|
||||
; out: if found: CF=0, ZF=1, es:di -> directory entry
|
||||
; out: if not found, but continue required: CF=1 and ZF=0
|
||||
; out: if not found and zero item reached: CF=1 and ZF=1
|
||||
push ds
|
||||
pop es
|
||||
xor di, di
|
||||
push cx
|
||||
jcxz .noent
|
||||
.loop:
|
||||
cmp byte [di], 0
|
||||
jz .notfound
|
||||
test byte [di+11], 8 ; volume label?
|
||||
jnz .cont ; ignore volume labels
|
||||
pusha
|
||||
mov cx, 11
|
||||
repz cmps byte [ss:si], byte [es:di]
|
||||
popa
|
||||
jz .done
|
||||
.cont:
|
||||
add di, 0x20
|
||||
loop .loop
|
||||
.noent:
|
||||
inc cx ; clear ZF flag
|
||||
.notfound:
|
||||
stc
|
||||
.done:
|
||||
pop cx
|
||||
ret
|
||||
|
||||
fat12_get_next_cluster:
|
||||
; in: ax = cluster (high word of eax is zero)
|
||||
; out: if there is next cluster: CF=1, ax = next cluster
|
||||
; out: if there is no next cluster: CF=0
|
||||
push si
|
||||
push ds
|
||||
push 0x6000
|
||||
pop ds
|
||||
mov si, ax
|
||||
shr si, 1
|
||||
add si, ax
|
||||
test al, 1
|
||||
lodsw
|
||||
jz @f
|
||||
shr ax, 4
|
||||
@@:
|
||||
and ax, 0xFFF
|
||||
cmp ax, 0xFF7
|
||||
pop ds si
|
||||
ret
|
||||
|
||||
fat16_get_next_cluster:
|
||||
; in: ax = cluster (high word of eax is zero)
|
||||
; out: if there is next cluster: CF=1, ax = next cluster
|
||||
; out: if there is no next cluster: CF=0
|
||||
; each sector contains 200h bytes = 100h FAT entries
|
||||
; so ah = # of sector, al = offset in sector
|
||||
push si
|
||||
mov si, ax
|
||||
shr si, 8
|
||||
; calculate segment for this sector of FAT table
|
||||
; base for FAT table is 6000:0000, so the sector #si has to be loaded to (60000 + 200*si)
|
||||
; segment = 6000 + 20*si, offset = 0
|
||||
push es
|
||||
push si
|
||||
shl si, 5
|
||||
add si, 0x6000
|
||||
mov es, si
|
||||
pop si
|
||||
cmp byte [ss:0x3400+si], 0 ; sector already loaded?
|
||||
jnz .noread
|
||||
; load corresponding sector, try all FATs if disk read error detected
|
||||
pusha
|
||||
movzx di, byte [ss:0x3210] ; BPB_NumFATs
|
||||
xor bx, bx
|
||||
mov ax, [ss:0x320E] ; BPB_RsvdSecCnt
|
||||
xor dx, dx
|
||||
add ax, si
|
||||
adc dx, bx
|
||||
@@:
|
||||
push es
|
||||
push dx ax
|
||||
pop eax
|
||||
mov cx, 1 ; read 1 sector
|
||||
call read
|
||||
pop es
|
||||
jnc @f
|
||||
add ax, [ss:0x3216] ; BPB_FATSz16
|
||||
adc dx, bx
|
||||
dec di
|
||||
jnz @b
|
||||
..found_disk_error:
|
||||
mov si, disk_error_msg
|
||||
jmp find_error_si
|
||||
@@:
|
||||
popa
|
||||
.noread:
|
||||
mov si, ax
|
||||
and si, 0xFF
|
||||
add si, si
|
||||
mov ax, [es:si]
|
||||
pop es
|
||||
cmp ax, 0xFFF7
|
||||
pop si
|
||||
ret
|
||||
|
||||
fat32_get_next_cluster:
|
||||
; in: eax = cluster
|
||||
; out: if there is next cluster: CF=1, eax = next cluster
|
||||
; out: if there is no next cluster: CF=0
|
||||
push di
|
||||
push ax
|
||||
shr eax, 7
|
||||
; eax = FAT sector number; look in cache
|
||||
push si
|
||||
mov si, cache1head
|
||||
call cache_lookup
|
||||
pop si
|
||||
jnc .noread
|
||||
; read FAT, try all FATs if disk read error detected
|
||||
push es
|
||||
pushad
|
||||
movzx edx, word [ss:0x320E] ; BPB_RsvdSecCnt
|
||||
add eax, edx
|
||||
movzx si, byte [ss:0x3210] ; BPB_NumFATs
|
||||
@@:
|
||||
lea cx, [di - 0x3400 + (0x6000 shr (9-3))]
|
||||
shl cx, 9-3
|
||||
mov es, cx
|
||||
xor bx, bx
|
||||
mov cx, 1
|
||||
call read
|
||||
jnc @f
|
||||
add eax, [ss:0x3224] ; BPB_FATSz32
|
||||
dec si
|
||||
jnz @b
|
||||
jmp ..found_disk_error
|
||||
@@:
|
||||
popad
|
||||
pop es
|
||||
.noread:
|
||||
; get requested item
|
||||
lea ax, [di - 0x3400 + (0x6000 shr (9-3))]
|
||||
pop di
|
||||
and di, 0x7F
|
||||
shl di, 2
|
||||
shl ax, 9-3
|
||||
push ds
|
||||
mov ds, ax
|
||||
and byte [di+3], 0x0F
|
||||
mov eax, [di]
|
||||
pop ds
|
||||
pop di
|
||||
;and eax, 0x0FFFFFFF
|
||||
cmp eax, 0x0FFFFFF7
|
||||
ret
|
||||
@@ -0,0 +1,924 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
; KordOS bootloader, based on mtldr, KolibriOS bootloader, by diamond
|
||||
; It is used when main bootloader is Windows loader.
|
||||
|
||||
; this code is loaded:
|
||||
; NT/2k/XP: by ntldr to 0D00:0000
|
||||
; 9x: by io.sys from config.sys to xxxx:0100
|
||||
; Vista: by bootmgr to 0000:7C00
|
||||
format binary
|
||||
use16
|
||||
|
||||
; in any case, we relocate this code to 0000:0600
|
||||
org 0x600
|
||||
; entry point for 9x and Vista booting
|
||||
call @f
|
||||
db 'NTFS'
|
||||
@@:
|
||||
pop si
|
||||
sub si, 3
|
||||
cmp si, 100h
|
||||
jnz boot_vista
|
||||
mov si, load_question + 100h - 600h
|
||||
call out_string
|
||||
; mov si, answer + 100h - 0600h ; already is
|
||||
xxy:
|
||||
mov ah, 0
|
||||
int 16h
|
||||
or al, 20h
|
||||
mov [si], al
|
||||
cmp al, 'y'
|
||||
jz xxz
|
||||
cmp al, 'n'
|
||||
jnz xxy
|
||||
; continue load Windows
|
||||
; call out_string
|
||||
; ret
|
||||
out_string:
|
||||
push bx
|
||||
@@:
|
||||
lodsb
|
||||
test al, al
|
||||
jz @f
|
||||
mov ah, 0Eh
|
||||
mov bx, 7
|
||||
int 10h
|
||||
jmp @b
|
||||
@@:
|
||||
pop bx
|
||||
ret
|
||||
xxz:
|
||||
; boot KordOS
|
||||
call out_string
|
||||
; 9x bootloader has already hooked some interrupts; to correctly remove all DOS handlers,
|
||||
; issue int 19h (reboot interrupt) and trace its DOS handler until original BIOS handler is reached
|
||||
xor di, di
|
||||
mov ds, di
|
||||
mov word [di+4], new01handler + 100h - 600h
|
||||
mov [di+6], cs
|
||||
pushf
|
||||
pop ax
|
||||
or ah, 1
|
||||
push ax
|
||||
popf
|
||||
; we cannot issue INT 19h directly, because INT command clears TF
|
||||
; int 19h ; don't issue it directly, because INT command clears TF
|
||||
; so instead we use direct call
|
||||
; pushf ; there will be no IRET
|
||||
call far [di + 19h*4]
|
||||
xxt:
|
||||
xor di, di
|
||||
mov ds, di
|
||||
cmp word [di + 8*4+2], 0F000h
|
||||
jz @f
|
||||
les bx, [di + 8*4]
|
||||
mov eax, [es:bx+1]
|
||||
mov [di + 8*4], eax
|
||||
@@:
|
||||
mov si, 100h
|
||||
boot_vista:
|
||||
; relocate cs:si -> 0000:0600
|
||||
push cs
|
||||
pop ds
|
||||
xor ax, ax
|
||||
mov es, ax
|
||||
mov di, 0x600
|
||||
mov cx, 2000h/2
|
||||
rep movsw
|
||||
jmp 0:real_entry
|
||||
|
||||
load_question db 'Load KordOS? [y/n]: ',0
|
||||
answer db ?
|
||||
db 13,10,0
|
||||
|
||||
new01handler:
|
||||
; [sp]=ip, [sp+2]=cs, [sp+4]=flags
|
||||
push bp
|
||||
mov bp, sp
|
||||
push ds
|
||||
lds bp, [bp+2]
|
||||
cmp word [ds:bp], 19cdh
|
||||
jz xxt
|
||||
pop ds
|
||||
pop bp
|
||||
iret
|
||||
|
||||
; read from hard disk
|
||||
; in: eax = absolute sector
|
||||
; cx = number of sectors
|
||||
; es:bx -> buffer
|
||||
; out: CF=1 if error
|
||||
read:
|
||||
pushad
|
||||
add eax, [bp + partition_start - dat]
|
||||
cmp [bp + use_lba - dat], 0
|
||||
jz .chs
|
||||
; LBA read
|
||||
push ds
|
||||
.lbado:
|
||||
push ax
|
||||
push cx
|
||||
cmp cx, 0x7F
|
||||
jbe @f
|
||||
mov cx, 0x7F
|
||||
@@:
|
||||
; create disk address packet on the stack
|
||||
; dq starting LBA
|
||||
push 0
|
||||
push 0
|
||||
push eax
|
||||
; dd buffer
|
||||
push es
|
||||
push bx
|
||||
; dw number of blocks to transfer (no more than 0x7F)
|
||||
push cx
|
||||
; dw packet size in bytes
|
||||
push 10h
|
||||
; issue BIOS call
|
||||
push ss
|
||||
pop ds
|
||||
mov si, sp
|
||||
mov dl, [bp + boot_drive - dat]
|
||||
mov ah, 42h
|
||||
int 13h
|
||||
jc .disk_error_lba
|
||||
add sp, 10h ; restore stack
|
||||
; increase current sector & buffer; decrease number of sectors
|
||||
movzx esi, cx
|
||||
mov ax, es
|
||||
shl cx, 5
|
||||
add ax, cx
|
||||
mov es, ax
|
||||
pop cx
|
||||
pop ax
|
||||
add eax, esi
|
||||
sub cx, si
|
||||
jnz .lbado
|
||||
pop ds
|
||||
popad
|
||||
ret
|
||||
.disk_error_lba:
|
||||
add sp, 14h
|
||||
pop ds
|
||||
popad
|
||||
stc
|
||||
ret
|
||||
|
||||
.chs:
|
||||
pusha
|
||||
pop edi ; loword(edi) = di, hiword(edi) = si
|
||||
push bx
|
||||
|
||||
; eax / (SectorsPerTrack) -> eax, remainder bx
|
||||
movzx esi, [bp + sectors - dat]
|
||||
xor edx, edx
|
||||
div esi
|
||||
mov bx, dx ; bx = sector-1
|
||||
|
||||
; eax -> dx:ax
|
||||
push eax
|
||||
pop ax
|
||||
pop dx
|
||||
; (dword in dx:ax) / (NumHeads) -> (word in ax), remainder dx
|
||||
div [bp + heads - dat]
|
||||
|
||||
; number of sectors: read no more than to end of track
|
||||
sub si, bx
|
||||
cmp cx, si
|
||||
jbe @f
|
||||
mov cx, si
|
||||
@@:
|
||||
|
||||
inc bx
|
||||
; now ax=track, dl=head, dh=0, cl=number of sectors, ch=0, bl=sector
|
||||
; convert to int13 format
|
||||
movzx edi, cx
|
||||
mov dh, dl
|
||||
mov dl, [bp + boot_drive - dat]
|
||||
shl ah, 6
|
||||
mov ch, al
|
||||
mov al, cl
|
||||
mov cl, bl
|
||||
or cl, ah
|
||||
pop bx
|
||||
mov si, 3
|
||||
mov ah, 2
|
||||
@@:
|
||||
push ax
|
||||
int 13h
|
||||
jnc @f
|
||||
xor ax, ax
|
||||
int 13h ; reset drive
|
||||
pop ax
|
||||
dec si
|
||||
jnz @b
|
||||
add sp, 12
|
||||
popad
|
||||
stc
|
||||
ret
|
||||
@@:
|
||||
pop ax
|
||||
mov ax, es
|
||||
mov cx, di
|
||||
shl cx, 5
|
||||
add ax, cx
|
||||
mov es, ax
|
||||
push edi
|
||||
popa
|
||||
add eax, edi
|
||||
sub cx, di
|
||||
jnz .chs
|
||||
popad
|
||||
ret
|
||||
|
||||
disk_error2 db 'Fatal: cannot read partitions info: '
|
||||
disk_error_msg db 'disk read error',0
|
||||
disk_params_msg db 'Fatal: cannot get drive parameters',0
|
||||
start_msg db 2,' KordOS bootloader',13,10,0
|
||||
part_msg db 'looking at partition '
|
||||
part_char db '0' ; will be incremented before writing message
|
||||
db ' ... ',0
|
||||
errfs_msg db 'unknown filesystem',13,10,0
|
||||
fatxx_msg db 'FATxx'
|
||||
newline db 13,10,0
|
||||
ntfs_msg db 'NTFS',13,10,0
|
||||
error_msg db 'Error'
|
||||
colon db ': ',0
|
||||
root_string db '\',0
|
||||
nomem_msg db 'No memory',0
|
||||
filesys_string db '(filesystem)',0
|
||||
directory_string db 'is a directory',0
|
||||
notdir_string db 'not a directory',0
|
||||
|
||||
; entry point for NT/2k/XP booting
|
||||
; ntldr loads our code to 0D00:0000 and jumps to 0D00:0256
|
||||
repeat 600h + 256h - $
|
||||
db 1 ; any data can be here; 1 in ASCII is a nice face :)
|
||||
end repeat
|
||||
; cs=es=0D00, ds=07C0, ss=0
|
||||
; esi=edi=ebp=0, esp=7C00
|
||||
xor si, si
|
||||
jmp boot_vista
|
||||
|
||||
real_entry:
|
||||
; ax = 0
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
; our stack is 4 Kb: memory range 2000-3000
|
||||
mov ss, ax
|
||||
mov sp, 3000h
|
||||
mov bp, dat
|
||||
sti ; just for case
|
||||
; say hi to user
|
||||
mov si, start_msg
|
||||
call out_string
|
||||
; we are booting from hard disk identified by [boot_drive]
|
||||
mov dl, [bp + boot_drive - dat]
|
||||
; is LBA supported?
|
||||
mov [bp + use_lba - dat], 0
|
||||
mov ah, 41h
|
||||
mov bx, 55AAh
|
||||
int 13h
|
||||
jc .no_lba
|
||||
cmp bx, 0AA55h
|
||||
jnz .no_lba
|
||||
test cl, 1
|
||||
jz .no_lba
|
||||
inc [bp + use_lba - dat]
|
||||
jmp disk_params_ok
|
||||
.no_lba:
|
||||
; get drive geometry
|
||||
mov ah, 8
|
||||
mov dl, [bp + boot_drive - dat]
|
||||
int 13h
|
||||
jnc @f
|
||||
mov si, disk_params_msg
|
||||
call out_string
|
||||
jmp $
|
||||
@@:
|
||||
movzx ax, dh
|
||||
inc ax
|
||||
mov [bp + heads - dat], ax
|
||||
and cx, 3Fh
|
||||
mov [bp + sectors - dat], cx
|
||||
disk_params_ok:
|
||||
; determine size of cache for folders
|
||||
int 12h ; ax = size of available base memory in Kb
|
||||
sub ax, 94000h / 1024
|
||||
jc nomem
|
||||
shr ax, 3
|
||||
mov [bp + cachelimit - dat], ax ; size of cache - 1
|
||||
; scan all partitions
|
||||
new_partition_ex:
|
||||
xor eax, eax ; read first sector of current disk area
|
||||
mov [bp + extended_part_cur - dat], eax ; no extended partition yet
|
||||
mov [bp + cur_partition_ofs - dat], 31BEh ; start from first partition
|
||||
push es
|
||||
mov cx, 1
|
||||
mov bx, 3000h
|
||||
call read
|
||||
pop es
|
||||
jnc new_partition
|
||||
mov si, disk_error2
|
||||
call out_string
|
||||
jmp $
|
||||
new_partition:
|
||||
mov bx, [bp + cur_partition_ofs - dat]
|
||||
mov al, [bx+4] ; partition type
|
||||
test al, al
|
||||
jz next_partition
|
||||
cmp al, 5
|
||||
jz @f
|
||||
cmp al, 0xF
|
||||
jnz not_extended
|
||||
@@:
|
||||
; extended partition
|
||||
mov eax, [bx+8] ; partition start
|
||||
add eax, [bp + extended_part_start - dat]
|
||||
mov [bp + extended_part_cur - dat], eax
|
||||
next_partition:
|
||||
add [bp + cur_partition_ofs - dat], 10h
|
||||
cmp [bp + cur_partition_ofs - dat], 31FEh
|
||||
jb new_partition
|
||||
mov eax, [bp + extended_part_cur - dat]
|
||||
test eax, eax
|
||||
jz partitions_done
|
||||
cmp [bp + extended_part_start - dat], 0
|
||||
jnz @f
|
||||
mov [bp + extended_part_start - dat], eax
|
||||
@@:
|
||||
mov [bp + extended_parent - dat], eax
|
||||
mov [bp + partition_start - dat], eax
|
||||
jmp new_partition_ex
|
||||
partitions_done:
|
||||
mov si, total_kaput
|
||||
call out_string
|
||||
jmp $
|
||||
not_extended:
|
||||
mov eax, [bx+8]
|
||||
add eax, [bp + extended_parent - dat]
|
||||
mov [bp + partition_start - dat], eax
|
||||
; try to load from current partition
|
||||
; inform user
|
||||
mov si, part_msg
|
||||
inc [si + part_char - part_msg]
|
||||
call out_string
|
||||
; read bootsector
|
||||
xor eax, eax
|
||||
mov [bp + cur_obj - dat], filesys_string
|
||||
push es
|
||||
mov cx, 1
|
||||
mov bx, 3200h
|
||||
call read
|
||||
pop es
|
||||
mov si, disk_error_msg
|
||||
jc find_error_si
|
||||
movzx si, byte [bx+13]
|
||||
mov word [bp + sect_per_clust - dat], si
|
||||
test si, si
|
||||
jz unknown_fs
|
||||
lea ax, [si-1]
|
||||
test si, ax
|
||||
jnz unknown_fs
|
||||
; determine file system
|
||||
; Number of bytes per sector == 0x200 (this loader assumes that physical sector size is 200h)
|
||||
cmp word [bx+11], 0x200
|
||||
jnz unknown_fs
|
||||
; is it NTFS?
|
||||
cmp dword [bx+3], 'NTFS'
|
||||
jnz not_ntfs
|
||||
cmp byte [bx+16], bl
|
||||
jz ntfs
|
||||
not_ntfs:
|
||||
; is it FAT? FAT12/FAT16/FAT32?
|
||||
; get count of sectors to dword in cx:si
|
||||
mov si, [bx+19]
|
||||
xor cx, cx
|
||||
test si, si
|
||||
jnz @f
|
||||
mov si, [bx+32]
|
||||
mov cx, [bx+34]
|
||||
@@:
|
||||
xor eax, eax
|
||||
; subtract size of system area
|
||||
sub si, [bx+14] ; BPB_ResvdSecCnt
|
||||
sbb cx, ax
|
||||
mov ax, [bx+17] ; BPB_RootEntCnt
|
||||
add ax, 0xF
|
||||
rcr ax, 1
|
||||
shr ax, 3
|
||||
sub si, ax
|
||||
sbb cx, 0
|
||||
push cx
|
||||
push si
|
||||
mov ax, word [bx+22]
|
||||
test ax, ax
|
||||
jnz @f
|
||||
mov eax, [bx+36]
|
||||
@@:
|
||||
movzx ecx, byte [bx+16]
|
||||
imul ecx, eax
|
||||
pop eax
|
||||
sub eax, ecx
|
||||
; now eax = count of sectors in the data region
|
||||
xor edx, edx
|
||||
div [bp + sect_per_clust - dat]
|
||||
; now eax = count of clusters in the data region
|
||||
mov si, fatxx_msg
|
||||
cmp eax, 0xFFF5
|
||||
jae test_fat32
|
||||
; test magic value in FAT bootsector - FAT12/16 bootsector has it at the offset +38
|
||||
cmp byte [bx+38], 0x29
|
||||
jnz not_fat
|
||||
cmp ax, 0xFF5
|
||||
jae fat16
|
||||
fat12:
|
||||
mov [bp + get_next_cluster_ptr - dat], fat12_get_next_cluster
|
||||
mov di, cx ; BPB_NumFATs
|
||||
mov ax, '12'
|
||||
push ax ; save for secondary loader
|
||||
mov word [si+3], ax
|
||||
call out_string
|
||||
movzx ecx, word [bx+22] ; BPB_FATSz16
|
||||
; FAT12: read entire FAT table (it is no more than 0x1000*3/2 = 0x1800 bytes)
|
||||
.fatloop:
|
||||
; if first copy is not readable, try to switch to other copies
|
||||
push 0x6000
|
||||
pop es
|
||||
xor bx, bx
|
||||
movzx eax, word [0x320E] ; BPB_RsvdSecCnt
|
||||
push cx
|
||||
cmp cx, 12
|
||||
jb @f
|
||||
mov cx, 12
|
||||
@@:
|
||||
call read
|
||||
pop cx
|
||||
jnc fat1x_common
|
||||
add eax, ecx ; switch to next copy of FAT
|
||||
dec di
|
||||
jnz .fatloop
|
||||
mov si, disk_error_msg
|
||||
jmp find_error_si
|
||||
fat16:
|
||||
mov [bp + get_next_cluster_ptr - dat], fat16_get_next_cluster
|
||||
mov ax, '16'
|
||||
push ax ; save for secondary loader
|
||||
mov word [si+3], ax
|
||||
call out_string
|
||||
; FAT16: init FAT cache - no sectors loaded
|
||||
mov di, 0x3400
|
||||
xor ax, ax
|
||||
mov cx, 0x100/2
|
||||
rep stosw
|
||||
fat1x_common:
|
||||
mov bx, 0x3200
|
||||
movzx eax, word [bx+22] ; BPB_FATSz16
|
||||
xor esi, esi ; no root cluster
|
||||
jmp fat_common
|
||||
test_fat32:
|
||||
; FAT32 bootsector has it at the offset +66
|
||||
cmp byte [bx+66], 0x29
|
||||
jnz not_fat
|
||||
mov [bp + get_next_cluster_ptr - dat], fat32_get_next_cluster
|
||||
mov ax, '32'
|
||||
push ax ; save for secondary loader
|
||||
mov word [si+3], ax
|
||||
call out_string
|
||||
; FAT32 - init cache for FAT table: no sectors loaded
|
||||
lea si, [bp + cache1head - dat]
|
||||
mov [si], si ; no sectors in cache:
|
||||
mov [si+2], si ; 'prev' & 'next' links point to self
|
||||
mov [bp + cache1end - dat], 3400h ; first free item = 3400h
|
||||
mov [bp + cache1limit - dat], 3C00h
|
||||
mov eax, [bx+36] ; BPB_FATSz32
|
||||
mov esi, [bx+44] ; BPB_RootClus
|
||||
jmp fat_common
|
||||
not_fat:
|
||||
unknown_fs:
|
||||
mov si, errfs_msg
|
||||
call out_string
|
||||
jmp next_partition
|
||||
fat_common:
|
||||
push ss
|
||||
pop es
|
||||
movzx edx, byte [bx+16] ; BPB_NumFATs
|
||||
mul edx
|
||||
mov [bp + root_start - dat], eax ; this is for FAT1x
|
||||
; eax = total size of all FAT tables, in sectors
|
||||
movzx ecx, word [bx+17] ; BPB_RootEntCnt
|
||||
add ecx, 0xF
|
||||
shr ecx, 4
|
||||
add eax, ecx
|
||||
mov cx, word [bx+14] ; BPB_RsvdSecCnt
|
||||
add [bp + root_start - dat], ecx ; this is for FAT1x
|
||||
add eax, ecx
|
||||
; cluster 2 begins from sector eax
|
||||
movzx ebx, byte [bx+13] ; BPB_SecPerClus
|
||||
sub eax, ebx
|
||||
sub eax, ebx
|
||||
mov [bp + data_start - dat], eax
|
||||
; no clusters in folders cache
|
||||
mov di, foldcache_clus - 2
|
||||
xor ax, ax
|
||||
mov cx, 7*8/2 + 1
|
||||
rep stosw
|
||||
mov [bp + root_clus - dat], esi
|
||||
; load secondary loader
|
||||
mov [bp + load_file_ptr - dat], load_file_fat
|
||||
load_secondary:
|
||||
push 0x1000
|
||||
pop es
|
||||
xor bx, bx
|
||||
mov si, kernel_name
|
||||
mov cx, 0x30000 / 0x200
|
||||
call [bp + load_file_ptr - dat]
|
||||
; say error if needed
|
||||
mov si, error_too_big
|
||||
dec bx
|
||||
js @f
|
||||
jz find_error_si
|
||||
mov si, disk_error_msg
|
||||
jmp find_error_si
|
||||
@@:
|
||||
; fill loader information and jump to secondary loader
|
||||
mov al, 'h' ; boot device: hard drive
|
||||
mov ah, [bp + boot_drive - dat]
|
||||
sub ah, 80h ; boot device: identifier
|
||||
pop bx ; restore file system ID ('12'/'16'/'32'/'nt')
|
||||
mov si, callback
|
||||
jmp 1000h:0000h
|
||||
|
||||
nomem:
|
||||
mov si, nomem_msg
|
||||
call out_string
|
||||
jmp $
|
||||
|
||||
ntfs:
|
||||
push 'nt' ; save for secondary loader
|
||||
mov si, ntfs_msg
|
||||
call out_string
|
||||
xor eax, eax
|
||||
mov [bp + data_start - dat], eax
|
||||
mov ecx, [bx+40h] ; frs_size
|
||||
cmp cl, al
|
||||
jg .1
|
||||
neg cl
|
||||
inc ax
|
||||
shl eax, cl
|
||||
jmp .2
|
||||
.1:
|
||||
mov eax, ecx
|
||||
shl eax, 9
|
||||
.2:
|
||||
mov [bp + frs_size - dat], ax
|
||||
; standard value for frs_size is 0x400 bytes = 1 Kb, and it cannot be set different
|
||||
; (at least with standard tools)
|
||||
; we allow extra size, but no more than 0x1000 bytes = 4 Kb
|
||||
mov si, invalid_volume_msg
|
||||
cmp eax, 0x1000
|
||||
ja find_error_si
|
||||
; must be multiple of sector size
|
||||
test ax, 0x1FF
|
||||
jnz find_error_si
|
||||
shr ax, 9
|
||||
xchg cx, ax
|
||||
; initialize cache - no data loaded
|
||||
lea si, [bp + cache1head - dat]
|
||||
mov [si], si
|
||||
mov [si+2], si
|
||||
mov word [si+4], 3400h ; first free item = 3400h
|
||||
mov word [si+6], 3400h + 8*8 ; 8 items in this cache
|
||||
; read first MFT record - description of MFT itself
|
||||
mov [bp + cur_obj - dat], mft_string
|
||||
mov eax, [bx+30h] ; mft_cluster
|
||||
mul [bp + sect_per_clust - dat]
|
||||
push 0x8000
|
||||
pop es
|
||||
xor bx, bx
|
||||
push es
|
||||
call read
|
||||
pop ds
|
||||
call restore_usa
|
||||
; scan for unnamed $DATA attribute
|
||||
mov [bp + freeattr - dat], 4000h
|
||||
mov ax, 80h
|
||||
call load_attr
|
||||
push ss
|
||||
pop ds
|
||||
mov si, nodata_string
|
||||
jc find_error_si
|
||||
; load secondary loader
|
||||
mov [bp + load_file_ptr - dat], load_file_ntfs
|
||||
jmp load_secondary
|
||||
|
||||
find_error_si:
|
||||
push si
|
||||
find_error_sp:
|
||||
cmp [bp + in_callback - dat], 0
|
||||
jnz error_in_callback
|
||||
push ss
|
||||
pop ds
|
||||
push ss
|
||||
pop es
|
||||
mov si, error_msg
|
||||
call out_string
|
||||
mov si, [bp + cur_obj - dat]
|
||||
@@:
|
||||
lodsb
|
||||
test al, al
|
||||
jz @f
|
||||
cmp al, '/'
|
||||
jz @f
|
||||
mov ah, 0Eh
|
||||
mov bx, 7
|
||||
int 10h
|
||||
jmp @b
|
||||
@@:
|
||||
mov si, colon
|
||||
call out_string
|
||||
pop si
|
||||
call out_string
|
||||
mov si, newline
|
||||
call out_string
|
||||
mov sp, 0x3000
|
||||
jmp next_partition
|
||||
error_in_callback:
|
||||
; return status: file not found, except for read errors
|
||||
mov bx, 2
|
||||
cmp si, disk_error_msg
|
||||
jnz @f
|
||||
inc bx
|
||||
@@:
|
||||
mov ax, 0xFFFF
|
||||
mov dx, ax
|
||||
mov sp, 3000h - 6
|
||||
ret
|
||||
|
||||
callback:
|
||||
; in: ax = function number; only functions 1 and 2 are defined for now
|
||||
; save caller's stack
|
||||
mov dx, ss
|
||||
mov cx, sp
|
||||
; set our stack (required because we need ss=0)
|
||||
xor si, si
|
||||
mov ss, si
|
||||
mov sp, 3000h
|
||||
mov bp, dat
|
||||
mov [bp + in_callback - dat], 1
|
||||
push dx
|
||||
push cx
|
||||
; set ds:si -> ASCIIZ name
|
||||
lea si, [di+6]
|
||||
; set cx = limit in sectors; 4Kb = 8 sectors
|
||||
movzx ecx, word [di+4]
|
||||
shl cx, 3
|
||||
; set es:bx = pointer to buffer
|
||||
les bx, [di]
|
||||
; call our function
|
||||
stc ; unsupported function
|
||||
dec ax
|
||||
jz callback_readfile
|
||||
dec ax
|
||||
jnz callback_ret
|
||||
call continue_load_file
|
||||
jmp callback_ret_succ
|
||||
callback_readfile:
|
||||
; function 1: read file
|
||||
; in: ds:di -> information structure
|
||||
; dw:dw address
|
||||
; dw limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
|
||||
; ASCIIZ name
|
||||
; out: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=2 - file not found, bx=3 - read error
|
||||
; out: dx:ax = file size (0xFFFFFFFF if file was not found)
|
||||
call [bp + load_file_ptr - dat]
|
||||
callback_ret_succ:
|
||||
clc
|
||||
callback_ret:
|
||||
; restore caller's stack
|
||||
pop cx
|
||||
pop ss
|
||||
mov sp, cx
|
||||
; return to caller
|
||||
retf
|
||||
|
||||
read_file_chunk.resident:
|
||||
; auxiliary label for read_file_chunk procedure
|
||||
mov di, bx
|
||||
lodsw
|
||||
read_file_chunk.resident.continue:
|
||||
mov dx, ax
|
||||
add dx, 0x1FF
|
||||
shr dx, 9
|
||||
cmp dx, cx
|
||||
jbe @f
|
||||
mov ax, cx
|
||||
shl ax, 9
|
||||
@@:
|
||||
xchg ax, cx
|
||||
rep movsb
|
||||
xchg ax, cx
|
||||
clc ; no disk error if no disk requests
|
||||
mov word [bp + num_sectors - dat], ax
|
||||
ret
|
||||
|
||||
read_file_chunk:
|
||||
; in: ds:si -> file chunk
|
||||
; in: es:bx -> buffer for output
|
||||
; in: ecx = maximum number of sectors to read (high word must be 0)
|
||||
; out: CF=1 <=> disk read error
|
||||
lodsb
|
||||
mov [bp + cur_chunk_resident - dat], al
|
||||
test al, al
|
||||
jz .resident
|
||||
; normal case: load (non-resident) attribute from disk
|
||||
.read_block:
|
||||
lodsd
|
||||
xchg eax, edx
|
||||
test edx, edx
|
||||
jz .ret
|
||||
lodsd
|
||||
; eax = start cluster, edx = number of clusters, cx = limit in sectors
|
||||
imul eax, [bp + sect_per_clust - dat]
|
||||
add eax, [bp + data_start - dat]
|
||||
mov [bp + cur_cluster - dat], eax
|
||||
imul edx, [bp + sect_per_clust - dat]
|
||||
mov [bp + num_sectors - dat], edx
|
||||
and [bp + cur_delta - dat], 0
|
||||
.nonresident.continue:
|
||||
cmp edx, ecx
|
||||
jb @f
|
||||
mov edx, ecx
|
||||
@@:
|
||||
test dx, dx
|
||||
jz .read_block
|
||||
add [bp + cur_delta - dat], edx
|
||||
sub [bp + num_sectors - dat], edx
|
||||
sub ecx, edx
|
||||
push cx
|
||||
mov cx, dx
|
||||
call read
|
||||
pop cx
|
||||
jc .ret
|
||||
test cx, cx
|
||||
jnz .read_block
|
||||
.ret:
|
||||
ret
|
||||
|
||||
cache_lookup:
|
||||
; in: eax = value to look, si = pointer to cache structure
|
||||
; out: di->cache entry; CF=1 <=> the value was not found
|
||||
push ds bx
|
||||
push ss
|
||||
pop ds
|
||||
mov di, [si+2]
|
||||
.look:
|
||||
cmp di, si
|
||||
jz .not_in_cache
|
||||
cmp eax, [di+4]
|
||||
jz .in_cache
|
||||
mov di, [di+2]
|
||||
jmp .look
|
||||
.not_in_cache:
|
||||
; cache miss
|
||||
; cache is full?
|
||||
mov di, [si+4]
|
||||
cmp di, [si+6]
|
||||
jnz .cache_not_full
|
||||
; yes, delete the oldest entry
|
||||
mov di, [si]
|
||||
mov bx, [di]
|
||||
mov [si], bx
|
||||
push word [di+2]
|
||||
pop word [bx+2]
|
||||
jmp .cache_append
|
||||
.cache_not_full:
|
||||
; no, allocate new item
|
||||
add word [si+4], 8
|
||||
.cache_append:
|
||||
mov [di+4], eax
|
||||
stc
|
||||
jmp @f
|
||||
.in_cache:
|
||||
; delete this sector from the list
|
||||
push si
|
||||
mov si, [di]
|
||||
mov bx, [di+2]
|
||||
mov [si+2], bx
|
||||
mov [bx], si
|
||||
pop si
|
||||
@@:
|
||||
; add new sector to the end of list
|
||||
mov bx, di
|
||||
xchg bx, [si+2]
|
||||
push word [bx]
|
||||
pop word [di]
|
||||
mov [bx], di
|
||||
mov [di+2], bx
|
||||
pop bx ds
|
||||
ret
|
||||
|
||||
include 'fat.inc'
|
||||
include 'ntfs.inc'
|
||||
|
||||
total_kaput db 13,10,'Fatal error: cannot load the secondary loader',0
|
||||
error_too_big db 'file is too big',0
|
||||
nodata_string db '$DATA '
|
||||
error_not_found db 'not found',0
|
||||
noindex_string db '$INDEX_ROOT not found',0
|
||||
badname_msg db 'bad name for FAT',0
|
||||
invalid_volume_msg db 'invalid volume',0
|
||||
mft_string db '$MFT',0
|
||||
fragmented_string db 'too fragmented file',0
|
||||
invalid_read_request_string db 'cannot read attribute',0
|
||||
|
||||
kernel_name db 'kernel.mnt',0
|
||||
|
||||
align 4
|
||||
dat:
|
||||
|
||||
extended_part_start dd 0 ; start sector for main extended partition
|
||||
extended_part_cur dd ? ; start sector for current extended child
|
||||
extended_parent dd 0 ; start sector for current extended parent
|
||||
partition_start dd 0 ; start sector for current logical disk
|
||||
cur_partition_ofs dw ? ; offset in MBR data for current partition
|
||||
sect_per_clust dd 0
|
||||
; change this variable if you want to boot from other physical drive
|
||||
boot_drive db 80h
|
||||
in_callback db 0
|
||||
|
||||
; uninitialized data
|
||||
use_lba db ?
|
||||
cur_chunk_resident db ?
|
||||
align 2
|
||||
heads dw ?
|
||||
sectors dw ?
|
||||
cache1head rw 2
|
||||
cache1end dw ?
|
||||
cache1limit dw ?
|
||||
data_start dd ?
|
||||
cachelimit dw ?
|
||||
load_file_ptr dw ?
|
||||
cur_obj dw ?
|
||||
missing_slash dw ?
|
||||
root_clus dd ?
|
||||
root_start dd ?
|
||||
get_next_cluster_ptr dw ?
|
||||
frs_size dw ?
|
||||
freeattr dw ?
|
||||
index_root dw ?
|
||||
index_alloc dw ?
|
||||
cur_index_seg dw ?
|
||||
cur_index_cache dw ?
|
||||
filesize dd ?
|
||||
filesize_sectors dd ?
|
||||
cur_cluster dd ?
|
||||
cur_delta dd ?
|
||||
num_sectors dd ?
|
||||
sectors_read dd ?
|
||||
cur_chunk_ptr dw ?
|
||||
|
||||
rootcache_size dw ? ; must be immediately before foldcache_clus
|
||||
if $-dat >= 0x80
|
||||
warning:
|
||||
unoptimal data displacement!
|
||||
end if
|
||||
foldcache_clus rd 7
|
||||
foldcache_mark rw 7
|
||||
foldcache_size rw 7
|
||||
fat_filename rb 11
|
||||
|
||||
if $ > 2000h
|
||||
error:
|
||||
file is too big
|
||||
end if
|
||||
|
||||
; for NT/2k/XP, file must be 16 sectors = 0x2000 bytes long
|
||||
repeat 0x2600 - $
|
||||
db 2 ; any data can be here; 2 is another nice face in ASCII :)
|
||||
end repeat
|
||||
@@ -0,0 +1,391 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
Нет повести печальнее на свете,
|
||||
Чем повесть о заклинившем Reset'е...
|
||||
|
||||
Загрузчик для FAT- и NTFS-томов для случаев, когда основной бутсектор загружает
|
||||
Windows, для носителей с размером сектора 512 байт.
|
||||
|
||||
=====================================================================
|
||||
|
||||
Требования для работы:
|
||||
1) Все используемые файлы должны быть читабельны.
|
||||
2) Минимальный процессор - 80386.
|
||||
3) В системе должно быть как минимум 592K свободной базовой памяти.
|
||||
4) Пути к используемым файлам не должны содержать символических ссылок NTFS
|
||||
(жёсткие ссылки допускаются).
|
||||
5) Используемые файлы не должны быть сжатыми или разреженными файлами
|
||||
(актуально для NTFS, для FAT выполнено автоматически).
|
||||
|
||||
=====================================================================
|
||||
|
||||
Документация в тему (ссылки проверялись на валидность 08.08.2008):
|
||||
официальная спецификация FAT: http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
в формате PDF: http://staff.washington.edu/dittrich/misc/fatgen103.pdf
|
||||
русский перевод: http://wasm.ru/docs/11/fatgen103-rus.zip
|
||||
спецификация NTFS: file://C:/windows/system32/drivers/ntfs.sys
|
||||
и file://C:/ntldr либо file://C:/bootmgr
|
||||
неофициальное описание NTFS: http://sourceforge.net/project/showfiles.php?group_id=13956&package_id=16543
|
||||
официальная спецификация расширения EDD BIOS 3.0: http://www.phoenix.com/NR/rdonlyres/19FEBD17-DB40-413C-A0B1-1F3F560E222F/0/specsedd30.pdf
|
||||
то же, версия 1.1: http://www.phoenix.com/NR/rdonlyres/9BEDED98-6B3F-4DAC-BBB7-FA89FA5C30F0/0/specsedd11.pdf
|
||||
описание функций BIOS: Interrupt List by Ralf Brown: http://www.cs.cmu.edu/~ralf/files.html
|
||||
официальная спецификация Boot BIOS: http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf
|
||||
официальное описание bcdedit для Vista: http://www.microsoft.com/whdc/system/platform/firmware/bcdedit_reff.mspx
|
||||
официальное описание работы с базой данных загрузчика Vista: http://www.microsoft.com/whdc/system/platform/firmware/bcd.mspx
|
||||
формат таблицы разделов жёсткого диска: http://www.microsoft.com/technet/prodtechnol/windows2000serv/reskit/prork/prcb_dis_qxql.mspx
|
||||
|
||||
=====================================================================
|
||||
|
||||
Схема используемой памяти:
|
||||
600-2000 код загрузчика (и данные)
|
||||
2000-3000 стек
|
||||
3000-3200 сектор MBR
|
||||
3200-3400 бутсектор логического диска
|
||||
3400-3C00 информация о кэше для таблиц FAT16/FAT32:
|
||||
для FAT16 - массив на 0x100 байт, каждый байт равен
|
||||
0 или 1 в зависимости от того, загружен ли
|
||||
соответствующий сектор таблицы FAT16;
|
||||
для FAT32 - 100h входов по 8 байт: 4 байта
|
||||
(две ссылки - вперёд и назад) для организации L2-списка
|
||||
всех прочитанных секторов в порядке возрастания
|
||||
последнего времени использования + 4 байта для номера
|
||||
сектора; при переполнении кэша выкидывается элемент из
|
||||
головы списка, то есть тот, к которому дольше всех
|
||||
не было обращений
|
||||
3400-3440 информация о кэше для файловых записей NTFS в
|
||||
таком же формате, как и кэш для FAT32, но на 8 входов
|
||||
3480-34C0 заголовки для кэшей записей индекса NTFS
|
||||
3500-3D00 информация о кэшах записей индекса NTFS: с каждой
|
||||
файловой записью связан свой кэш для
|
||||
соответствующего индекса
|
||||
4000-8000 место для информации об атрибутах для NTFS
|
||||
60000-80000 таблица FAT12 / место под таблицу FAT16 /
|
||||
кэш для таблицы FAT32 / кэш для структур NTFS
|
||||
80000-90000 текущий рассматриваемый кластер
|
||||
90000-92000 FAT: кэш для корневой папки
|
||||
92000-... FAT: кэш для некорневых папок (каждой папке отводится
|
||||
2000h байт = 100h входов, одновременно в кэше
|
||||
может находиться не более 7 папок;
|
||||
точный размер определяется размером доступной
|
||||
физической памяти - как правило, непосредственно
|
||||
перед A0000 размещается EBDA, Extended BIOS Data Area)
|
||||
|
||||
=====================================================================
|
||||
|
||||
Основной процесс загрузки.
|
||||
0a. Загрузка из-под DOS и Win9x: установка kordldr.win осуществляется
|
||||
размещением команды install=c:\kordldr.win в первой строке config.sys;
|
||||
при этом основной загрузчик системы загружает kordldr.win как обычный
|
||||
com-файл, в какой-то сегмент по смещению 100h и передаёт управление
|
||||
в начало кода (xxxx:0100).
|
||||
0б. Загрузка из-под WinNT/2000/XP: установка kordldr.win осуществляется
|
||||
добавлением строки наподобие c:\kordldr.win="KordOS" в секцию
|
||||
[operating systems] файла boot.ini; если загружаемый файл имеет размер
|
||||
не менее 8 Кб (0x2000 байт) и по смещению 3 содержит сигнатуру 'NTFS'
|
||||
(в случае kordldr.win так и есть), то основной загрузчик каждой из
|
||||
этих систем загружает kordldr.win по адресу 0D00:0000 и передаёт
|
||||
управление на адрес 0D00:0256.
|
||||
0в. Загрузка из-под Vista: установка kordldr.win осуществляется манипуляциями
|
||||
с базой данных основного загрузчика через bcdedit и подробно описана в
|
||||
инструкции к kordldr.win; основной загрузчик загружает целиком
|
||||
kordldr.win по адресу 0000:7C00 и передаёт управление в начало кода.
|
||||
1. При загрузке из-под DOS/9x основной загрузчик не ожидает, что загруженная
|
||||
им программа окажется в свою очередь загрузчиком, и в этом случае
|
||||
kordldr.win оказывается в условиях, когда основной загрузчик уже
|
||||
установил какое-то окружение, в частности, перехватил некоторые
|
||||
прерывания. Поэтому перед остальными действиями загрузчик должен
|
||||
восстановить систему в начальное состояние. (При загрузке под
|
||||
NT-линейкой такой проблемы не возникает, поскольку там основной
|
||||
загрузчик ничего в системе не трогает.) Поэтому перед собственно
|
||||
инициализацией KordOS при работе из-под DOS/9x производятся
|
||||
дополнительные действия. Первым делом kordldr проверяет, какой из
|
||||
случаев 0а и 0в имеет место (случай 0б отличается тем, что передаёт
|
||||
управление не на начало кода): определяет значение ip (команда call
|
||||
помещает в стек адрес следующей после call инструкции, команда pop si
|
||||
выталкивает его в регистр si), и если оно равно 100h, то kordldr
|
||||
загружен как com-файл из-под DOS/9x. Тогда он спрашивает подтверждения
|
||||
у пользователя (поскольку в этой схеме kordldr загружается всегда,
|
||||
он должен оставить возможность продолжить загрузку DOS/9x). Если
|
||||
пользователь хочет продолжить обычную загрузку, kordldr завершается.
|
||||
Иначе используется тот факт, что при выдаче прерывания перезагрузки
|
||||
int 19h система предварительно снимает все свои перехваты BIOSовских
|
||||
прерываний, а потом в свою очередь выдаёт int 19h уже BIOSу. Так что
|
||||
kordldr устанавливает свой обработчик трассировочного прерывания,
|
||||
устанавливает флаг трассировки и передаёт управление DOSовскому
|
||||
обработчику. Обработчик трассировочного прерывания ничего не делает
|
||||
до тех пор, пока следующей инструкцией не оказывается int 19h, а
|
||||
в этот момент отбирает управление и продолжает загрузку KordOS.
|
||||
При этом BIOSовские обработчики восстановлены за исключением,
|
||||
быть может, прерывания таймера int 8, которое, возможно, восстановлено
|
||||
до команды jmp far на оригинальный обработчик. В последнем случае его
|
||||
нужно восстановить явно.
|
||||
2. Загрузчик перемещает свой код на адрес 0000:0600.
|
||||
3. (метка real_entry) Загрузчик устанавливает сегментные регистры ds = es = 0,
|
||||
настраивает стек ss:sp = 0000:3000 и устанавливает bp так, чтобы
|
||||
все данные можно было адресовать через [bp+N] с однобайтовым N
|
||||
(в дальнейшем они так и будут адресоваться для освобождения ds и
|
||||
экономии на размере кода). Разрешает прерывания на случай, если
|
||||
они были запрещены. Выдаёт сообщение о начале загрузки, начинающееся
|
||||
с весёлой рожицы (символ с ASCII-кодом 2).
|
||||
4. Определяет характеристики жёсткого диска, указанного в качестве
|
||||
загрузочного: проверяет поддержку LBA (функция 41h прерывания 13h),
|
||||
если LBA не поддерживается, то определяет геометрию - число дорожек
|
||||
и число секторов на дорожке (функция 8 прерывания 13h), эти параметры
|
||||
нужны функции чтения с диска.
|
||||
5. (метка new_partition_ex) Устраивает цикл по разделам жёсткого диска.
|
||||
Цель цикла - для каждого логического диска попытаться загрузиться с
|
||||
него (действия по загрузке с конкретного логического диска начинаются
|
||||
с метки not_extended), при ошибке загрузки управление передаётся
|
||||
назад этому циклу (метка next_partition), и поиск подходящего раздела
|
||||
продолжается. На выходе заполняется одна переменная partition_start,
|
||||
имеющая смысл начала текущего рассматриваемого логического диска,
|
||||
но по ходу дела из-за приколов таблиц разделов используются ещё четыре
|
||||
переменных. cur_partition_ofs - фактически счётчик цикла, формально
|
||||
указатель на текущий вход в текущей загрузочной записи. Сама
|
||||
загрузочная запись считывается в память начиная с адреса 3000h.
|
||||
Три оставшихся нужны для правильной работы с расширенными разделами.
|
||||
В каждой загрузочной записи помещается не более 4 записей о разделах.
|
||||
Поэтому главной загрузочной записи, размещающейся в первом физическом
|
||||
секторе диска, может не хватить, и обычно создаётся так называемый
|
||||
расширенный раздел с расширенными загрузочными записями, формат
|
||||
которых почти идентичен главной. Расширенный раздел может быть только
|
||||
один, но в нём может быть много логических дисков и расширенных
|
||||
загрузочных записей. Расширенные загрузочные записи организованы
|
||||
в односвязный список, в каждой такой записи первый вход указывает
|
||||
на соответствующий логический диск, а второй - на следующую расширенную
|
||||
загрузочную запись.
|
||||
При этом в главной загрузочной записи все адреса разделов являются
|
||||
абсолютными номерами секторов. В расширенных же записях адреса разделов
|
||||
относительны, причём с разными базами: адрес логического диска
|
||||
указывается относительно расширенной записи, а адрес следующей
|
||||
расширенной записи указывается относительно начала расширенного
|
||||
раздела. Такой разнобой выглядит несколько странно, но имеет место
|
||||
быть. Три оставшихся переменных содержат: extended_part_start -
|
||||
начало расширенного раздела; extended_parent - текущая рассматриваемая
|
||||
расширенная загрузочная запись; extended_part_cur - следующая
|
||||
загрузочная запись для рассмотрения.
|
||||
Цикл выглядит так: просматриваются все разделы, указанные в текущей
|
||||
(главной или расширенной) загрузочной записи; для нормальных разделов
|
||||
(они же логические диски) происходит переход на not_extended, где
|
||||
устанавливается partition_start и начинается собственно загрузка
|
||||
(последующие шаги); при встрече с разделом, тип которого указывает
|
||||
на расширенность (5 или 0xF), код запоминает начало этого раздела
|
||||
(в главной загрузочной записи такой тип означает расширенный раздел,
|
||||
в расширенной - только указатель на следующую расширенную запись,
|
||||
в обоих случаях он может встретиться только один раз в данной записи);
|
||||
когда код доходит до конца списка, все нормальные разделы, описываемые
|
||||
в этой записи, уже просмотрены, так что код с чистой совестью переходит
|
||||
к следующей расширенной записи. Если он её не встретил, значит, уже
|
||||
все логические разделы были подвергнуты попыткам загрузиться, и все
|
||||
безрезультатно, так что выводится ругательство и работа останавливается
|
||||
(jmp $).
|
||||
Может возникнуть вопрос, зачем нужна такая сложная схема и почему
|
||||
нельзя узнать нужный логический диск заранее или хотя бы ограничиться
|
||||
первым попавшимся логическим диском, не крутя цикл. Так вот, вариант
|
||||
с предварительным определением нужного раздела в данном случае не
|
||||
используется, поскольку повлёк бы за собой нетривиальные лишние
|
||||
действия по установке (в текущем виде установку можно провести вручную,
|
||||
и она сводится к указанию системному загрузчику на существование
|
||||
kordldr); кстати, в альтернативной версии загрузки после
|
||||
Windows-загрузчика, когда установка осуществляется не вручную, а
|
||||
специальной программой под Windows, используется модифицированная
|
||||
версия, в которой как раз начальный физический сектор нужного раздела
|
||||
прописывается установщиком. Сам kordldr не может установить, с какого
|
||||
раздела его загрузил Windows-загрузчик (и вообще под NT/2000/XP обязан
|
||||
быть файлом на диске C:\). Вариант с первым попавшимся логическим
|
||||
диском был реализован в первой версии загрузчика, но по ходу дела
|
||||
обнаружилось, что таки нужно крутить цикл: во-вторых, может быть
|
||||
приятным, что сама система может стоять вовсе не на системном C:\, а и
|
||||
на других дисках; во-первых, диск C: может и не быть первым логическим
|
||||
разделом - Vista любит создавать скрытый первичный раздел перед
|
||||
системным, и тогда диск C: становится вторым логическим.
|
||||
6. Извещает пользователя о том, что происходит попытка загрузки с очередного
|
||||
логического диска.
|
||||
7. Читает первый сектор логического диска и определяет файловую систему.
|
||||
И в FAT, и в NTFS поле со смещением +11 содержит число байт в секторе
|
||||
и должно совпадать с характеристикой физического носителя, то есть
|
||||
200h байт. И в FAT, и в NTFS поле со смещением +13 содержит число
|
||||
секторов в кластере и должно быть степенью двойки.
|
||||
Критерий NTFS: поле со смещением +3 содержит строку NTFS и поле со
|
||||
смещением +16 нулевое (в FAT оно содержит число таблиц FAT и обязано
|
||||
быть ненулевым).
|
||||
Критерий FAT: загрузчик вычисляет число кластеров, определяет
|
||||
предположительный тип (FAT12/FAT16/FAT32) и проверяет байт по смещению
|
||||
+38 для FAT12/16, +66 для FAT32 (он должен быть равен 0x29).
|
||||
После определения типа файловой системы извещает пользователя об
|
||||
определённом типе. Если файловая система не распознана, выдаёт
|
||||
соответствующее сообщение и переходит к следующему логическому диску.
|
||||
8a. Для FAT12-томов: засовывает в стек идентификатор файловой системы -
|
||||
константу '12'; устанавливает указатель на функцию получения следующего
|
||||
в цепочке FAT кластера на FAT12-обработчик; считывает в память всю
|
||||
таблицу FAT12 (она не превосходит 0x1800 байт = 6 Кб), при ошибке
|
||||
чтения пытается использовать другие копии FAT.
|
||||
8б. Для FAT16-томов: засовывает в стек идентификатор файловой системы -
|
||||
константу '16'; устанавливает указатель на функцию получения следующего
|
||||
в цепочке FAT кластера на FAT16-обработчик; инициализирует информацию
|
||||
о кэше секторов FAT (массив байт с возможными значениями 0 и 1,
|
||||
означающими, был ли уже загружен соответствующий сектор - всего в
|
||||
таблице FAT16 не более 0x100 секторов) - ни один сектор ещё не
|
||||
загружен, все байты нулевые.
|
||||
8в. Для FAT32-томов: засовывает в стек идентификатор файловой системы -
|
||||
константу '32'; устанавливает указатель на функцию получения следующего
|
||||
в цепочке FAT кластера на FAT16-обработчик; инициализирует информацию
|
||||
о кэше секторов FAT (формат информации описан выше, в распределении
|
||||
используемой загрузчиком памяти) - ни один сектор ещё не загружен.
|
||||
8г. Общее для FAT-томов: определяет значения служебных переменных
|
||||
root_start (первый сектор корневого каталога в FAT12/16, игнорируется
|
||||
при обработке FAT32-томов), data_start (начало данных с поправкой,
|
||||
вводимой для того, чтобы кластер N начинался с сектора
|
||||
N*sectors_per_cluster+data_start), root_clus (первый кластер корневого
|
||||
каталога в FAT32, 0 в FAT12/16); устанавливает указатель на функцию
|
||||
загрузки файла на FAT-обработчик.
|
||||
8д. Для NTFS-томов: засовывает в стек идентификатор файловой системы -
|
||||
константу 'nt'; определяет значение служебной переменной frs_size
|
||||
(размер в байтах файловой записи, File Record Segment), для полной
|
||||
корректности проверяет, что это значение (равное 0x400 байт на всех
|
||||
реальных NTFS-томах - единственный способ изменить его заключается
|
||||
в пересоздании всех системных структур вручную) не превосходит 0x1000
|
||||
и кратно размеру сектора 0x200 байт; инициализирует кэш файловых
|
||||
записей - ничего ещё не загружено; считывает первый кластер $MFT
|
||||
и загружает информацию о расположении на диске всей таблицы $MFT
|
||||
(атрибут 0x80, $Data); устанавливает указатель на функцию загрузки
|
||||
файла на NTFS-обработчик.
|
||||
9. (метка load_secondary) Вызывает функцию загрузки файла для файла вторичного
|
||||
загрузчика. При обнаружении ошибки переходит на обработчик ошибок с
|
||||
соответствующим сообщением.
|
||||
10. Устанавливает регистры для вторичного загрузчика: al='h' (жёсткий диск),
|
||||
ah=номер диска (для готового бинарника - 0 (BIOS-идентификатор 80h),
|
||||
может быть изменён путём модификации константы в исходнике или
|
||||
специальным установщиком), bx=идентификатор файловой системы (берётся
|
||||
из стека, куда ранее был засунут на шаге 8), ds:si=указатель на
|
||||
callback-функцию.
|
||||
11. Передаёт управление вторичному загрузчику дальним переходом на 1000:0000.
|
||||
|
||||
Функция обратного вызова для вторичного загрузчика:
|
||||
предоставляет возможность чтения файла.
|
||||
Вход и выход описаны в спецификации на загрузчик.
|
||||
Чтение файла:
|
||||
1. Сохраняет стек вызывающего кода и устанавливает свой стек:
|
||||
ss:sp = 0:3000, bp=dat: пара ss:bp при работе с остальным
|
||||
кодом должна указывать на 0:dat.
|
||||
2. Разбирает переданные параметры и вызывает процедуру загрузки файла.
|
||||
3. Восстанавливает стек вызывающего кода и возвращает управление.
|
||||
|
||||
Вспомогательные процедуры.
|
||||
Процедура чтения секторов (read):
|
||||
на входе должно быть установлено:
|
||||
ss:bp = 0:dat
|
||||
es:bx = указатель на начало буфера, куда будут прочитаны данные
|
||||
eax = стартовый сектор (относительно начала логического диска)
|
||||
cx = число секторов (должно быть больше нуля)
|
||||
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные,
|
||||
флаг CF установлен, если возникла ошибка чтения
|
||||
1. Переводит стартовый сектор (отсчитываемый от начала тома) в сектор на
|
||||
устройстве, прибавляя номер первого сектора логического диска,
|
||||
найденный при переборе дисков.
|
||||
2. В цикле (шаги 3-6) читает секторы, следит за тем, чтобы на каждой итерации
|
||||
CHS-версия: все читаемые секторы были на одной дорожке.
|
||||
LBA-версия: число читаемых секторов не превосходило 7Fh (требование
|
||||
спецификации EDD BIOS).
|
||||
CHS-версия:
|
||||
3. Переводит абсолютный номер сектора в CHS-систему: сектор рассчитывается как
|
||||
единица плюс остаток от деления абсолютного номера на число секторов
|
||||
на дорожке; дорожка рассчитывается как остаток от деления частного,
|
||||
полученного на предыдущем шаге, на число дорожек, а цилиндр - как
|
||||
частное от этого же деления. Если число секторов для чтения больше,
|
||||
чем число секторов до конца дорожки, уменьшает число секторов для
|
||||
чтения.
|
||||
4. Формирует данные для вызова int 13h (ah=2 - чтение, al=число секторов,
|
||||
dh=головка, (младшие 6 бит cl)=сектор,
|
||||
(старшие 2 бита cl и весь ch)=дорожка, dl=диск, es:bx->буфер).
|
||||
5. Вызывает BIOS. Если BIOS рапортует об ошибке, выполняет сброс диска
|
||||
и повторяет попытку чтения, всего делается не более трёх попыток
|
||||
(несколько попыток нужно в случае дискеты для гарантии того, что
|
||||
мотор раскрутился). Если все три раза происходит ошибка чтения,
|
||||
переходит на код обработки ошибок с сообщением "Read error".
|
||||
6. В соответствии с числом прочитанных на текущей итерации секторов
|
||||
корректирует текущий сектор, число оставшихся секторов и указатель на
|
||||
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
|
||||
работу, иначе возвращается на шаг 3.
|
||||
LBA-версия:
|
||||
3. Если число секторов для чтения больше 7Fh, уменьшает его (для текущей
|
||||
итерации) до 7Fh.
|
||||
4. Формирует в стеке пакет для int 13h (кладёт все нужные данные командами
|
||||
push, причём в обратном порядке: стек - структура LIFO, и данные в
|
||||
стеке хранятся в обратном порядке по отношению к тому, как их туда
|
||||
клали).
|
||||
5. Вызывает BIOS. Если BIOS рапортует об ошибке, переходит на код обработки
|
||||
ошибок с сообщением "Read error". Очищает стек от пакета,
|
||||
сформированного на предыдущем шаге.
|
||||
6. В соответствии с числом прочитанных на текущей итерации секторов
|
||||
корректирует текущий сектор, число оставшихся секторов и указатель на
|
||||
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
|
||||
работу, иначе возвращается на шаг 3.
|
||||
|
||||
Процедура обработки ошибок (find_error_si и find_error_sp):
|
||||
на входе: указатель на сообщение об ошибке в si либо на верхушке стека
|
||||
0. Если вызывается find_error_si, она помещает переданный указатель в стек.
|
||||
1. Если ошибка произошла в процессе работы callback-функции, то
|
||||
(метка error_in_callback) обработчик просто возвращает управление
|
||||
вызвавшему коду, рапортуя о ненайденном файле.
|
||||
2. Если же ошибка произошла до передачи управления вторичному загрузчику,
|
||||
обработчик выводит сообщение типа "Error: <текущий объект>: <ошибка>"
|
||||
и (восстановив стек) переходит к следующему логическому диску.
|
||||
|
||||
Процедура чтения файла/атрибута по известному размещению на диске
|
||||
(read_file_chunk):
|
||||
на входе должно быть установлено:
|
||||
ds:si = указатель на информацию о размещении
|
||||
es:bx = указатель на начало буфера, куда будут прочитаны данные
|
||||
ecx = лимит числа секторов для чтения, старшее слово должно быть 0
|
||||
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные,
|
||||
флаг CF установлен, если возникла ошибка чтения
|
||||
1. Определяет, является ли атрибут резидентным (возможно только в NTFS
|
||||
и означает, что данные файла/атрибута уже были целиком прочитаны при
|
||||
обработке информации о файле) или нерезидентным (означает, что данные
|
||||
хранятся где-то на диске, и имеется информация о том, где именно).
|
||||
2. Для резидентных атрибутов (метка read_file_chunk.resident) просто копирует
|
||||
данные по месту назначения (с учётом указанного лимита).
|
||||
3. Для нерезидентных атрибутов информация состоит из пар <размер очередного
|
||||
фрагмента файла в кластерах, стартовый кластер фрагмента>; процедура
|
||||
читает фрагменты, пока файл не закончится или пока не будет достигнут
|
||||
указанный лимит.
|
||||
|
||||
Процедура просмотра кэша (cache_lookup):
|
||||
на входе должно быть установлено:
|
||||
eax = искомое значение
|
||||
ss:si = указатель на структуру-заголовок кэша
|
||||
на выходе: ss:di = указатель на вход в кэше; флаг CF установлен, если значение
|
||||
было только что добавлено, и сброшен, если оно уже было в кэше.
|
||||
1. Просматривает кэш в поисках указанного значения. Если значение найдено
|
||||
(при этом флаг CF оказывается сброшенным), переходит к шагу 4.
|
||||
2. Если кэш уже заполнен, удаляет из кэша самый старый вход (он находится в
|
||||
голове двусвязного списка), иначе добавляет к кэшу ещё один вход.
|
||||
3. Устанавливает в полученном входе указанное значение. Устанавливает флаг
|
||||
CF, последующие шаги не меняют состояния флагов. Переходит к шагу 5.
|
||||
4. Удаляет вход из списка.
|
||||
5. Добавляет сектор в конец списка (самый новый вход).
|
||||
@@ -0,0 +1,587 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
restore_usa:
|
||||
; Update Sequence Array restore
|
||||
; in: ds:bx -> USA-protected structure
|
||||
push bx
|
||||
lea di, [bx+1feh]
|
||||
mov cx, [bx+6]
|
||||
add bx, [bx+4]
|
||||
dec cx
|
||||
@@:
|
||||
mov ax, [bx+2]
|
||||
mov [di], ax
|
||||
inc bx
|
||||
inc bx
|
||||
add di, 200h
|
||||
loop @b
|
||||
pop bx
|
||||
ret
|
||||
|
||||
find_attr:
|
||||
; in: ds:di->file record, ax=attribute
|
||||
; out: ds:di->attribute or di=0 if not found
|
||||
add di, [di+14h]
|
||||
.1:
|
||||
; attributes' codes are formally dwords, but all of them fit in word
|
||||
cmp word [di], -1
|
||||
jz .notfound
|
||||
cmp word [di], ax
|
||||
jnz .continue
|
||||
; for $DATA attribute, scan only unnamed
|
||||
cmp ax, 80h
|
||||
jnz .found
|
||||
cmp byte [di+9], 0
|
||||
jz .found
|
||||
.continue:
|
||||
add di, [di+4]
|
||||
jmp .1
|
||||
.notfound:
|
||||
xor di, di
|
||||
.found:
|
||||
ret
|
||||
|
||||
process_mcb_nonres:
|
||||
; in: ds:si->attribute, es:di->buffer
|
||||
; out: es:di->buffer end
|
||||
pushad
|
||||
pop di
|
||||
add si, [si+20h]
|
||||
xor ebx, ebx
|
||||
.loop:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .done
|
||||
push invalid_read_request_string
|
||||
movzx cx, al
|
||||
shr cx, 4
|
||||
jz find_error_sp
|
||||
xchg ax, dx
|
||||
and dx, 0Fh
|
||||
jz find_error_sp
|
||||
add si, cx
|
||||
add si, dx
|
||||
pop ax
|
||||
push si
|
||||
dec si
|
||||
movsx eax, byte [si]
|
||||
dec cx
|
||||
jz .l1e
|
||||
.l1:
|
||||
dec si
|
||||
shl eax, 8
|
||||
mov al, [si]
|
||||
loop .l1
|
||||
.l1e:
|
||||
xchg ebp, eax
|
||||
dec si
|
||||
movsx eax, byte [si]
|
||||
mov cx, dx
|
||||
dec cx
|
||||
jz .l2e
|
||||
.l2:
|
||||
dec si
|
||||
shl eax, 8
|
||||
mov al, byte [si]
|
||||
loop .l2
|
||||
.l2e:
|
||||
pop si
|
||||
add ebx, ebp
|
||||
; eax=length, ebx=disk block
|
||||
stosd
|
||||
mov eax, ebx
|
||||
stosd
|
||||
cmp di, 0x8000 - 12
|
||||
jbe .loop
|
||||
..attr_overflow:
|
||||
mov si, fragmented_string
|
||||
jmp find_error_si
|
||||
.done:
|
||||
xor ax, ax
|
||||
stosw
|
||||
stosw
|
||||
push di
|
||||
popad
|
||||
ret
|
||||
|
||||
load_attr:
|
||||
; in: ax=attribute, ds:bx->base record
|
||||
; out: if found: CF=0, attribute loaded to [freeattr], [freeattr] updated,
|
||||
; edx=size of attribute in bytes
|
||||
; out: if not found: CF=1
|
||||
mov di, [bp + freeattr - dat]
|
||||
push ss
|
||||
pop es
|
||||
mov byte [es:di], 1
|
||||
inc di
|
||||
cmp di, 0x8000 - 12
|
||||
ja ..attr_overflow
|
||||
or edx, -1 ; file size is not known yet
|
||||
; scan for attribute
|
||||
push di
|
||||
mov di, bx
|
||||
add di, [di+14h]
|
||||
@@:
|
||||
call find_attr.1
|
||||
test di, di
|
||||
jz .notfound1
|
||||
cmp byte [di+8], 0
|
||||
jnz .nonresident
|
||||
mov si, di
|
||||
pop di
|
||||
push ds
|
||||
jmp .resident
|
||||
.aux_resident:
|
||||
mov ax, ds
|
||||
mov si, di
|
||||
pop di ds bx ds edx
|
||||
push ss
|
||||
pop es
|
||||
push ds
|
||||
mov ds, ax
|
||||
; resident attribute
|
||||
.resident:
|
||||
dec di
|
||||
mov al, 0
|
||||
stosb
|
||||
mov ax, [si+10h]
|
||||
stosw
|
||||
push di
|
||||
add di, ax
|
||||
cmp di, 0x8000 - 12
|
||||
pop di
|
||||
ja ..attr_overflow
|
||||
movzx edx, ax ; length of attribute
|
||||
xchg ax, cx
|
||||
add si, [si+14h]
|
||||
rep movsb
|
||||
mov [bp + freeattr - dat], di
|
||||
pop ds
|
||||
ret
|
||||
.nonresident:
|
||||
; nonresident attribute
|
||||
cmp dword [di+10h], 0
|
||||
jnz @b
|
||||
; read start of data
|
||||
mov si, di
|
||||
mov edx, [di+30h] ; size of attribute
|
||||
pop di
|
||||
call process_mcb_nonres
|
||||
sub di, 4
|
||||
push di
|
||||
.notfound1:
|
||||
pop di
|
||||
push edx
|
||||
; $ATTRIBUTE_LIST is always in base file record
|
||||
cmp ax, 20h
|
||||
jz .nofragmented
|
||||
; try to load $ATTRIBUTE_LIST = 20h
|
||||
push ax
|
||||
mov ax, 20h
|
||||
push [bp + freeattr - dat]
|
||||
mov [bp + freeattr - dat], di
|
||||
push di
|
||||
call load_attr
|
||||
pop di
|
||||
pop [bp + freeattr - dat]
|
||||
pop ax
|
||||
jc .nofragmented
|
||||
push ds bx
|
||||
pusha
|
||||
mov si, di
|
||||
push ss
|
||||
pop ds
|
||||
push 0x8100
|
||||
pop es
|
||||
xor ecx, ecx
|
||||
mov cl, 0x78
|
||||
xor bx, bx
|
||||
push es
|
||||
call read_file_chunk
|
||||
pop ds
|
||||
jc ..found_disk_error
|
||||
test cx, cx
|
||||
jz ..attr_overflow
|
||||
popa
|
||||
push ss
|
||||
pop es
|
||||
xor bx, bx
|
||||
.1:
|
||||
cmp [bx], ax
|
||||
jnz .continue1
|
||||
; only unnamed $DATA attributes!
|
||||
cmp ax, 80h
|
||||
jnz @f
|
||||
cmp byte [bx+6], 0
|
||||
jnz .continue1
|
||||
@@:
|
||||
cmp dword [bx+10h], 0
|
||||
jz .continue1
|
||||
cmp dword [bx+8], 0
|
||||
jnz @f
|
||||
dec di
|
||||
cmp di, [bp + freeattr - dat]
|
||||
lea di, [di+1]
|
||||
jnz .continue1
|
||||
@@:
|
||||
push ds di
|
||||
push ax
|
||||
mov eax, [bx+10h]
|
||||
mov ecx, [bx+8]
|
||||
call read_file_record
|
||||
pop ax
|
||||
mov di, [14h]
|
||||
.2:
|
||||
call find_attr.1
|
||||
cmp byte [di+8], 0
|
||||
jz .aux_resident
|
||||
cmp dword [di+10h], ecx
|
||||
jnz .2
|
||||
mov si, di
|
||||
mov di, sp
|
||||
cmp dword [ss:di+8], -1
|
||||
jnz @f
|
||||
push dword [si+30h] ; size of attribute
|
||||
pop dword [ss:di+8]
|
||||
@@:
|
||||
pop di
|
||||
call process_mcb_nonres
|
||||
sub di, 4
|
||||
pop ds
|
||||
.continue1:
|
||||
add bx, [bx+4]
|
||||
cmp bx, dx
|
||||
jb .1
|
||||
pop bx ds
|
||||
.nofragmented:
|
||||
pop edx
|
||||
dec di
|
||||
cmp di, [bp + freeattr - dat]
|
||||
jnz @f
|
||||
stc
|
||||
ret
|
||||
@@:
|
||||
inc di
|
||||
xor ax, ax
|
||||
stosw
|
||||
stosw
|
||||
mov [bp + freeattr - dat], di
|
||||
ret
|
||||
|
||||
read_file_record:
|
||||
; in: eax = index of record
|
||||
; out: ds:0 -> record
|
||||
; find place in cache
|
||||
push di
|
||||
push si
|
||||
mov si, cache1head
|
||||
call cache_lookup
|
||||
pop si
|
||||
pushf
|
||||
sub di, 3400h
|
||||
shl di, 10-3
|
||||
add di, 0x6000
|
||||
mov ds, di
|
||||
popf
|
||||
pop di
|
||||
jnc .noread
|
||||
; read file record <eax> to ds:0
|
||||
pushad
|
||||
push ds
|
||||
push es
|
||||
movzx ecx, [bp + frs_size - dat]
|
||||
shr cx, 9
|
||||
mul ecx
|
||||
push ds
|
||||
pop es
|
||||
push ss
|
||||
pop ds
|
||||
mov si, 0x4000
|
||||
xor bx, bx
|
||||
push [bp + cur_obj - dat]
|
||||
mov [bp + cur_obj - dat], mft_string
|
||||
push es
|
||||
call read_attr
|
||||
; initialize cache for $INDEX_ALLOCATION for this record
|
||||
pop si
|
||||
push si
|
||||
sub si, 0x6000
|
||||
mov ax, si
|
||||
shr si, 10-3
|
||||
shr ax, 2
|
||||
add si, 3480h
|
||||
add ax, 3500h
|
||||
mov [si], si
|
||||
mov [si+2], si
|
||||
mov [si+4], ax
|
||||
pop ds
|
||||
call restore_usa
|
||||
pop [bp + cur_obj - dat]
|
||||
pop es
|
||||
pop ds
|
||||
popad
|
||||
.noread:
|
||||
ret
|
||||
|
||||
read_attr:
|
||||
; in: eax = offset in sectors, ecx = size in sectors (<10000h), es:bx -> buffer, ds:si -> attribute
|
||||
push invalid_read_request_string
|
||||
cmp byte [si], 0
|
||||
jnz .nonresident
|
||||
cmp eax, 10000h shr 9
|
||||
jae find_error_sp
|
||||
shl ax, 9
|
||||
shl cx, 9
|
||||
cmp ax, [si+2]
|
||||
jae find_error_sp
|
||||
cmp cx, [si+2]
|
||||
ja find_error_sp
|
||||
add si, 3
|
||||
add si, ax
|
||||
mov di, bx
|
||||
rep movsb
|
||||
pop ax
|
||||
ret
|
||||
.nonresident:
|
||||
inc si
|
||||
.loop:
|
||||
mov edx, dword [si]
|
||||
add si, 8
|
||||
test edx, edx
|
||||
jz find_error_sp
|
||||
imul edx, [bp + sect_per_clust - dat]
|
||||
sub eax, edx
|
||||
jnc .loop
|
||||
add eax, edx
|
||||
sub edx, eax
|
||||
push cx
|
||||
cmp ecx, edx
|
||||
jb @f
|
||||
mov cx, dx
|
||||
@@:
|
||||
push bx
|
||||
mov ebx, [si-4]
|
||||
imul ebx, [bp + sect_per_clust - dat]
|
||||
add eax, ebx
|
||||
pop bx
|
||||
call read
|
||||
jc ..found_disk_error
|
||||
mov dx, cx
|
||||
pop cx
|
||||
xor eax, eax
|
||||
sub cx, dx
|
||||
jnz .loop
|
||||
pop ax
|
||||
ret
|
||||
|
||||
load_file_ntfs:
|
||||
; in: ss:bp = 0:dat
|
||||
; in: es:bx = address to load file
|
||||
; in: ds:si -> ASCIIZ name
|
||||
; in: cx = limit in sectors
|
||||
; out: bx = status: bx=0 - ok, bx=1 - file is too big, only part has been loaded, bx=2 - file not found
|
||||
; out: dx:ax = file size (0xFFFFFFFF if file not found)
|
||||
push es bx cx
|
||||
mov eax, 5 ; root cluster
|
||||
mov [bp + cur_obj - dat], root_string
|
||||
.parse_dir_loop:
|
||||
push ds si
|
||||
call read_file_record
|
||||
; find attributes $INDEX_ROOT, $INDEX_ALLOCATION, $BITMAP
|
||||
mov ax, [bp + freeattr - dat]
|
||||
mov [bp + index_root - dat], ax
|
||||
mov ax, 90h ; $INDEX_ROOT
|
||||
xor bx, bx
|
||||
call load_attr
|
||||
mov si, noindex_string
|
||||
jc find_error_si
|
||||
mov ax, [bp + freeattr - dat]
|
||||
mov [bp + index_alloc - dat], ax
|
||||
mov ax, 0A0h ; $INDEX_ALLOCATION
|
||||
call load_attr
|
||||
jnc @f
|
||||
mov [bp + index_alloc - dat], bx
|
||||
@@:
|
||||
push ds
|
||||
; search for entry
|
||||
mov si, [bp + index_root - dat]
|
||||
push ss
|
||||
pop ds
|
||||
push 0x8100
|
||||
pop es
|
||||
xor ecx, ecx
|
||||
mov cl, 0x78
|
||||
xor bx, bx
|
||||
push es
|
||||
call read_file_chunk
|
||||
pop ds
|
||||
jc ..found_disk_error
|
||||
test cx, cx
|
||||
jz ..attr_overflow
|
||||
mov si, invalid_read_request_string
|
||||
cmp word [bx+10], 0
|
||||
jnz find_error_si
|
||||
; calculate number of items in cache
|
||||
mov di, [bx+8] ; subnode_size
|
||||
mov ax, 0x4000
|
||||
sub ax, word [bp + frs_size - dat]
|
||||
cwd
|
||||
div di
|
||||
test ax, ax
|
||||
jz find_error_si
|
||||
mov si, invalid_volume_msg
|
||||
test di, 0x1FF
|
||||
jnz find_error_si
|
||||
pop cx
|
||||
mov [bp + cur_index_seg - dat], cx
|
||||
shl ax, 3
|
||||
sub cx, 6000h
|
||||
mov si, cx
|
||||
shr cx, 2
|
||||
shr si, 10-3
|
||||
add cx, ax
|
||||
add si, 3480h
|
||||
mov [bp + cur_index_cache - dat], si
|
||||
add cx, 3500h
|
||||
mov [ss:si+6], cx
|
||||
mov dx, di
|
||||
add bx, 10h
|
||||
.scan_record:
|
||||
add bx, [bx]
|
||||
.scan:
|
||||
test byte [bx+0Ch], 2
|
||||
jnz .look_child
|
||||
movzx cx, byte [bx+50h] ; namelen
|
||||
lea di, [bx+52h] ; name
|
||||
push ds
|
||||
pop es
|
||||
pop si ds
|
||||
push ds si
|
||||
xor ax, ax
|
||||
.1:
|
||||
lodsb
|
||||
cmp al, '/'
|
||||
jnz @f
|
||||
mov al, 0
|
||||
@@:
|
||||
cmp al, 'A'
|
||||
jb .nocapital
|
||||
cmp al, 'Z'
|
||||
ja .nocapital
|
||||
or al, 20h
|
||||
.nocapital:
|
||||
cmp al, 'a'
|
||||
jb .notletter
|
||||
cmp al, 'z'
|
||||
ja .notletter
|
||||
or byte [es:di], 20h
|
||||
.notletter:
|
||||
scasw
|
||||
loopz .1
|
||||
jb .look_child
|
||||
ja @f
|
||||
cmp byte [si], 0
|
||||
jz .file_found
|
||||
cmp byte [si], '/'
|
||||
jz .file_found
|
||||
@@:
|
||||
push es
|
||||
pop ds
|
||||
add bx, [bx+8]
|
||||
jmp .scan
|
||||
.look_child:
|
||||
push es
|
||||
pop ds
|
||||
test byte [bx+0Ch], 1
|
||||
jz .not_found
|
||||
mov si, [bp + index_alloc - dat]
|
||||
test si, si
|
||||
jz .not_found
|
||||
add bx, [bx+8]
|
||||
mov eax, [bx-8]
|
||||
mov es, [bp + cur_index_seg - dat]
|
||||
push si
|
||||
mov si, [bp + cur_index_cache - dat]
|
||||
call cache_lookup
|
||||
pop si
|
||||
pushf
|
||||
mov bx, di
|
||||
mov bh, 0
|
||||
shr bx, 3
|
||||
imul bx, dx
|
||||
add bx, [bp + frs_size - dat]
|
||||
popf
|
||||
jnc .noread
|
||||
push es
|
||||
push dx
|
||||
push ss
|
||||
pop ds
|
||||
movzx ecx, dx
|
||||
shr cx, 9
|
||||
mul [bp + sect_per_clust - dat]
|
||||
call read_attr
|
||||
pop dx
|
||||
pop es
|
||||
push es
|
||||
pop ds
|
||||
call restore_usa
|
||||
.noread:
|
||||
push es
|
||||
pop ds
|
||||
add bx, 18h
|
||||
jmp .scan_record
|
||||
.not_found:
|
||||
pop [bp + cur_obj - dat]
|
||||
mov si, error_not_found
|
||||
jmp find_error_si
|
||||
.file_found:
|
||||
pop [bp + cur_obj - dat]
|
||||
pop cx
|
||||
mov ax, [bp + index_root - dat]
|
||||
mov [bp + freeattr - dat], ax
|
||||
mov eax, [es:bx]
|
||||
test byte [es:bx+48h+3], 10h
|
||||
jz .regular_file
|
||||
cmp byte [si], 0
|
||||
jz ..directory_error
|
||||
inc si
|
||||
jmp .parse_dir_loop
|
||||
.regular_file:
|
||||
cmp byte [si], 0
|
||||
jnz ..notdir_error
|
||||
; read entry
|
||||
call read_file_record
|
||||
xor bx, bx
|
||||
mov ax, 80h
|
||||
call load_attr
|
||||
mov si, nodata_string
|
||||
jc find_error_si
|
||||
mov si, [bp + index_root - dat]
|
||||
mov [bp + freeattr - dat], si
|
||||
push ss
|
||||
pop ds
|
||||
jmp load_file_common_end
|
||||
@@ -0,0 +1,2 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("bootsect.asm", "fasm %f %o ", "bootsect.bin")
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,418 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
Sector not found. N. N.N.N. N.N.N.N.N.N.N. N.N. N.N.N.N.N.N.?
|
||||
|
||||
Бутсектор для загрузки с CD/DVD с файловой системой ISO-9660.
|
||||
(ISO-9660 и её расширения - стандарт для CD; DVD может использовать
|
||||
либо ISO-9660, либо UDF.)
|
||||
|
||||
=====================================================================
|
||||
|
||||
Требования для работы:
|
||||
1) Сам бутсектор и все используемые файлы должны быть читабельны.
|
||||
2) Минимальный процессор - 80386.
|
||||
3) В системе должно быть как минимум 452K свободной базовой памяти.
|
||||
|
||||
=====================================================================
|
||||
|
||||
Документация в тему (ссылки проверялись на валидность 14.09.2008):
|
||||
стандарт ISO-9660: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
|
||||
стандарт загрузочного CD: http://www.phoenix.com/NR/rdonlyres/98D3219C-9CC9-4DF5-B496-A286D893E36A/0/specscdrom.pdf
|
||||
официальная спецификация расширения EDD BIOS 3.0: http://www.phoenix.com/NR/rdonlyres/19FEBD17-DB40-413C-A0B1-1F3F560E222F/0/specsedd30.pdf
|
||||
то же, версия 1.1: http://www.phoenix.com/NR/rdonlyres/9BEDED98-6B3F-4DAC-BBB7-FA89FA5C30F0/0/specsedd11.pdf
|
||||
описание функций BIOS: Interrupt List by Ralf Brown: http://www.cs.cmu.edu/~ralf/files.html
|
||||
официальная спецификация Boot BIOS: http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf
|
||||
|
||||
=====================================================================
|
||||
|
||||
Схема используемой памяти:
|
||||
1000-1800 временный буфер для чтения одиночных секторов
|
||||
...-7C00 стек
|
||||
7C00-8400 код бутсектора
|
||||
8400-8A00 информация о кэше для папок: массив входов следующего
|
||||
формата:
|
||||
dw следующий элемент в L2-списке закэшированных папок,
|
||||
упорядоченном по времени использования
|
||||
(голова списка - самый старый);
|
||||
dw предыдущий элемент в том же списке;
|
||||
dd первый сектор папки;
|
||||
dw размер папки в байтах;
|
||||
dw сегмент кэша
|
||||
60000-... содержимое Path Table, если она используется
|
||||
+ кэш для папок;
|
||||
точный размер определяется размером доступной
|
||||
физической памяти - как правило, непосредственно
|
||||
перед A0000 размещается EBDA, Extended BIOS Data Area
|
||||
|
||||
=====================================================================
|
||||
|
||||
Основной процесс загрузки.
|
||||
Точка входа (start): получает управление от BIOS при загрузке, при этом
|
||||
dl содержит идентификатор диска, с которого идёт загрузка
|
||||
1. При передаче управления загрузочному коду в случае CD/DVD пара cs:ip
|
||||
равна не 0:7C00, а на 07C0:0000. Поэтому сначала загрузчик делает
|
||||
дальний прыжок на самого себя с целью получить cs=0 (в некоторых
|
||||
местах используется адресация переменных загрузчика через cs, поскольку
|
||||
и ds, и es могут быть заняты под другие сегменты).
|
||||
2. Настраивает стек ss:sp = 0:7C00 (непосредственно перед основным кодом)
|
||||
и сегментные регистры ds=es=0. Форсирует сброшенный флаг направления
|
||||
и разрешённые прерывания. Сохраняет идентификатор загрузочного диска
|
||||
в специальную переменную.
|
||||
3. Проверяет поддержку LBA. Для CD/DVD носителя BIOS обязана предоставлять
|
||||
LBA-функции.
|
||||
4. Ищет описатель тома CD (Primary Volume Descriptor, PVD): по стандарту
|
||||
ISO9660 со смещения 10h начинается цепочка описателей тома,
|
||||
завершающаяся специальным описателем (Volume Descriptor Set
|
||||
Terminator). Код по очереди считывает все сектора, пока не наткнётся
|
||||
либо на искомый описатель, либо на терминатор. Во втором случае
|
||||
выдаётся соответствующее сообщение, и загрузка прекращается.
|
||||
Вообще говоря, в случае мультисессионных CD основной каталог содержимого CD
|
||||
располагается в последней сессии. И спецификация ElTorito загрузочного
|
||||
CD оперирует также с последней сессией. Однако на практике оказывается,
|
||||
что: во-первых, реальные BIOSы не понимают мультисессионных CD и
|
||||
всегда используют первую сессию; во-вторых, BIOSовский int 13h просто
|
||||
не позволяет получить информацию о последней сессии. В связи с этим
|
||||
загрузчик также использует первую сессию. (В-третьих, в одной из BIOS
|
||||
обнаружилась заготовка, которая в случае запроса сектора 10h, в котором
|
||||
во всех нормальных случаях и располагается PVD, перенаправляет его
|
||||
на сектор 10h+(начало сессии). Если бы этот BIOS ещё и грузился с
|
||||
последней сессии, то благодаря заготовке загрузчик без всяких
|
||||
модификаций также читал бы последнюю сессию.)
|
||||
5. (метка pvd_found) Считывает из PVD некоторую информацию о томе во
|
||||
внутренние переменные: размер логического блока (согласно спецификации,
|
||||
должен быть степенью двойки от 512 до размера логического сектора,
|
||||
равного 2048 для CD и DVD); положение на диске корневой папки;
|
||||
вычисляет число блоков в секторе (из предыдущего примечания следует,
|
||||
что оно всегда целое и само является степенью двойки).
|
||||
6. Получает размер базовой памяти вызовом int 12h; на его основе вычисляет
|
||||
размер пространства, которое может использовать загрузчик (от
|
||||
адреса 6000:0000 до конца доступной памяти).
|
||||
7. Загружает таблицу путей CD (Path Table) - область данных, которая содержит
|
||||
базовую информацию обо всех папках на диске. Если таблица слишком
|
||||
велика (больше 62K или больше половины доступной памяти), то она
|
||||
игнорируется. Если таблица путей недоступна, то запрос типа
|
||||
dir1/dir2/dir3/file приведёт к последовательному разбору корневой
|
||||
папки и папок dir1,dir2,dir3; если доступна, то достаточно разобрать
|
||||
саму таблицу путей (где записано положение папки dir1/dir2/dir3)
|
||||
и папку dir3. Если таблица загружена, то соответственно уменьшается
|
||||
объём оставшейся доступной памяти и увеличивается указатель на
|
||||
свободную область.
|
||||
8. Запоминает общий размер и начало кэша для папок (вся оставшаяся после п.7
|
||||
доступная память отводится под этот кэш).
|
||||
9. Выдаёт запрос на чтение файла вторичного загрузчика kord/loader. При ошибке
|
||||
печатает соответствующее сообщение и прекращает загрузку с CD.
|
||||
10. Устанавливает регистры для вторичного загрузчика: al='c' идентифицирует
|
||||
тип устройства - CD/DVD; ah=BIOS-идентификатор диска; bx='is'
|
||||
идентифицирует файловую систему ISO-9660; ds:si указывает на
|
||||
callback-функцию, которую может вызывать вторичный загрузчик.
|
||||
11. Передаёт управление вторичному загрузчику, совершая дальний прыжок
|
||||
на адрес, куда kord/loader был загружен.
|
||||
|
||||
Функция обратного вызова для вторичного загрузчика (callback):
|
||||
предоставляет возможность чтения файла.
|
||||
Вход и выход описаны в спецификации на загрузчик.
|
||||
Перенаправляет запрос соответствующей локальной процедуре (load_file при
|
||||
первом запросе на загрузку файла, loadloop.loadnew при последующих
|
||||
запросах на продолжение загрузки файла).
|
||||
|
||||
Вспомогательные процедуры.
|
||||
Код обработки ошибок (err):
|
||||
1. Выводит строку с сообщением об ошибке.
|
||||
2. Выводит строку "Press any key...".
|
||||
3. Ждёт нажатия any key.
|
||||
4. Вызывает int 18h, давая шанс BIOSу попытаться загрузиться откуда-нибудь ещё.
|
||||
5. Для подстраховки зацикливается.
|
||||
|
||||
Процедура чтения секторов (read_sectors):
|
||||
на входе должно быть установлено:
|
||||
es:bx = указатель на начало буфера, куда будут прочитаны данные
|
||||
eax = стартовый сектор
|
||||
cx = число секторов
|
||||
на выходе:
|
||||
es:bx указывает на конец буфера, в который были прочитаны данные
|
||||
если произошла ошибка чтения, флаг CF установлен
|
||||
1. В цикле (шаги 2-4) читает секторы, следит за тем, чтобы на каждой итерации
|
||||
число читаемых секторов не превосходило 7Fh (требование спецификации
|
||||
EDD BIOS).
|
||||
2. Если число секторов для чтения больше 7Fh, уменьшает его (для текущей
|
||||
итерации) до 7Fh.
|
||||
3. Формирует в стеке пакет для int 13h (кладёт все нужные данные командами
|
||||
push, причём в обратном порядке: стек - структура LIFO, и данные в
|
||||
стеке хранятся в обратном порядке по отношению к тому, как их туда
|
||||
клали).
|
||||
4. Вызывает BIOS. Если BIOS рапортует об ошибке, очищает стек,
|
||||
устанавливает CF=1 и выходит из процедуры.
|
||||
Очищает стек от пакета, сформированного на предыдущем шаге.
|
||||
5. В соответствии с числом прочитанных на текущей итерации секторов
|
||||
корректирует текущий сектор, число оставшихся секторов и указатель на
|
||||
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
|
||||
работу, иначе возвращается на шаг 2.
|
||||
|
||||
Процедура вывода на экран ASCIIZ-строки (out_string):
|
||||
на входе: ds:si -> строка
|
||||
В цикле, пока не достигнут завершающий ноль, вызывает функцию int 10h/ah=0Eh.
|
||||
|
||||
Процедура загрузки файла (load_file):
|
||||
на входе:
|
||||
ds:di = указатель на информационную структуру, описанную в спецификации
|
||||
на загрузчик, а также в комментариях к коду
|
||||
на выходе:
|
||||
bx = статус: 0=успех, 1=файл слишком большой, прочитана только часть,
|
||||
2=файл не найден, 3=ошибка чтения
|
||||
dx:ax = размер файла, 0xFFFFFFFF, если файл не найден
|
||||
1. Если подготовительный код загрузил таблицу путей, то ищет папку в таблице,
|
||||
иначе переходит сразу к шагу 4, установив eax = начальный блок
|
||||
корневой папки.
|
||||
2. Устанавливает es:di на начало таблицы путей. Ограничение на размер
|
||||
гарантирует, что вся таблица помещается в сегменте 6000h.
|
||||
Инициализирует dx (в котором будет хранится номер текущего входа в
|
||||
таблице, считая с 1), cx (размер оставшегося участка таблицы),
|
||||
bx (номер входа, соответствующего родительской папке для текущего
|
||||
рассматриваемого участка пути).
|
||||
3. В цикле ищет вход с нужным родительским элементом и нужным именем. Элементы
|
||||
таблицы путей упорядочены (подробно о порядке написано в спецификации),
|
||||
так что если родительский элемент для очередного входа больше нужного,
|
||||
то нужного входа в таблице нет совсем, и в этом случае происходит
|
||||
выход из процедуры с bx=2, ax=dx=0xFFFF. Если обнаружился элемент,
|
||||
соответствующий очередной папке в запрошенном пути, то на рассмотрение
|
||||
выносится следующая компонента пути. Если эта компонента последняя,
|
||||
то осталось найти файл в папке, и код переходит к пункту 4,
|
||||
установив eax = начальный блок этой папки. Если же нет, то эта
|
||||
компонента должна задавать имя папки, и код возвращается к пункту 3,
|
||||
скорректировав указатель на имя ds:si и номер родительского входа bx.
|
||||
4. (parse_dir) На этом шаге заданы начальный логический блок папки в eax
|
||||
и указатель на имя файла относительно этой папки в ds:si. Если
|
||||
папку искали по таблице путей, то имя файла уже не содержит подпапок;
|
||||
если же нет, то подпапки вполне возможны.
|
||||
5. Файлы в ISO-9660 могут состоять из нескольких кусков (File Section), каждый
|
||||
из которых задаётся отдельным входом в папке. Информация обо всех
|
||||
таких кусках при просмотре папки запоминается в области, начинающейся
|
||||
с адреса 0000:2000. Переменная cur_desc_end содержит указатель на
|
||||
конец этой области, он же указатель, куда будет помещена информация
|
||||
при обнаружении следующего входа. (Папки, согласно спецификации,
|
||||
должны задаваться одним куском.)
|
||||
6. Код сначала ищет запрошенную папку в кэше папок.
|
||||
7. (parse_dir.found) Если папка уже есть в кэше, то она удаляется из списка,
|
||||
отсортированного по давности последнего обращения и код переходит к
|
||||
п.15. (Следующим действием станет добавление папки в конец списка.)
|
||||
8. (parse_dir.notfound) Если же папки нет в кэше, то её придётся загружать
|
||||
с диска. Сначала загружается первый сектор (физический сектор,
|
||||
содержащий первый логический блок). При ошибке ввода/вывода
|
||||
происходит немедленный выход из процедуры с bx=3, dx=ax=0xFFFF.
|
||||
Первый элемент папки содержит информацию о самой этой папке, конкретно
|
||||
загрузчик интересуется её размером.
|
||||
9. Если размер папки слишком большой (больше или равен 64K либо больше половины
|
||||
общего размера кэша), то кэшироваться она не будет. В этом случае код
|
||||
считывает папку посекторно во временный буфер (0000:1000) и посекторно
|
||||
сканирует на наличие запрошенного имени, пока не найдёт такого имени
|
||||
или пока не кончатся данные. (Цикл начинается со сканирования,
|
||||
поскольку первая часть данных уже прочитана.) В конце код переходит
|
||||
к п.17.
|
||||
10. (parse_dir.yescache) Если принято решение о кэшировании папки, то нужно
|
||||
обеспечить достаточное количество свободного места. Для этого может
|
||||
понадобиться выкинуть какое-то количество старых данных (цикл
|
||||
parse_dir.freeloop). Но если просто выкидывать, то, вообще говоря,
|
||||
свободное пространство окажется разорванным на несколько фрагментов.
|
||||
Поэтому при выкидывании какой-то папки из кэша загрузчик перемещает
|
||||
все следующие за ней данные назад по памяти и соответственно
|
||||
корректирует информацию о местонахождении данных в информации о кэше.
|
||||
При этом новое пространство всегда добавляется в конец доступной
|
||||
памяти. Цикл выкидывания продолжается, пока не освободится место,
|
||||
достаточное для хранения папки. Из-за ограничений на размер кэшируемых
|
||||
папок в конце концов место найдётся.
|
||||
11. Выделяется новый элемент кэша. Все удалённые на шаге 10 элементы
|
||||
организуются в единый список свободных элементов; если он непуст,
|
||||
то очередной элемент берётся из этого списка; если же пуст, то
|
||||
берётся совсем новый элемент из области памяти, предназначенной для
|
||||
элементов кэша.
|
||||
12. В новом элементе заполняются поля начального блока, сегмента с данными,
|
||||
размера в байтах.
|
||||
13. Уже прочитанные данные первого физического сектора пересылаются на
|
||||
законное место в кэше.
|
||||
14. Если все данные не исчерпываются первым сектором, то догружаются оставшиеся
|
||||
данные с диска. При ошибке чтения, как и раньше, происходит выход из
|
||||
процедуры с bx=3, ax=dx=0xFFFF.
|
||||
15. (parse_dir.scan) Новый элемент добавляется в конец списка всех элементов
|
||||
кэша.
|
||||
16. Загрузчик ищет запрошенное имя в загруженных данных папки.
|
||||
(Из-за ограничений на размер кэшируемой папки все данные располагаются
|
||||
в одном сегменте.)
|
||||
17. (parse_dir.scandone) Если в процессе сканирования папки не было найдено
|
||||
никаких кусков файла, то cur_desc_end такой же, каким был вначале.
|
||||
В этом случае процедура рапортует о ненайденном файле и выходит.
|
||||
18. (filefound) Пропускает текущую компоненту имени. Если она была не последней
|
||||
(то есть подпапкой, в которой нужно производить дальнейший поиск),
|
||||
то код проверяет, что найденный вход - действительно подпапка,
|
||||
устанавливает новый стартовый блок и возвращается к п.4.
|
||||
Если же последней, то код проверяет, что найденный вход - регулярный
|
||||
файл и начинает загрузку файла.
|
||||
19. Нормализует указатель, по которому требуется прочитать файл. Под
|
||||
нормализацией понимается преобразование типа
|
||||
1234:FC08 -> (1234+0FC0):0008, которое не меняет суммарного адреса,
|
||||
но гарантирует отсутствие переполнений: в приведённом примере попытка
|
||||
переслать 400h байт по rep movsb приведёт к тому, что последние 8
|
||||
байт запишутся не в нужное место, а на 64K раньше. Далее нормализация
|
||||
будет производиться после каждой пересылки. В cur_limit помещает
|
||||
предельный размер для чтения в байтах.
|
||||
20. (loadloop) В цикле по найденным фрагментам файла загружает эти фрагменты
|
||||
(пункты 21-27).
|
||||
21. Обнуляет переменную [cur_start], имеющую смысл числа байт, которое
|
||||
нужно пропустить с начала фрагмента.
|
||||
22. (loadloop.loadnew) На эту метку управление может попасть либо с предыдущего
|
||||
шага, либо напрямую из callback-процедуры при запросе на продолжение
|
||||
чтения. Для этого и нужна вышеупомянутая переменная [cur_start] -
|
||||
при продолжении чтения, прервавшегося из-за конца буфера посередине
|
||||
фрагмента, там будет записано соответствующее значение.
|
||||
23. Определяет текущую длину (хранится в esi) как минимум из длины фрагмента
|
||||
и максимальной длины остатка. Если второе строго меньше, то
|
||||
запоминает, что файл слишком большой и прочитан только частично.
|
||||
Определяет новое значение числа прочитанных байт во фрагменте
|
||||
для возможных будущих вызовов [cur_start].
|
||||
24. Переводит пропускаемое число байт в число логических блоков и байт
|
||||
в первом блоке, последнее число записывает в переменную [first_byte],
|
||||
откуда её позднее достанет read_many_bytes.with_first.
|
||||
25. Если фрагмент записан в обычном режиме (non-interleaved mode), то код
|
||||
определяет начальный блок фрагмента и вызывает вспомогательную функцию
|
||||
чтения блоков. При ошибке чтения устанавливает bx=3 (код ошибки чтения)
|
||||
и выходит из цикла к п.28.
|
||||
26. Если фрагмент записан в чередуемом режиме (interleaved mode), то сначала
|
||||
код пропускает нужное количество непрерывных частей, а потом
|
||||
в цикле загружает непрерывные части с помощью той же функции,
|
||||
в промежутках между частями увеличивая номер начального блока.
|
||||
Пока не кончится фрагмент или пока не наберётся запрошенное число байт.
|
||||
При ошибке чтения делает то же самое, что и в предыдущем случае.
|
||||
27. (loadloop.loadcontinue) Если фрагменты ещё не кончились и предельный размер
|
||||
ещё не достигнут, переходит к следующему фрагменту и п.20. В противном
|
||||
случае устанавливает bx=0 либо bx=1 в зависимости от того, было ли
|
||||
переполнение в п.23.
|
||||
28. (loadloop.calclen) Подсчитывает общую длину файла, суммируя длины всех
|
||||
фрагментов.
|
||||
|
||||
Процедура проверки, является ли текущая компонента имени файла последней
|
||||
(is_last_component):
|
||||
на входе: ds:si = указатель на имя
|
||||
на выходе: флаг CF установлен, если есть последующие компоненты
|
||||
В цикле загружает символы имени в поисках нулевого и '/'; если нашёлся первый,
|
||||
то выходит (при этом CF=0); если нашёлся второй, то устанавливает CF
|
||||
и выходит.
|
||||
|
||||
Процедуры проверки на совпадение текущей компоненты имени файла с именем
|
||||
текущего элемента (test_filename1 для таблицы путей, test_filename2 для папки):
|
||||
на входе: ds:si = указатель на имя, es:di = указатель на элемент
|
||||
таблицы путей для test_filename1, папки для test_filename2
|
||||
на выходе: CF установлен, если имена не совпадают
|
||||
В цикле проверяет совпадение приведённых к верхнему регистру очередных символов
|
||||
имён файла и элемента. Условия выхода из цикла: закончилось имя файла
|
||||
в ds:si (то есть, очередной символ - нулевой либо '/') - совпадение
|
||||
возможно только в ситуации типа имени "filename.ext" и элемента
|
||||
"filename.ext;1" (в ISO9660 ";1" - версия файла, элементы с одинаковыми
|
||||
именами в папке отсортированы по убыванию версий);
|
||||
несовпадение символов - означает, что имена не совпадают;
|
||||
закончилось имя элемента - нужно проверить, закончилось ли при этом имя
|
||||
файла, и в зависимости от этого принимать решение о совпадении.
|
||||
|
||||
Процедура приведения символа в верхний регистр (toupper):
|
||||
на входе: ASCII-символ
|
||||
на выходе: тот же символ в верхнем регистре (он сам, если понятие регистра к
|
||||
нему неприменимо)
|
||||
Из символов в диапазоне 'a' - 'z' включительно вычитает константу 'a'-'A',
|
||||
остальные символы не трогает.
|
||||
|
||||
Процедура поиска файла в данных папки (scan_for_filename_in_sector):
|
||||
на входе:
|
||||
ds:si = указатель на имя файла
|
||||
es:bx = указатель на начало данных папки
|
||||
es:dx = указатель на конец данных папки
|
||||
на выходе:
|
||||
CF сброшен, если найден финальный фрагмент файла
|
||||
(и дальше сканировать папку не нужно)
|
||||
в область для информации о фрагментах файла записывается найденное
|
||||
В цикле просматривает все входы папки, пропуская те, у которых установлен
|
||||
бит Associated (это специальные входы, дополняющие основные). Если
|
||||
имя очередного входа совпадает с именем файла, то запоминает новый
|
||||
фрагмент. Если фрагмент финальный (не установлен бит Multi-Extent),
|
||||
то код выходит с CF=0. Если достигнут конец данных, то код выходит
|
||||
с CF=1. Если очередной вход нулевой (первый байт настоящего входа
|
||||
содержит длину и не может быть нулём), то процедура переходит к
|
||||
рассмотрению следующего логического блока. При этом потенциально
|
||||
возможно переполнение при добавлении размера блока; поскольку такой
|
||||
сценарий означает, что процедура вызвана для кэшированной папки
|
||||
с размером почти 64K и началом данных bx=0 (это свойство вызывающего
|
||||
кода), а размер блока - степень двойки, то после переполнения всегда
|
||||
bx=0, так что это можно обнаружить по взведённому ZF после сложения;
|
||||
в этом случае также происходит выход (а после переполнения CF=1).
|
||||
|
||||
Процедура перевода логического блока в номер сектора:
|
||||
на входе: eax = логический блок
|
||||
на выходе: eax = физический сектор, dx = номер логического блока в секторе
|
||||
Осуществляет обычное деление 32-битного числа на 32-битное (число логических
|
||||
блоков в секторе, хранящееся во внутренней переменной).
|
||||
|
||||
Процедура загрузки физического сектора, содержащего указанный логический блок
|
||||
(load_phys_sector_for_lb_force):
|
||||
на входе: eax = логический блок;
|
||||
si - индикатор, задающий, следует ли читать данные в случае,
|
||||
если логический блок начинается с начала физического:
|
||||
si = 0 - не нужно, si ненулевой - нужно
|
||||
на выходе:
|
||||
физический сектор загружен по адресу 0000:1000
|
||||
si указывает на данные логического блока
|
||||
CF установлен при ошибке чтения
|
||||
Преобразует предыдущей процедурой номер логического блока в номер физического
|
||||
сектора и номер логического блока внутри сектора; если последняя
|
||||
величина нулевая и никаких действий в этом случае не запрошено (si=0),
|
||||
то ничего и не делает; иначе устанавливает si в соответствии с ней
|
||||
и читает сектор.
|
||||
|
||||
Процедуры чтения нужного числа байт из непрерывной цепочки логических блоков
|
||||
(read_many_bytes и read_many_bytes.with_first):
|
||||
на входе:
|
||||
eax = логический блок
|
||||
esi = число байт для чтения
|
||||
es:bx = указатель на начало буфера, куда будут прочитаны данные
|
||||
cur_limit = размер буфера (не меньше esi)
|
||||
на выходе:
|
||||
es:bx указывает на конец буфера, в который были прочитаны данные
|
||||
если произошла ошибка чтения, флаг CF установлен
|
||||
cur_limit соответствующим образом уменьшен
|
||||
Отличие двух процедур: вторая дополнительно принимает во внимание переменную
|
||||
[first_byte], начиная чтение первого блока со смещения [first_byte];
|
||||
соответственно, первая читает блок с начала, обнуляя [first_byte]
|
||||
при входе.
|
||||
1. Отдельно считывает первый физический сектор во временную область 0000:1000,
|
||||
если первый логический блок начинается не с начала сектора. При
|
||||
ошибке чтения выходит из процедуры.
|
||||
2. Пересылает нужную часть данных (возможно, 0 байт), прочитанных в п.1,
|
||||
в буфер. Нормализует указатель на буфер.
|
||||
3. Если все необходимые данные уже прочитаны, выходит из процедуры.
|
||||
4. Дальнейшие данные находятся в нескольких физических секторах, при этом,
|
||||
возможно, последний сектор считывать нужно не целиком.
|
||||
5. Если в буфере есть место для считывания всех секторов, то сразу читаются
|
||||
все сектора, после чего указатель на буфер нужным образом уменьшается.
|
||||
6. Если же нет, то считываются все сектора, кроме последнего, после чего
|
||||
последний сектор считывается отдельно во временную область, и уже
|
||||
оттуда нужная часть данных копируется в буфер.
|
||||
@@ -0,0 +1,2 @@
|
||||
@fasm -m 65535 bootsect.asm bootsect.bin
|
||||
@pause
|
||||
@@ -0,0 +1,15 @@
|
||||
; boot time parameters for KolibriOS
|
||||
|
||||
; timeout in seconds for config settings screen
|
||||
timeout=5
|
||||
|
||||
; width*height
|
||||
;resolution=1024*768
|
||||
|
||||
; where to load ramdisk from
|
||||
; 2 - /hd0/1/kolibri.img
|
||||
; 3 - don't load ramdisk
|
||||
;imgfrom=3
|
||||
|
||||
; which directory to use as /sys
|
||||
;syspath=/HD0/1/KOLIBRIOS
|
||||
@@ -0,0 +1,3 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("bootsect.asm", "fasm %f %o", "bootsect.bin")
|
||||
tup.rule("kordldr.f1x.asm", "fasm %f %o", "kordldr.f1x.bin")
|
||||
@@ -0,0 +1,392 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
use_lba = 0
|
||||
org 0x7C00
|
||||
jmp start
|
||||
nop
|
||||
; FAT parameters, BPB
|
||||
; note: they can be changed at install, replaced with real values
|
||||
; these settings are for most typical 1.44M floppies
|
||||
db 'KOLIBRI ' ; BS_OEMName, ignored
|
||||
dw 200h ; BPB_BytsPerSec
|
||||
BPB_SecsPerClus db 1
|
||||
BPB_RsvdSecCnt dw 1
|
||||
BPB_NumFATs db 2
|
||||
BPB_RootEntCnt dw 0xE0
|
||||
dw 2880 ; BPB_TotSec16
|
||||
db 0xF0 ; BPB_Media
|
||||
BPB_FATSz16 dw 9
|
||||
BPB_SecPerTrk dw 18
|
||||
BPB_NumHeads dw 2
|
||||
BPB_HiddSec dd 0
|
||||
dd 0 ; BPB_TotSec32
|
||||
BS_DrvNum db 0
|
||||
db 0 ; BS_Reserved1
|
||||
db ')' ; BS_BootSig
|
||||
dd 12344321h ; BS_VolID
|
||||
filename:
|
||||
db 'KORD.OS ' ; BS_VolLab
|
||||
db 'FAT12 ' ; BS_FilSysType
|
||||
; Used memory map:
|
||||
; 8000:0000 - current directory
|
||||
; 9000:0000 - root directory data [cached]
|
||||
start:
|
||||
xor ax, ax
|
||||
mov ss, ax
|
||||
mov sp, 0x7C00
|
||||
mov ds, ax
|
||||
mov bp, sp
|
||||
cld
|
||||
sti
|
||||
mov [bp+BS_DrvNum-0x7C00], dl
|
||||
if use_lba
|
||||
mov ah, 41h
|
||||
mov bx, 55AAh
|
||||
int 13h
|
||||
mov si, aNoLBA
|
||||
jc err_
|
||||
cmp bx, 0AA55h
|
||||
jnz err_
|
||||
test cx, 1
|
||||
jz err_
|
||||
else
|
||||
mov ah, 8
|
||||
int 13h
|
||||
jc @f ; on error, assume that BPB geometry is valid
|
||||
mov al, dh
|
||||
mov ah, 0
|
||||
inc ax
|
||||
mov [bp+BPB_NumHeads-0x7C00], ax
|
||||
and cx, 3Fh
|
||||
mov [bp+BPB_SecPerTrk-0x7C00], cx
|
||||
@@:
|
||||
end if
|
||||
; get FAT parameters
|
||||
xor bx, bx
|
||||
mov al, [bp+BPB_NumFATs-0x7C00]
|
||||
mov ah, 0
|
||||
mul [bp+BPB_FATSz16-0x7C00]
|
||||
add ax, [bp+BPB_RsvdSecCnt-0x7C00]
|
||||
adc dx, bx
|
||||
push dx
|
||||
push ax ; root directory start = dword [bp-4]
|
||||
mov cx, [bp+BPB_RootEntCnt-0x7C00]
|
||||
add cx, 0xF
|
||||
rcr cx, 1
|
||||
shr cx, 3 ; cx = size of root directory in sectors
|
||||
add ax, cx
|
||||
adc dx, bx
|
||||
push dx
|
||||
push ax ; data start = dword [bp-8]
|
||||
; load start of root directory (no more than 0x2000 bytes = 0x10 sectors)
|
||||
cmp cx, 0x10
|
||||
jb @f
|
||||
mov cx, 0x10
|
||||
@@:
|
||||
mov ax, [bp-4]
|
||||
mov dx, [bp-2]
|
||||
push 0x9000
|
||||
pop es
|
||||
call read_sectors
|
||||
add word [bp-4], cx ; dword [bp-4] = start of non-cached root data
|
||||
adc word [bp-2], bx
|
||||
; load kordldr.f12
|
||||
mov si, main_loader
|
||||
call lookup_in_root_dir
|
||||
jc noloader
|
||||
test byte [es:di+11], 10h ; directory?
|
||||
jz kordldr_ok
|
||||
noloader:
|
||||
mov si, aLoaderNotFound
|
||||
err_:
|
||||
call out_string
|
||||
mov si, aPressAnyKey
|
||||
call out_string
|
||||
xor ax, ax
|
||||
int 16h
|
||||
int 18h
|
||||
jmp $
|
||||
kordldr_ok:
|
||||
mov ax, [es:di+26] ; get file cluster
|
||||
mov bx, 0x7E00
|
||||
xor cx, cx
|
||||
mov es, cx
|
||||
sub ax, 2
|
||||
jc noloader
|
||||
push bx ; save return address: bx = 7E00
|
||||
mov cl, [bp+BPB_SecsPerClus-0x7C00]
|
||||
mul cx
|
||||
; fall through - 'ret' in read_sectors will return to 7E00
|
||||
|
||||
read_sectors2:
|
||||
; same as read_sectors, but dx:ax is relative to start of data
|
||||
add ax, [bp-8]
|
||||
adc dx, [bp-6]
|
||||
read_sectors:
|
||||
; ss:bp = 0:7C00
|
||||
; es:bx = pointer to data
|
||||
; dx:ax = first sector
|
||||
; cx = number of sectors
|
||||
pusha
|
||||
add ax, word [bp+BPB_HiddSec-0x7C00]
|
||||
adc dx, word [bp+BPB_HiddSec+2-0x7C00]
|
||||
if use_lba
|
||||
push ds
|
||||
do_read_sectors:
|
||||
push ax
|
||||
push cx
|
||||
push dx
|
||||
cmp cx, 0x7F
|
||||
jbe @f
|
||||
mov cx, 0x7F
|
||||
@@:
|
||||
; create disk address packet on the stack
|
||||
; dq starting LBA
|
||||
push 0
|
||||
push 0
|
||||
push dx
|
||||
push ax
|
||||
; dd buffer
|
||||
push es
|
||||
push bx
|
||||
; dw number of blocks to transfer (no more than 0x7F)
|
||||
push cx
|
||||
; dw packet size in bytes
|
||||
push 10h
|
||||
; issue BIOS call
|
||||
push ss
|
||||
pop ds
|
||||
mov si, sp
|
||||
mov dl, [bp+BS_DrvNum-0x7C00]
|
||||
mov ah, 42h
|
||||
int 13h
|
||||
mov si, aReadError
|
||||
jc err_
|
||||
; restore stack
|
||||
add sp, 10h
|
||||
; increase current sector & buffer; decrease number of sectors
|
||||
mov si, cx
|
||||
mov ax, es
|
||||
shl cx, 5
|
||||
add ax, cx
|
||||
mov es, ax
|
||||
pop dx
|
||||
pop cx
|
||||
pop ax
|
||||
add ax, si
|
||||
adc dx, 0
|
||||
sub cx, si
|
||||
jnz do_read_sectors
|
||||
pop ds
|
||||
popa
|
||||
ret
|
||||
else
|
||||
do_read_sectors:
|
||||
pusha
|
||||
pop di
|
||||
push bx
|
||||
|
||||
; (dword in dx:ax) / (SectorsPerTrack) -> (dword in dx:ax), remainder bx
|
||||
mov si, ax
|
||||
xchg ax, dx
|
||||
xor dx, dx
|
||||
div [bp+BPB_SecPerTrk-0x7C00]
|
||||
push ax
|
||||
mov ax, si
|
||||
div [bp+BPB_SecPerTrk-0x7C00]
|
||||
mov bx, dx ; bx=sector-1
|
||||
pop dx
|
||||
|
||||
; (dword in dx:ax) / (NumHeads) -> (word in ax), remainder dx
|
||||
div [bp+BPB_NumHeads-0x7C00]
|
||||
|
||||
; number of sectors: read no more than to end of track
|
||||
push bx
|
||||
sub bx, [bp+BPB_SecPerTrk-0x7C00]
|
||||
neg bx
|
||||
cmp cx, bx
|
||||
jbe @f
|
||||
mov cx, bx
|
||||
@@:
|
||||
pop bx
|
||||
|
||||
inc bx
|
||||
; now ax=track, dl=head, dh=0, cl=number of sectors, ch=0, bl=sector; convert to int13 format
|
||||
mov di, cx
|
||||
mov dh, dl
|
||||
mov dl, [bp+BS_DrvNum-0x7C00]
|
||||
shl ah, 6
|
||||
mov ch, al
|
||||
mov al, cl
|
||||
mov cl, bl
|
||||
or cl, ah
|
||||
pop bx
|
||||
mov si, 3
|
||||
mov ah, 2
|
||||
@@:
|
||||
push ax
|
||||
int 13h
|
||||
jnc @f
|
||||
xor ax, ax
|
||||
int 13h ; reset drive
|
||||
pop ax
|
||||
dec si
|
||||
jnz @b
|
||||
mov si, aReadError
|
||||
jmp err_
|
||||
@@:
|
||||
pop ax
|
||||
mov ax, es
|
||||
mov cx, di
|
||||
shl cx, 5
|
||||
add ax, cx
|
||||
mov es, ax
|
||||
push di
|
||||
popa
|
||||
add ax, di
|
||||
adc dx, 0
|
||||
sub cx, di
|
||||
jnz do_read_sectors
|
||||
popa
|
||||
ret
|
||||
end if
|
||||
|
||||
scan_for_filename:
|
||||
; in: ds:si -> 11-bytes FAT name
|
||||
; in: es:0 -> part of directory data
|
||||
; in: cx = number of entries
|
||||
; out: if found: CF=0, ZF=1, es:di -> directory entry
|
||||
; out: if not found, but continue required: CF=1 and ZF=0
|
||||
; out: if not found and zero item reached: CF=1 and ZF=1
|
||||
xor di, di
|
||||
push cx
|
||||
sloop:
|
||||
cmp byte [es:di], 0
|
||||
jz snotfound
|
||||
test byte [es:di+11], 8 ; volume label?
|
||||
jnz scont ; ignore volume labels
|
||||
pusha
|
||||
mov cx, 11
|
||||
repz cmpsb
|
||||
popa
|
||||
jz sdone
|
||||
scont:
|
||||
add di, 0x20
|
||||
loop sloop
|
||||
inc cx ; clear ZF flag
|
||||
snotfound:
|
||||
stc
|
||||
sdone:
|
||||
pop cx
|
||||
lrdret:
|
||||
ret
|
||||
|
||||
lookup_in_root_dir:
|
||||
; ss:bp = 0:7C00
|
||||
; in: ds:si -> 11-bytes FAT name
|
||||
; out: if found: CF=0, es:di -> directory entry
|
||||
; out: if not found: CF=1
|
||||
mov cx, [bp+BPB_RootEntCnt-0x7C00]
|
||||
push cx
|
||||
; first, look in root directory cache
|
||||
push 0x9000
|
||||
pop es
|
||||
test ch, ch
|
||||
jz @f
|
||||
mov cx, 0x100
|
||||
@@:
|
||||
mov ax, [bp-4]
|
||||
mov dx, [bp-2] ; dx:ax = starting sector of not cached data of root directory
|
||||
lrdloop:
|
||||
call scan_for_filename
|
||||
pop bx
|
||||
jz lrdret
|
||||
sub bx, cx
|
||||
mov cx, bx
|
||||
stc
|
||||
jz lrdret
|
||||
; read no more than 0x10000 bytes, or 0x10000/0x20 = 0x800 entries
|
||||
push cx
|
||||
cmp ch, 0x8
|
||||
jb @f
|
||||
mov cx, 0x800
|
||||
@@:
|
||||
push 0x8000
|
||||
pop es
|
||||
push cx
|
||||
push es
|
||||
xor bx, bx
|
||||
add cx, 0xF
|
||||
shr cx, 4
|
||||
call read_sectors
|
||||
pop es
|
||||
add ax, cx
|
||||
adc dx, bx
|
||||
pop cx
|
||||
jmp lrdloop
|
||||
|
||||
out_string:
|
||||
; in: ds:si -> ASCIIZ string
|
||||
lodsb
|
||||
test al, al
|
||||
jz lrdret
|
||||
mov ah, 0Eh
|
||||
mov bx, 7
|
||||
int 10h
|
||||
jmp out_string
|
||||
|
||||
aReadError db 'Read error',0
|
||||
if use_lba
|
||||
aNoLBA db 'The drive does not support LBA!',0
|
||||
end if
|
||||
aLoaderNotFound db 'Loader not found',0
|
||||
aPressAnyKey db 13,10,'Press any key...',13,10,0
|
||||
main_loader db 'KORDLDR F1X'
|
||||
|
||||
if use_lba
|
||||
db 0 ; make bootsector 512 bytes in length
|
||||
end if
|
||||
|
||||
; bootsector signature
|
||||
dw 0xAA55
|
||||
|
||||
; display offsets of all procedures used by kordldr.f12.asm
|
||||
macro show [procedure]
|
||||
{
|
||||
bits = 16
|
||||
display `procedure,' = '
|
||||
repeat bits/4
|
||||
d = '0' + procedure shr (bits - %*4) and 0Fh
|
||||
if d > '9'
|
||||
d = d + 'A'-'9'-1
|
||||
end if
|
||||
display d
|
||||
end repeat
|
||||
display 13,10
|
||||
}
|
||||
|
||||
show read_sectors, read_sectors2, lookup_in_root_dir, scan_for_filename, err_, noloader
|
||||
@@ -0,0 +1,360 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
Встречаются вирус и FAT.
|
||||
- Привет, ты кто?
|
||||
- Я? Вирус.
|
||||
- A я AFT, то есть TAF, то есть FTA, черт, совсем запутался...
|
||||
|
||||
Бутсектор для FAT12/FAT16-тома на носителе с размером сектора 0x200 = 512 байт.
|
||||
|
||||
=====================================================================
|
||||
|
||||
Есть две версии в зависимости от того, поддерживает ли носитель LBA,
|
||||
выбор осуществляется установкой константы use_lba в первой строке исходника.
|
||||
Требования для работы:
|
||||
1) Сам бутсектор, первая копия FAT и все используемые файлы
|
||||
должны быть читабельны.
|
||||
2) Минимальный процессор - 80186.
|
||||
3) В системе должно быть как минимум 592K свободной базовой памяти.
|
||||
|
||||
=====================================================================
|
||||
|
||||
Документация в тему (ссылки валидны на момент написания этого файла, 15.05.2008):
|
||||
официальная спецификация FAT: http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
в формате PDF: http://staff.washington.edu/dittrich/misc/fatgen103.pdf
|
||||
русский перевод: http://wasm.ru/docs/11/fatgen103-rus.zip
|
||||
официальная спецификация расширения EDD BIOS 3.0: http://www.phoenix.com/NR/rdonlyres/19FEBD17-DB40-413C-A0B1-1F3F560E222F/0/specsedd30.pdf
|
||||
то же, версия 1.1: http://www.phoenix.com/NR/rdonlyres/9BEDED98-6B3F-4DAC-BBB7-FA89FA5C30F0/0/specsedd11.pdf
|
||||
описание функций BIOS: Interrupt List by Ralf Brown: http://www.cs.cmu.edu/~ralf/files.html
|
||||
официальная спецификация Boot BIOS: http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf
|
||||
|
||||
=====================================================================
|
||||
|
||||
Максимальное количество кластеров на FAT12-томе - 0xFF4 = 4084; каждый кластер
|
||||
занимает 12 бит в таблице FAT, так что общий размер не превосходит
|
||||
0x17EE = 6126 байт. Вся таблица помещается в памяти.
|
||||
Максимальное количество кластеров на FAT16-томе - 0xFFF4 = 65524; каждый
|
||||
кластер занимает 16 бит в таблице FAT, так что общий размер не превосходит
|
||||
0x1FFE8 = 131048 байт. Вся таблица также помещается в памяти, однако в
|
||||
этом случае несколько нецелесообразно считывать всю таблицу, поскольку
|
||||
на практике нужна только небольшая её часть. Поэтому место в памяти
|
||||
резервируется, но данные считываются только в момент, когда к ним
|
||||
действительно идёт обращение.
|
||||
|
||||
Схема используемой памяти:
|
||||
...-7C00 стек
|
||||
7C00-7E00 код бутсектора
|
||||
7E00-8200 вспомогательный файл загрузчика (kordldr.f1x)
|
||||
8200-8300 список загруженных секторов таблицы FAT16
|
||||
(1 = соответствующий сектор загружен)
|
||||
60000-80000 загруженная таблица FAT12 / место для таблицы FAT16
|
||||
80000-90000 текущий кластер текущей рассматриваемой папки
|
||||
90000-92000 кэш для корневой папки
|
||||
92000-... кэш для некорневых папок (каждой папке отводится
|
||||
2000h байт = 100h входов, одновременно в кэше
|
||||
может находиться не более 7 папок;
|
||||
точный размер определяется размером доступной
|
||||
физической памяти - как правило, непосредственно
|
||||
перед A0000 размещается EBDA, Extended BIOS Data Area)
|
||||
|
||||
=====================================================================
|
||||
|
||||
Основной процесс загрузки.
|
||||
Точка входа (start): получает управление от BIOS при загрузке, при этом
|
||||
dl содержит идентификатор диска, с которого идёт загрузка
|
||||
1. Настраивает стек ss:sp = 0:7C00 (стек располагается непосредственно перед
|
||||
кодом), сегмент данных ds = 0, и устанавливает ss:bp на начало
|
||||
бутсектора (в дальнейшем данные будут адресоваться через [bp+N] -
|
||||
это освобождает ds и экономит на размере кода).
|
||||
2. LBA-версия: проверяет, поддерживает ли носитель LBA, вызовом функции 41h
|
||||
прерывания 13h. Если нет, переходит на код обработки ошибок с
|
||||
сообщением об отсутствии LBA.
|
||||
CHS-версия: определяет геометрию носителя вызовом функции 8 прерывания 13h и
|
||||
записывает полученные данные поверх BPB. Если вызов завершился ошибкой,
|
||||
предполагает уже существующие данные корректными.
|
||||
3. Вычисляет некоторые параметры FAT-тома: начальный сектор корневой папки
|
||||
и начальный сектор данных. Кладёт их в стек; впоследствии они
|
||||
всегда будут лежать в стеке и адресоваться через bp.
|
||||
4. Считывает начало корневой папки по адресу 9000:0000. Число считываемых
|
||||
секторов - минимум из размера корневой папки, указанного в BPB, и 16
|
||||
(размер кэша для корневой папки - 2000h байт = 16 секторов).
|
||||
5. Ищет в корневой папке элемент kordldr.f1x. Если не находит, или если
|
||||
он оказывается папкой, или если файл имеет нулевую длину -
|
||||
переходит на код обработки ошибок с сообщением о
|
||||
ненайденном загрузчике.
|
||||
Замечание: на этом этапе загрузки искать можно только в корневой
|
||||
папке и только имена, заданные в формате файловой системе FAT
|
||||
(8+3 - 8 байт на имя, 3 байта на расширение, все буквы должны
|
||||
быть заглавными, при необходимости имя и расширение дополняются
|
||||
пробелами, разделяющей точки нет, завершающего нуля нет).
|
||||
6. Загружает первый кластер файла kordldr.f1x по адресу 0:7E00 и передаёт
|
||||
ему управление. При этом в регистрах dx:ax оказывается абсолютный
|
||||
номер первого сектора kordldr.f1x, а в cx - число считанных секторов
|
||||
(равное размеру кластера).
|
||||
|
||||
Вспомогательные процедуры бутсектора.
|
||||
Код обработки ошибок (err):
|
||||
1. Выводит строку с сообщением об ошибке.
|
||||
2. Выводит строку "Press any key...".
|
||||
3. Ждёт нажатия any key.
|
||||
4. Вызывает int 18h, давая шанс BIOSу попытаться загрузиться откуда-нибудь ещё.
|
||||
5. Для подстраховки зацикливается.
|
||||
|
||||
Процедура чтения секторов (read_sectors и read_sectors2):
|
||||
на входе должно быть установлено:
|
||||
ss:bp = 0:7C00
|
||||
es:bx = указатель на начало буфера, куда будут прочитаны данные
|
||||
dx:ax = стартовый сектор (относительно начала логического диска
|
||||
для read_sectors, относительно начала данных для read_sectors2)
|
||||
cx = число секторов (должно быть больше нуля)
|
||||
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные
|
||||
0. Если вызывается read_sectors2, она переводит указанный ей номер сектора
|
||||
в номер относительно начала логического диска, прибавляя номер сектора
|
||||
начала данных, хранящийся в стеке как [bp-8].
|
||||
1. Переводит стартовый сектор (отсчитываемый от начала тома) в сектор на
|
||||
устройстве, прибавляя значение соответствующего поля из BPB.
|
||||
2. В цикле (шаги 3-6) читает секторы, следит за тем, чтобы на каждой итерации
|
||||
CHS-версия: все читаемые секторы были на одной дорожке.
|
||||
LBA-версия: число читаемых секторов не превосходило 7Fh (требование
|
||||
спецификации EDD BIOS).
|
||||
CHS-версия:
|
||||
3. Переводит абсолютный номер сектора в CHS-систему: сектор рассчитывается как
|
||||
единица плюс остаток от деления абсолютного номера на число секторов
|
||||
на дорожке; дорожка рассчитывается как остаток от деления частного,
|
||||
полученного на предыдущем шаге, на число дорожек, а цилиндр - как
|
||||
частное от этого же деления. Если число секторов для чтения больше,
|
||||
чем число секторов до конца дорожки, уменьшает число секторов для
|
||||
чтения.
|
||||
4. Формирует данные для вызова int 13h (ah=2 - чтение, al=число секторов,
|
||||
dh=головка, (младшие 6 бит cl)=сектор,
|
||||
(старшие 2 бита cl и весь ch)=дорожка, dl=диск, es:bx->буфер).
|
||||
5. Вызывает BIOS. Если BIOS рапортует об ошибке, выполняет сброс диска
|
||||
и повторяет попытку чтения, всего делается не более трёх попыток
|
||||
(несколько попыток нужно в случае дискеты для гарантии того, что
|
||||
мотор раскрутился). Если все три раза происходит ошибка чтения,
|
||||
переходит на код обработки ошибок с сообщением "Read error".
|
||||
6. В соответствии с числом прочитанных на текущей итерации секторов
|
||||
корректирует текущий сектор, число оставшихся секторов и указатель на
|
||||
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
|
||||
работу, иначе возвращается на шаг 3.
|
||||
LBA-версия:
|
||||
3. Если число секторов для чтения больше 7Fh, уменьшает его (для текущей
|
||||
итерации) до 7Fh.
|
||||
4. Формирует в стеке пакет для int 13h (кладёт все нужные данные командами
|
||||
push, причём в обратном порядке: стек - структура LIFO, и данные в
|
||||
стеке хранятся в обратном порядке по отношению к тому, как их туда
|
||||
клали).
|
||||
5. Вызывает BIOS. Если BIOS рапортует об ошибке, переходит на код обработки
|
||||
ошибок с сообщением "Read error". Очищает стек от пакета,
|
||||
сформированного на предыдущем шаге.
|
||||
6. В соответствии с числом прочитанных на текущей итерации секторов
|
||||
корректирует текущий сектор, число оставшихся секторов и указатель на
|
||||
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
|
||||
работу, иначе возвращается на шаг 3.
|
||||
|
||||
Процедура поиска элемента по имени в уже прочитанных данных папки
|
||||
(scan_for_filename):
|
||||
на входе должно быть установлено:
|
||||
ds:si = указатель на имя файла в формате FAT (11 байт, 8 на имя,
|
||||
3 на расширение, все буквы заглавные, если имя/расширение
|
||||
короче, оно дополняется до максимума пробелами)
|
||||
es = сегмент данных папки
|
||||
cx = число элементов в прочитанных данных
|
||||
на выходе: ZF определяет, нужно ли продолжать разбор данных папки
|
||||
(ZF=1, если либо найден запрошенный элемент, либо достигнут
|
||||
конец папки); CF определяет, удалось ли найти элемент с искомым именем
|
||||
(CF=1, если не удалось); если удалось, то es:di указывает на него.
|
||||
scan_for_filename считает, что данные папки размещаются начиная с es:0.
|
||||
Первой командой процедура обнуляет di. Затем просто в цикле по элементам папки
|
||||
проверяет имена.
|
||||
|
||||
Процедура поиска элемента в корневой папке (lookup_in_root_dir):
|
||||
на входе должно быть установлено:
|
||||
ss:bp = 0:7C00
|
||||
ds:si = указатель на имя файла в формате FAT (см. выше)
|
||||
на выходе: флаг CF определяет, удалось ли найти файл; если удалось, то
|
||||
CF сброшен и es:di указывает на элемент папки
|
||||
Начинает с просмотра кэшированной (начальной) части корневой папки. В цикле
|
||||
сканирует элементы; если по результатам сканирования обнаруживает,
|
||||
что нужно читать папку дальше, то считывает не более 0x10000 = 64K
|
||||
байт (ограничение введено по двум причинам: во-первых, чтобы заведомо
|
||||
не вылезти за пределы используемой памяти, во-вторых, сканирование
|
||||
предполагает, что все обрабатываемые элементы располагаются в одном
|
||||
сегменте) и продолжает цикл.
|
||||
Сканирование прекращается в трёх случаях: обнаружен искомый элемент;
|
||||
кончились элементы в папке (судя по числу элементов, указанному в BPB);
|
||||
очередной элемент папки сигнализирует о конце (первый байт нулевой).
|
||||
|
||||
Процедура вывода на экран ASCIIZ-строки (out_string):
|
||||
на входе: ds:si -> строка
|
||||
В цикле, пока не достигнут завершающий ноль, вызывает функцию int 10h/ah=0Eh.
|
||||
|
||||
=====================================================================
|
||||
|
||||
Работа вспомогательного загрузчика kordldr.f1x:
|
||||
1. Определяет, был ли он загружен CHS- или LBA-версией бутсектора.
|
||||
В зависимости от этого устанавливает смещения используемых процедур
|
||||
бутсектора. Критерий проверки: scan_for_filename должна начинаться
|
||||
с инструкции 'xor di,di' с кодом 31 FF (вообще-то эта инструкция может
|
||||
с равным успехом ассемблироваться и как 33 FF, но fasm генерирует
|
||||
именно такую форму).
|
||||
2. Узнаёт размер свободной базовой памяти (т.е. свободного непрерывного куска
|
||||
адресов памяти, начинающегося с 0) вызовом int 12h. В соответствии с
|
||||
ним вычисляет число элементов в кэше папок. Хотя бы для одного элемента
|
||||
место должно быть, отсюда ограничение в 592 Kb (94000h байт).
|
||||
Замечание: этот размер не может превосходить 0A0000h байт и
|
||||
на практике оказывается немного (на 1-2 килобайта) меньшим из-за
|
||||
наличия дополнительной области данных BIOS "вверху" базовой памяти.
|
||||
3. Определяет тип файловой системы: FAT12 или FAT16. Согласно официальной
|
||||
спецификации от Microsoft (версия 1.03 спецификации датирована,
|
||||
к слову, 06 декабря 2000 года), разрядность FAT определяется
|
||||
исключительно числом кластеров: максимальное число кластеров на
|
||||
FAT12-томе равно 4094 = 0xFF4. Согласно здравому смыслу, на FAT12
|
||||
может быть 0xFF5 кластеров, но не больше: кластеры нумеруются с 2,
|
||||
а число 0xFF7 не может быть корректным номером кластера.
|
||||
Win95/98/Me следует здравому смыслу: разграничение FAT12/16 делается
|
||||
по максимуму 0xFF5. Драйвер FAT в WinNT/2k/XP/Vista вообще поступает
|
||||
явно неверно, считая, что 0xFF6 (или меньше) кластеров означает
|
||||
FAT12-том, в результате получается, что последний кластер
|
||||
(в случае 0xFF6) неадресуем. Основной загрузчик osloader.exe
|
||||
[встроен в ntldr] для NT/2k/XP делает так же. Первичный загрузчик
|
||||
[бутсектор FAT12/16 загружает первый сектор ntldr, и разбор FAT-таблицы
|
||||
лежит на нём] в NT/2k подвержен той же ошибке. В XP её таки исправили
|
||||
в соответствии со спецификацией. Linux при определении FAT12/FAT16
|
||||
честно следует спецификации.
|
||||
Здесь код основан всё же на спецификации. 9x мертва, а в линейке NT
|
||||
Microsoft если и будет исправлять ошибки, то согласно собственному
|
||||
описанию.
|
||||
4. Для FAT12: загружает в память первую копию таблицы FAT по адресу 6000:0000.
|
||||
Если размер, указанный в BPB, превосходит 12 секторов,
|
||||
это означает, что заявленный размер слишком большой (это не считается
|
||||
ошибкой файловой системы), и читаются только 12 секторов (таблица FAT12
|
||||
заведомо влезает в такой объём данных).
|
||||
Для FAT16: инициализирует внутренние данные, указывая, что никакой сектор
|
||||
FAT не загружен (они будут подгружаться позднее, когда понадобятся
|
||||
и только те, которые понадобятся).
|
||||
5. Если кластер равен сектору, то бутсектор загрузил только часть файла
|
||||
kordldr.f1x, и загрузчик подгружает вторую свою часть, используя
|
||||
значения регистров на входе в kordldr.f1x.
|
||||
6. Загружает вторичный загрузчик kord/loader по адресу 1000:0000. Если файл не
|
||||
найден, или оказался папкой, или оказался слишком большим, то переходит
|
||||
на код обработки ошибок из бутсектора с сообщением
|
||||
"Fatal error: cannot load the secondary loader".
|
||||
Замечание: на этом этапе имя файла уже можно указывать вместе с путём
|
||||
и в формате ASCIIZ, хотя поддержки длинных имён и неанглийских символов
|
||||
по-прежнему нет.
|
||||
7. Изменяет код обработки ошибок бутсектора на переход на метку hooked_err.
|
||||
Это нужно, чтобы последующие обращения к коду бутсектора в случае
|
||||
ошибок чтения не выводил соответствующее сообщение с последующей
|
||||
перезагрузкой, а рапортовал об ошибке чтения, которую мог бы
|
||||
как-нибудь обработать вторичный загрузчик.
|
||||
8. Если загрузочный диск имеет идентификатор меньше 0x80,
|
||||
то устанавливает al='f' ("floppy"), ah=идентификатор диска,
|
||||
иначе al='h' ("hard"), ah=идентификатор диска-0x80 (номер диска).
|
||||
Устанавливает bx='12', если тип файловой системы - FAT12, и
|
||||
bx='16' в случае FAT16. Устанавливает si=смещение функции обратного
|
||||
вызова. Поскольку в этот момент ds=0, то ds:si образуют полный адрес.
|
||||
9. Передаёт управление по адресу 1000:0000.
|
||||
|
||||
Функция обратного вызова для вторичного загрузчика:
|
||||
предоставляет возможность чтения файла.
|
||||
Вход и выход описаны в спецификации на загрузчик.
|
||||
1. Сохраняет стек вызывающего кода и устанавливает свой стек:
|
||||
ss:sp = 0:(7C00-8), bp=7C00: пара ss:bp при работе с остальным
|
||||
кодом должна указывать на 0:7C00, а -8 берётся от того, что
|
||||
инициализирующий код бутсектора уже поместил в стек 2 двойных слова,
|
||||
и они должны сохраняться в неизменности.
|
||||
2. Разбирает переданные параметры, выясняет, какое действие запрошено,
|
||||
и вызывает нужную вспомогательную процедуру.
|
||||
3. Восстанавливает стек вызывающего кода и возвращает управление.
|
||||
|
||||
Вспомогательные процедуры kordldr.f1x.
|
||||
Процедура получения следующего кластера в FAT (get_next_cluster):
|
||||
1. Вспоминает разрядность FAT, вычисленную ранее.
|
||||
Для FAT12:
|
||||
2. Устанавливает ds = 0x6000 - сегмент, куда ранее была считана
|
||||
вся таблица FAT.
|
||||
3. Подсчитывает si = (кластер) + (кластер)/2 - смещение в этом сегменте
|
||||
слова, задающего следующий кластер. Загружает слово по этому адресу.
|
||||
4. Если кластер имеет нечётный номер, то соответствующий ему элемент
|
||||
располагается в старших 12 битах слова, и слово нужно сдвинуть вправо
|
||||
на 4 бита; в противном случае - в младших 12 битах, и делать ничего не
|
||||
надо.
|
||||
5. Выделяет из получившегося слова 12 бит. Сравнивает их с пределом 0xFF7:
|
||||
номера нормальных кластеров меньше, и флаг CF устанавливается;
|
||||
специальные значения EOF и BadClus сбрасывают флаг CF.
|
||||
Для FAT16:
|
||||
2. Вычисляет адрес памяти, предназначенной для соответствующего сектора данных
|
||||
в таблице FAT.
|
||||
3. Если сектор ещё не загружен, то загружает его.
|
||||
4. Вычисляет смещение данных для конкретного кластера относительно начала
|
||||
сектора.
|
||||
5. Загружает слово в ax из адреса, вычисленному на шагах 1 и 3.
|
||||
6. Сравнивает его с пределом 0xFFF7: номера нормальных кластеров меньше, и флаг
|
||||
CF устанавливается; специальные значения EOF и BadClus сбрасывают CF.
|
||||
|
||||
Процедура загрузки файла (load_file):
|
||||
1. Текущая рассматриваемая папка - корневая. В цикле выполняет шаги 2-4.
|
||||
2. Конвертирует имя текущего рассматриваемого компонента имени (компоненты
|
||||
разделяются символом '/') в FAT-формат 8+3. Если это невозможно
|
||||
(больше 8 символов в имени, больше 3 символов в расширении или
|
||||
больше одной точки), возвращается с ошибкой.
|
||||
3. Ищет элемент с таким именем в текущей рассматриваемой папке. Для корневой
|
||||
папки используется процедура из бутсектора. Для остальных папок:
|
||||
a) Проверяет, есть ли такая папка в кэше некорневых папок.
|
||||
(Идентификация папок осуществляется по номеру начального кластера.)
|
||||
Если такой папки ещё нет, добавляет её в кэш; если тот переполняется,
|
||||
выкидывает папку, к которой дольше всего не было обращений. (Для
|
||||
каждого элемента кэша хранится метка от 0 до (размер кэша)-1,
|
||||
определяющая его номер при сортировке по давности последнего обращения.
|
||||
При обращении к какому-то элементу его метка становится нулевой,
|
||||
а те метки, которые меньше старого значения, увеличиваются на единицу.)
|
||||
б) Просматривает в поисках запрошенного имени все элементы из кэша,
|
||||
используя процедуру из бутсектора. Если обнаруживает искомый элемент,
|
||||
переходит к шагу 4. Если обнаруживает конец папки, возвращается из
|
||||
процедуры с ошибкой.
|
||||
в) В цикле считывает папку посекторно. При этом пропускает начальные
|
||||
секторы, которые уже находятся в кэше и уже были просмотрены. Каждый
|
||||
прочитанный сектор копирует в кэш, если там ещё остаётся место,
|
||||
и просматривает в нём все элементы. Работает, пока не случится одно из
|
||||
трёх событий: найден искомый элемент; кончились кластеры (судя по
|
||||
цепочке кластеров в FAT); очередной элемент папки сигнализирует о конце
|
||||
(первый байт нулевой). В двух последних случаях возвращается с ошибкой.
|
||||
4. Проверяет тип найденного элемента (файл/папка): последний элемент в
|
||||
запрошенном имени должен быть файлом, все промежуточные - папками.
|
||||
Если текущий компонент имени - промежуточный, продвигает текущую
|
||||
рассматриваемую папку и возвращается к пункту 2.
|
||||
5. Проходит по цепочке кластеров в FAT и считывает все кластеры в указанный
|
||||
при вызове буфер последовательными вызовами функции бутсектора;
|
||||
при этом если несколько кластеров файла расположены на диске
|
||||
последовательно, то их чтение объединяется в одну операцию.
|
||||
Следит за тем, чтобы не превысить указанный при вызове процедуры
|
||||
лимит числа секторов для чтения.
|
||||
|
||||
Процедура продолжения загрузки файла (continue_load_file): встроена
|
||||
внутрь шага 5 load_file; загружает в регистры нужные значения (ранее
|
||||
сохранённые из load_file) и продолжает шаг 5.
|
||||
@@ -0,0 +1,3 @@
|
||||
@fasm -m 65535 bootsect.asm bootsect.bin
|
||||
@fasm -m 65535 kordldr.f1x.asm kordldr.f1x
|
||||
@pause
|
||||
@@ -0,0 +1,689 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
org 0x7E00
|
||||
; the KordOS FAT12/FAT16 bootsector loads first cluster of this file to 0:7E00 and transfers control to here
|
||||
; ss:bp = 0:7C00
|
||||
virtual at bp
|
||||
rb 3 ; BS_jmpBoot
|
||||
rb 8 ; BS_OEMName, ignored
|
||||
dw ? ; BPB_BytsPerSec
|
||||
BPB_SecsPerClus db ?
|
||||
BPB_RsvdSecCnt dw ?
|
||||
BPB_NumFATs db ?
|
||||
BPB_RootEntCnt dw ?
|
||||
BPB_TotSec16 dw ?
|
||||
db ? ; BPB_Media
|
||||
BPB_FATSz16 dw ?
|
||||
BPB_SecPerTrk dw ?
|
||||
BPB_NumHeads dw ?
|
||||
BPB_HiddSec dd ?
|
||||
BPB_TotSec32 dd ?
|
||||
BS_DrvNum db ?
|
||||
fat_type db ? ; this is BS_Reserved1,
|
||||
; we use it to save FS type: 0=FAT12, 1=FAT16
|
||||
db ? ; BS_BootSig
|
||||
num_sectors dd ? ; BS_VolID
|
||||
; rb 11 ; BS_VolLab
|
||||
; rb 3 ; BS_FilSysType, first 3 bytes
|
||||
read_sectors dw ?
|
||||
read_sectors2 dw ?
|
||||
lookup_in_root_dir dw ?
|
||||
scan_for_filename dw ?
|
||||
err_ dw ?
|
||||
noloader dw ?
|
||||
cachelimit dw ?
|
||||
filesize: ; will be used to save file size
|
||||
rb 5 ; BS_FilSysType, last 5 bytes
|
||||
; following variables are located in the place of starting code;
|
||||
; starting code is no more used at this point
|
||||
sect_per_clus dw ?
|
||||
cur_cluster dw ?
|
||||
next_cluster dw ?
|
||||
flags dw ?
|
||||
cur_delta dd ?
|
||||
end virtual
|
||||
|
||||
; procedures from boot sector
|
||||
; LBA version
|
||||
lba_read_sectors = 7CE2h
|
||||
lba_read_sectors2 = 7CDCh
|
||||
lba_lookup_in_root_dir = 7D4Fh
|
||||
lba_scan_for_filename = 7D2Dh
|
||||
lba_err = 7CB5h
|
||||
lba_noloader = 7CB2h
|
||||
; CHS version
|
||||
chs_read_sectors = 7CDEh
|
||||
chs_read_sectors2 = 7CD8h
|
||||
chs_lookup_in_root_dir = 7D70h
|
||||
chs_scan_for_filename = 7D4Eh
|
||||
chs_err = 7CB1h
|
||||
chs_noloader = 7CAEh
|
||||
|
||||
push ax cx ; save our position on disk
|
||||
push ss
|
||||
pop es
|
||||
; determine version of bootsector (LBA vs CHS)
|
||||
; mov [read_sectors], chs_read_sectors
|
||||
; mov [read_sectors2], chs_read_sectors2
|
||||
; mov [lookup_in_root_dir], chs_lookup_in_root_dir
|
||||
; mov [scan_for_filename], chs_scan_for_filename
|
||||
; mov [err], chs_err
|
||||
; mov [noloader], chs_noloader
|
||||
lea di, [read_sectors]
|
||||
mov si, chs_proc_addresses
|
||||
mov cx, 6*2
|
||||
cmp word [chs_scan_for_filename], 0xFF31 ; 'xor di,di'
|
||||
jz @f
|
||||
add si, cx
|
||||
; mov [read_sectors], lba_read_sectors
|
||||
; mov [read_sectors2], lba_read_sectors2
|
||||
; mov [lookup_in_root_dir], lba_lookup_in_root_dir
|
||||
; mov [scan_for_filename], lba_scan_for_filename
|
||||
; mov [err], lba_err
|
||||
; mov [noloader], lba_noloader
|
||||
@@:
|
||||
rep movsb
|
||||
mov cl, [BPB_SecsPerClus]
|
||||
mov [sect_per_clus], cx
|
||||
xor bx, bx
|
||||
; determine size of cache for folders
|
||||
int 12h ; ax = size of available base memory in Kb
|
||||
sub ax, 94000h / 1024
|
||||
jae @f
|
||||
nomem:
|
||||
mov si, nomem_str
|
||||
jmp [err_]
|
||||
@@:
|
||||
shr ax, 3
|
||||
mov [cachelimit], ax ; size of cache - 1
|
||||
; get type of file system - FAT12 or FAT16?
|
||||
; calculate number of clusters
|
||||
mov ax, [BPB_TotSec16]
|
||||
xor dx, dx
|
||||
test ax, ax
|
||||
jnz @f
|
||||
mov ax, word [BPB_TotSec32]
|
||||
mov dx, word [BPB_TotSec32+2]
|
||||
@@:
|
||||
sub ax, [bp-8] ; dword [bp-8] = first data sector
|
||||
sbb dx, [bp-6]
|
||||
jb j_noloader
|
||||
div [sect_per_clus]
|
||||
; ax = number of clusters
|
||||
; note: this is loader for FAT12/FAT16, so 'div' does not overflow on correct volumes
|
||||
mov [fat_type], ch
|
||||
cmp ax, 0xFF5
|
||||
jb init_fat12
|
||||
inc [fat_type]
|
||||
init_fat16:
|
||||
; no sectors loaded
|
||||
mov di, 0x8200
|
||||
xor ax, ax
|
||||
mov cx, 0x100/2
|
||||
rep stosw
|
||||
jmp init_fat_done
|
||||
init_fat12:
|
||||
; read FAT
|
||||
push 0x6000
|
||||
pop es
|
||||
mov ax, [BPB_RsvdSecCnt]
|
||||
mov cx, [BPB_FATSz16]
|
||||
cmp cx, 12
|
||||
jb @f
|
||||
mov cx, 12
|
||||
@@:
|
||||
xor dx, dx
|
||||
call [read_sectors]
|
||||
init_fat_done:
|
||||
; if cluster = sector, we need to read second part of our file
|
||||
; (bootsector loads only first cluster of kordldr.f1x)
|
||||
pop cx ax ; restore our position on disk
|
||||
cmp cx, 1
|
||||
ja kordldr_full
|
||||
sub ax, [bp-8]
|
||||
inc ax
|
||||
inc ax ; ax = first cluster of kordldr.f12
|
||||
call get_next_cluster
|
||||
jc @f
|
||||
j_noloader:
|
||||
jmp [noloader]
|
||||
@@:
|
||||
dec ax
|
||||
dec ax
|
||||
push 0x800
|
||||
pop es
|
||||
call [read_sectors2]
|
||||
kordldr_full:
|
||||
; ...continue loading...
|
||||
mov di, secondary_loader_info
|
||||
call load_file
|
||||
test bx, bx
|
||||
mov bx, [err_]
|
||||
jz @f
|
||||
mov si, aKernelNotFound
|
||||
jmp bx
|
||||
@@:
|
||||
; for subsequent calls to callback function, hook error handler
|
||||
; mov byte [bx], 0xE9 ; 'jmp' opcode
|
||||
; mov ax, hooked_err - 3
|
||||
; sub ax, bx
|
||||
; mov word [bx+1], ax
|
||||
; push hooked_err / ret
|
||||
mov word [bx], 0x68 + ((hooked_err and 0xFF) shl 8)
|
||||
mov word [bx+2], (hooked_err shr 8) + (0xC3 shl 8)
|
||||
; set registers for secondary loader
|
||||
mov ah, [BS_DrvNum]
|
||||
mov al, 'f'
|
||||
test ah, ah
|
||||
jns @f
|
||||
sub ah, 80h
|
||||
mov al, 'h'
|
||||
@@:
|
||||
mov bx, '12'
|
||||
cmp [fat_type], 0
|
||||
jz @f
|
||||
mov bh, '6'
|
||||
@@:
|
||||
mov si, callback ; ds:si = far pointer to callback procedure
|
||||
jmp far [si-callback+secondary_loader_info] ; jump to 1000:0000
|
||||
|
||||
nomem_str db 'No memory',0
|
||||
|
||||
chs_proc_addresses:
|
||||
dw chs_read_sectors
|
||||
dw chs_read_sectors2
|
||||
dw chs_lookup_in_root_dir
|
||||
dw chs_scan_for_filename
|
||||
dw chs_err
|
||||
dw chs_noloader
|
||||
lba_proc_addresses:
|
||||
dw lba_read_sectors
|
||||
dw lba_read_sectors2
|
||||
dw lba_lookup_in_root_dir
|
||||
dw lba_scan_for_filename
|
||||
dw lba_err
|
||||
dw lba_noloader
|
||||
|
||||
get_next_cluster:
|
||||
; in: ax = cluster
|
||||
; out: if there is next cluster: CF=1, ax = next cluster
|
||||
; out: if there is no next cluster: CF=0
|
||||
push si
|
||||
cmp [fat_type], 0
|
||||
jnz gnc16
|
||||
; for FAT12
|
||||
push ds
|
||||
push 0x6000
|
||||
pop ds
|
||||
mov si, ax
|
||||
shr si, 1
|
||||
add si, ax
|
||||
test al, 1
|
||||
lodsw
|
||||
jz @f
|
||||
shr ax, 4
|
||||
@@:
|
||||
and ax, 0xFFF
|
||||
cmp ax, 0xFF7
|
||||
pop ds si
|
||||
ret
|
||||
; for FAT16
|
||||
gnc16:
|
||||
; each sector contains 200h bytes = 100h FAT entries
|
||||
; so ah = # of sector, al = offset in sector
|
||||
mov si, ax
|
||||
mov ah, 0
|
||||
shr si, 8
|
||||
; calculate segment for this sector of FAT table
|
||||
; base for FAT table is 6000:0000, so the sector #si has to be loaded to (60000 + 200*si)
|
||||
; segment = 6000 + 20*si, offset = 0
|
||||
push es
|
||||
push si
|
||||
shl si, 5
|
||||
add si, 0x6000
|
||||
mov es, si
|
||||
pop si
|
||||
cmp byte [ss:0x8200+si], ah ; sector already loaded?
|
||||
jnz @f
|
||||
; load corresponding sector
|
||||
pusha
|
||||
push es
|
||||
xor bx, bx
|
||||
mov ax, [BPB_RsvdSecCnt]
|
||||
xor dx, dx
|
||||
add ax, si
|
||||
adc dx, bx
|
||||
mov cx, 1 ; read 1 sector
|
||||
call [read_sectors]
|
||||
pop es
|
||||
popa
|
||||
@@:
|
||||
mov si, ax
|
||||
add si, si
|
||||
; mov ax, [es:si]
|
||||
lods word [es:si]
|
||||
pop es
|
||||
cmp ax, 0xFFF7
|
||||
pop si
|
||||
ret
|
||||
|
||||
if $ > 0x8000
|
||||
error 'get_next_cluster must fit in first sector of kordldr.f1x!'
|
||||
end if
|
||||
|
||||
load_file:
|
||||
; in: ss:bp = 0:7C00
|
||||
; in: ds:di -> information structure
|
||||
; dw:dw address
|
||||
; dw limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
|
||||
; ASCIIZ name
|
||||
; out: bx = status: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=2 - file not found
|
||||
; out: dx:ax = file size (0xFFFFFFFF if file not found)
|
||||
xor ax, ax ; start from root directory
|
||||
mov dx, -1
|
||||
mov word [filesize], dx
|
||||
mov word [filesize+2], dx ; initialize file size with invalid value
|
||||
lea si, [di+6]
|
||||
parse_dir_loop:
|
||||
; convert name to FAT name
|
||||
push di
|
||||
push ax
|
||||
push ss
|
||||
pop es
|
||||
; convert ASCIIZ filename to FAT name
|
||||
mov di, filename
|
||||
push di
|
||||
mov cx, 8+3
|
||||
mov al, ' '
|
||||
rep stosb
|
||||
pop di
|
||||
mov cl, 8 ; 8 symbols per name
|
||||
mov bl, 1
|
||||
nameloop:
|
||||
lodsb
|
||||
test al, al
|
||||
jz namedone
|
||||
cmp al, '/'
|
||||
jz namedone
|
||||
cmp al, '.'
|
||||
jz namedot
|
||||
dec cx
|
||||
js badname
|
||||
cmp al, 'a'
|
||||
jb @f
|
||||
cmp al, 'z'
|
||||
ja @f
|
||||
sub al, 'a'-'A'
|
||||
@@:
|
||||
stosb
|
||||
jmp nameloop
|
||||
namedot:
|
||||
inc bx
|
||||
jp badname
|
||||
add di, cx
|
||||
mov cl, 3
|
||||
jmp nameloop
|
||||
badname: ; do not make direct js/jp to notfound_pop:
|
||||
; this generates long forms of conditional jumps and results in longer code
|
||||
jmp notfound_pop
|
||||
namedone:
|
||||
; scan directory
|
||||
pop ax ; ax = cluster of directory or 0 for root
|
||||
push ds
|
||||
push si
|
||||
push es
|
||||
pop ds
|
||||
mov si, filename ; ds:si -> filename in FAT style
|
||||
test ax, ax
|
||||
jnz lookup_in_notroot_dir
|
||||
; for root directory, use the subroutine from bootsector
|
||||
call [lookup_in_root_dir]
|
||||
jmp lookup_done
|
||||
lookup_in_notroot_dir:
|
||||
; for other directories, read a folder sector-by-sector and scan
|
||||
; first, try to use the cache
|
||||
push ds
|
||||
push cs
|
||||
pop ds
|
||||
mov bx, [cachelimit]
|
||||
add bx, bx
|
||||
mov di, foldcache_mark
|
||||
@@:
|
||||
mov dx, [foldcache_clus+di-foldcache_mark+bx]
|
||||
cmp dx, ax
|
||||
jz cacheok
|
||||
test dx, dx
|
||||
jz cacheadd ; the cache has place for new entry
|
||||
dec bx
|
||||
dec bx
|
||||
jns @b
|
||||
; the folder is not present in the cache, so add it
|
||||
; the cache is full; find the oldest entry and replace it with the new one
|
||||
mov dx, [cachelimit]
|
||||
@@:
|
||||
inc bx
|
||||
inc bx
|
||||
cmp word [di+bx], dx ; marks have values 0 through [cachelimit]
|
||||
jnz @b
|
||||
cacheadd:
|
||||
or word [di+bx], 0xFFFF ; very big value, it will be changed soon
|
||||
mov [foldcache_clus+di-foldcache_mark+bx], ax
|
||||
and [foldcache_size+di-foldcache_mark+bx], 0 ; no folder items yet
|
||||
cacheok:
|
||||
; update cache marks
|
||||
mov dx, [di+bx]
|
||||
mov cx, [foldcache_size+di-foldcache_mark+bx]
|
||||
mov di, [cachelimit]
|
||||
add di, di
|
||||
cacheupdate:
|
||||
cmp [foldcache_mark+di], dx
|
||||
adc [foldcache_mark+di], 0
|
||||
dec di
|
||||
dec di
|
||||
jns cacheupdate
|
||||
and [foldcache_mark+bx], 0
|
||||
; done, bx contains (position in cache)*2
|
||||
pop ds
|
||||
; mov dx, bx
|
||||
; shl dx, 8 ; dx = (position in cache)*0x2000/0x10
|
||||
; add dx, 0x9200
|
||||
lea dx, [bx+0x92]
|
||||
xchg dl, dh
|
||||
mov es, dx
|
||||
jcxz not_in_cache
|
||||
call [scan_for_filename]
|
||||
jz lookup_done
|
||||
not_in_cache:
|
||||
; cache miss, read folder data from disk
|
||||
mov bx, cx
|
||||
shr bx, 4
|
||||
shl cx, 5
|
||||
mov di, cx ; es:di -> free space in cache entry
|
||||
; external loop: scan clusters
|
||||
folder_next_cluster:
|
||||
; internal loop: scan sectors in cluster
|
||||
mov cx, [sect_per_clus]
|
||||
push ax
|
||||
dec ax
|
||||
dec ax
|
||||
mul cx
|
||||
add ax, [bp-8]
|
||||
adc dx, [bp-6] ; dx:ax = absolute sector
|
||||
folder_next_sector:
|
||||
; skip first bx sectors
|
||||
dec bx
|
||||
jns folder_skip_sector
|
||||
push cx
|
||||
push es di
|
||||
push 0x8000
|
||||
pop es
|
||||
xor bx, bx
|
||||
mov cx, 1
|
||||
push es
|
||||
call [read_sectors]
|
||||
; copy data to the cache...
|
||||
pop ds
|
||||
pop di es
|
||||
cmp di, 0x2000 ; ...if there is free space, of course
|
||||
jae @f
|
||||
push si di
|
||||
mov cx, 0x100
|
||||
xor si, si
|
||||
rep movsw
|
||||
mov di, es
|
||||
shr di, 8
|
||||
add [ss:foldcache_size+di-0x92], 0x10 ; 0x10 new entries in the cache
|
||||
pop di si
|
||||
@@:
|
||||
push es
|
||||
push 0x8000
|
||||
pop es
|
||||
push cs
|
||||
pop ds
|
||||
mov cx, 0x10
|
||||
call [scan_for_filename]
|
||||
pop es
|
||||
pop cx
|
||||
jz lookup_done_pop
|
||||
folder_skip_sector:
|
||||
inc ax
|
||||
jnz @f
|
||||
inc dx
|
||||
@@:
|
||||
loop folder_next_sector
|
||||
pop ax ; ax = current cluster
|
||||
call get_next_cluster
|
||||
jc folder_next_cluster
|
||||
stc
|
||||
push ax
|
||||
lookup_done_pop:
|
||||
pop ax
|
||||
lookup_done:
|
||||
pop si
|
||||
pop ds
|
||||
; CF=1 <=> failed
|
||||
jnc found
|
||||
notfound:
|
||||
pop di
|
||||
mov bx, 2 ; file not found
|
||||
mov ax, 0xFFFF
|
||||
mov dx, ax ; invalid file size
|
||||
ret
|
||||
notfound_pop:
|
||||
pop ax
|
||||
jmp notfound
|
||||
found:
|
||||
mov ax, [es:di+26] ; get cluster
|
||||
test byte [es:di+11], 10h ; directory?
|
||||
jz regular_file
|
||||
cmp byte [si-1], 0
|
||||
jz notfound ; don't read directories as a regular files
|
||||
; ok, we have found a directory and the caller requested a file into it
|
||||
pop di
|
||||
jmp parse_dir_loop ; restart with new cluster in ax
|
||||
regular_file:
|
||||
cmp byte [si-1], 0
|
||||
jnz notfound ; file does not contain another files
|
||||
; ok, we have found a regular file and the caller requested it
|
||||
; save file size
|
||||
mov dx, [es:di+28]
|
||||
mov [filesize], dx
|
||||
mov dx, [es:di+30]
|
||||
mov [filesize+2], dx
|
||||
pop di
|
||||
mov si, [di+4]
|
||||
shl si, 3
|
||||
push si ; [ds:di+4] = limit in 4K blocks
|
||||
les bx, [di] ; es:bx -> buffer
|
||||
clusloop:
|
||||
; ax = first cluster, top of stack contains limit in sectors
|
||||
mov si, ax ; remember current cluster
|
||||
xor cx, cx ; cx will contain number of consecutive clusters
|
||||
mov word [cur_delta], cx
|
||||
mov word [cur_delta+2], cx
|
||||
mov di, ax
|
||||
clusfind:
|
||||
inc di
|
||||
inc cx
|
||||
call get_next_cluster
|
||||
jnc clusread
|
||||
cmp ax, di
|
||||
jz clusfind
|
||||
stc
|
||||
clusread:
|
||||
pop di ; limit in sectors
|
||||
push ax ; save next cluster
|
||||
pushf ; save flags
|
||||
; read cx clusters, starting from si
|
||||
; calculate number of sectors
|
||||
xchg ax, cx
|
||||
mul [sect_per_clus]
|
||||
; dx:ax = number of sectors; compare with limit
|
||||
mov word [num_sectors], ax
|
||||
mov word [num_sectors+2], dx
|
||||
jmp @f
|
||||
continue_load_file:
|
||||
les bx, [di] ; es:bx -> buffer
|
||||
mov di, [di+4] ; ds:di = limit in 4K blocks
|
||||
shl di, 3 ; now di = limit in sectors
|
||||
mov ax, word [num_sectors]
|
||||
mov dx, word [num_sectors+2]
|
||||
mov si, [cur_cluster]
|
||||
push [next_cluster]
|
||||
push [flags]
|
||||
or ax, dx
|
||||
jz nextclus
|
||||
@@:
|
||||
test dx, dx
|
||||
jnz clusdecrease
|
||||
push dx ; limit was not exceeded
|
||||
cmp ax, di
|
||||
jbe @f
|
||||
pop ax
|
||||
clusdecrease:
|
||||
push 1 ; limit was exceeded
|
||||
mov ax, di
|
||||
@@:
|
||||
sub di, ax ; calculate new limit
|
||||
sub word [num_sectors], ax
|
||||
sbb word [num_sectors+2], 0
|
||||
readloop:
|
||||
push ax
|
||||
; buffer should not cross a 64K boundary
|
||||
push bx
|
||||
shr bx, 4
|
||||
mov cx, es
|
||||
add bx, cx
|
||||
neg bx
|
||||
and bh, 0xF
|
||||
shr bx, 5
|
||||
jnz @f
|
||||
mov bl, 0x80
|
||||
@@:
|
||||
cmp ax, bx
|
||||
jbe @f
|
||||
xchg ax, bx
|
||||
@@:
|
||||
pop bx
|
||||
xchg ax, cx
|
||||
; calculate starting sector
|
||||
lea ax, [si-2]
|
||||
mul [sect_per_clus]
|
||||
add ax, word [cur_delta]
|
||||
adc dx, word [cur_delta+2]
|
||||
add word [cur_delta], cx
|
||||
adc word [cur_delta+2], 0
|
||||
; read
|
||||
call [read_sectors2]
|
||||
pop ax
|
||||
sub ax, cx
|
||||
jnz readloop
|
||||
pop dx
|
||||
; next cluster?
|
||||
nextclus:
|
||||
popf
|
||||
pop ax
|
||||
mov [cur_cluster], si
|
||||
mov [next_cluster], ax
|
||||
pushf
|
||||
pop [flags]
|
||||
jnc @f ; no next cluster => return
|
||||
mov dl, 1 ; dh=0 in any case
|
||||
test di, di
|
||||
jz @f ; if there is next cluster but current limit is 0 => return: limit exceeded
|
||||
push di
|
||||
jmp clusloop ; all is ok, continue
|
||||
hooked_err:
|
||||
mov sp, 7C00h-12-2 ; restore stack
|
||||
mov dx, 3 ; return: read error
|
||||
@@:
|
||||
mov bx, dx
|
||||
mov ax, [filesize]
|
||||
mov dx, [filesize+2]
|
||||
ret
|
||||
|
||||
; Callback function for secondary loader
|
||||
callback:
|
||||
; in: ax = function number; only functions 1 and 2 are defined for now
|
||||
; save caller's stack
|
||||
mov dx, ss
|
||||
mov cx, sp
|
||||
; set our stack (required because we need ss=0)
|
||||
xor si, si
|
||||
mov ss, si
|
||||
mov sp, 7C00h-8
|
||||
mov bp, 7C00h
|
||||
push dx
|
||||
push cx
|
||||
; call our function
|
||||
stc ; unsupported function
|
||||
dec ax
|
||||
jz callback_readfile
|
||||
dec ax
|
||||
jnz callback_ret
|
||||
; function 2: continue loading file
|
||||
; can be called only after function 1 returned value bx=1 (only part of file was loaded)
|
||||
; in: ds:di -> information structure
|
||||
; dw:dw address
|
||||
; dw limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
|
||||
; out: bx=0 - ok, bx=1 - still only part of file was loaded, bx=3 - read error
|
||||
; out: dx:ax = file size
|
||||
call continue_load_file
|
||||
jmp callback_ret_succ
|
||||
callback_readfile:
|
||||
; function 1: read file
|
||||
; in: ds:di -> information structure
|
||||
; dw:dw address
|
||||
; dw limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
|
||||
; ASCIIZ name
|
||||
; out: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=2 - file not found, bx=3 - read error
|
||||
; out: dx:ax = file size (0xFFFFFFFF if file was not found)
|
||||
call load_file
|
||||
callback_ret_succ:
|
||||
clc ; function is supported
|
||||
callback_ret:
|
||||
; restore caller's stack
|
||||
pop cx
|
||||
pop ss
|
||||
mov sp, cx
|
||||
; return to caller
|
||||
retf
|
||||
|
||||
secondary_loader_info:
|
||||
dw 0, 0x1000
|
||||
dw 0x30000 / 0x1000
|
||||
db 'kernel.mnt',0
|
||||
aKernelNotFound db 'Fatal error: cannot load the kernel',0
|
||||
|
||||
foldcache_clus dw 0,0,0,0,0,0,0 ; start with no folders in cache
|
||||
foldcache_mark rw 7
|
||||
foldcache_size rw 7
|
||||
filename rb 11
|
||||
if $ > 0x8200
|
||||
error:
|
||||
table overwritten
|
||||
end if
|
||||
@@ -0,0 +1,3 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("bootsect.asm", "fasm %f %o", "bootsect.bin")
|
||||
tup.rule("kordldr.f32.asm", "fasm %f %o", "kordldr.f32")
|
||||
@@ -0,0 +1,358 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
use_lba = 1
|
||||
org 0x7C00
|
||||
jmp start
|
||||
nop
|
||||
; FAT parameters, BPB
|
||||
; they must be changed at install, replaced with real values
|
||||
rb 8 ; BS_OEMName, ignored
|
||||
dw 200h ; BPB_BytsPerSec
|
||||
BPB_SecsPerClus db ?
|
||||
BPB_RsvdSecCnt dw ?
|
||||
BPB_NumFATs db ?
|
||||
BPB_RootEntCnt dw ?
|
||||
dw ? ; BPB_TotSec16
|
||||
db ? ; BPB_Media
|
||||
dw ? ; BPB_FATSz16 = 0 for FAT32
|
||||
BPB_SecPerTrk dw ?
|
||||
BPB_NumHeads dw ?
|
||||
BPB_HiddSec dd ?
|
||||
dd ? ; BPB_TotSec32
|
||||
BPB_FATSz32 dd ?
|
||||
BPB_ExtFlags dw ?
|
||||
dw ? ; BPB_FSVer
|
||||
BPB_RootClus dd ?
|
||||
dw ? ; BPB_FSInfo
|
||||
BPB_BkBootSec dw ?
|
||||
rb 12 ; BPB_Reserved
|
||||
BS_DrvNum db ?
|
||||
db ? ; BS_Reserved1
|
||||
db ? ; BS_BootSig
|
||||
dd ? ; BS_VolID
|
||||
rb 11 ; BS_VolLab
|
||||
rb 8 ;
|
||||
|
||||
curseg dw 0x8000
|
||||
|
||||
start:
|
||||
xor ax, ax
|
||||
mov ss, ax
|
||||
mov sp, 0x7C00
|
||||
mov ds, ax
|
||||
mov bp, sp
|
||||
cld
|
||||
sti
|
||||
push dx ; byte [bp-2] = boot drive
|
||||
if use_lba
|
||||
mov ah, 41h
|
||||
mov bx, 55AAh
|
||||
int 13h
|
||||
mov si, aNoLBA
|
||||
jc err_
|
||||
cmp bx, 0AA55h
|
||||
jnz err_
|
||||
test cl, 1
|
||||
jz err_
|
||||
else
|
||||
mov ah, 8
|
||||
int 13h
|
||||
jc @f
|
||||
movzx ax, dh
|
||||
inc ax
|
||||
mov [bp+BPB_NumHeads-0x7C00], ax
|
||||
and cx, 3Fh
|
||||
mov [bp+BPB_SecPerTrk-0x7C00], cx
|
||||
@@:
|
||||
end if
|
||||
; get FAT parameters
|
||||
xor bx, bx
|
||||
movzx eax, [bp+BPB_NumFATs-0x7C00]
|
||||
mul [bp+BPB_FATSz32-0x7C00]
|
||||
movzx ecx, [bp+BPB_RsvdSecCnt-0x7C00]
|
||||
push ecx ; FAT start = dword [bp-6]
|
||||
add eax, ecx
|
||||
push eax ; data start = dword [bp-10]
|
||||
;push dword -1 ; dword [bp-14] = current sector for FAT cache
|
||||
db 66h
|
||||
push -1 ; dword [bp-14] = current sector for FAT cache
|
||||
mov eax, [bp+BPB_RootClus-0x7C00]
|
||||
mov si, main_loader
|
||||
call lookup_in_dir
|
||||
jnc kordldr_ok
|
||||
noloader:
|
||||
mov si, aLoaderNotFound
|
||||
err_:
|
||||
call out_string
|
||||
mov si, aPressAnyKey
|
||||
call out_string
|
||||
xor ax, ax
|
||||
int 16h
|
||||
int 18h
|
||||
jmp $
|
||||
kordldr_ok:
|
||||
mov eax, [es:di+20-2] ; hiword(eax) = hiword(cluster)
|
||||
mov ax, [es:di+26] ; loword(eax) = loword(cluster)
|
||||
mov es, bx ; es = 0
|
||||
mov bx, 0x7E00
|
||||
push bx ; save return address: bx = 7E00
|
||||
; fall through - 'ret' in read_cluster will return to 7E00
|
||||
|
||||
read_cluster:
|
||||
; ss:bp = 0:7C00
|
||||
; es:bx = pointer to data
|
||||
; eax = cluster
|
||||
sub eax, 2
|
||||
movzx ecx, [bp+BPB_SecsPerClus-0x7C00]
|
||||
mul ecx
|
||||
|
||||
read_sectors2:
|
||||
; same as read_sectors32, but eax is relative to start of data
|
||||
add eax, [bp-10]
|
||||
read_sectors32:
|
||||
; ss:bp = 0:7C00
|
||||
; es:bx = pointer to data
|
||||
; eax = first sector
|
||||
; cx = number of sectors
|
||||
; some high words of 32-bit registers are destroyed!
|
||||
pusha
|
||||
add eax, [bp+BPB_HiddSec-0x7C00]
|
||||
if use_lba
|
||||
push ds
|
||||
do_read_sectors:
|
||||
push ax
|
||||
push cx
|
||||
cmp cx, 0x7F
|
||||
jbe @f
|
||||
mov cx, 0x7F
|
||||
@@:
|
||||
; create disk address packet on the stack
|
||||
; dq starting LBA
|
||||
push 0
|
||||
push 0
|
||||
push eax
|
||||
; dd buffer
|
||||
push es
|
||||
push bx
|
||||
; dw number of blocks to transfer (no more than 0x7F)
|
||||
push cx
|
||||
; dw packet size in bytes
|
||||
push 10h
|
||||
; issue BIOS call
|
||||
push ss
|
||||
pop ds
|
||||
mov si, sp
|
||||
mov dl, [bp-2]
|
||||
mov ah, 42h
|
||||
int 13h
|
||||
mov si, aReadError
|
||||
jc err_
|
||||
; restore stack
|
||||
add sp, 10h
|
||||
; increase current sector & buffer; decrease number of sectors
|
||||
movzx esi, cx
|
||||
mov ax, es
|
||||
shl cx, 5
|
||||
add ax, cx
|
||||
mov es, ax
|
||||
pop cx
|
||||
pop ax
|
||||
add eax, esi
|
||||
sub cx, si
|
||||
jnz do_read_sectors
|
||||
pop ds
|
||||
popa
|
||||
ret
|
||||
else
|
||||
do_read_sectors:
|
||||
pusha
|
||||
pop edi ; loword(edi) = di, hiword(edi) = si
|
||||
push bx
|
||||
|
||||
; eax / (SectorsPerTrack) -> eax, remainder bx
|
||||
movzx esi, [bp+BPB_SecPerTrk-0x7C00]
|
||||
xor edx, edx
|
||||
div esi
|
||||
mov bx, dx ; bx=sector-1
|
||||
|
||||
; eax -> dx:ax
|
||||
push eax
|
||||
pop ax
|
||||
pop dx
|
||||
; (dword in dx:ax) / (NumHeads) -> (word in ax), remainder dx
|
||||
div [bp+BPB_NumHeads-0x7C00]
|
||||
|
||||
; number of sectors: read no more than to end of track
|
||||
sub si, bx
|
||||
cmp cx, si
|
||||
jbe @f
|
||||
mov cx, si
|
||||
@@:
|
||||
|
||||
inc bx
|
||||
; now ax=track, dl=head, dh=0, cl=number of sectors, ch=0, bl=sector; convert to int13 format
|
||||
movzx edi, cx
|
||||
mov dh, dl
|
||||
mov dl, [bp-2]
|
||||
shl ah, 6
|
||||
mov ch, al
|
||||
mov al, cl
|
||||
mov cl, bl
|
||||
or cl, ah
|
||||
pop bx
|
||||
mov si, 3
|
||||
mov ah, 2
|
||||
@@:
|
||||
push ax
|
||||
int 13h
|
||||
jnc @f
|
||||
xor ax, ax
|
||||
int 13h ; reset drive
|
||||
pop ax
|
||||
dec si
|
||||
jnz @b
|
||||
mov si, aReadError
|
||||
jmp err_
|
||||
@@:
|
||||
pop ax
|
||||
mov ax, es
|
||||
mov cx, di
|
||||
shl cx, 5
|
||||
add ax, cx
|
||||
mov es, ax
|
||||
push edi
|
||||
popa
|
||||
add eax, edi
|
||||
sub cx, di
|
||||
jnz do_read_sectors
|
||||
popa
|
||||
ret
|
||||
end if
|
||||
|
||||
lookup_in_dir:
|
||||
; in: ds:si -> 11-bytes FAT name
|
||||
; in: eax = cluster
|
||||
; in: bx = 0
|
||||
; out: if found: CF=0, es:di -> directory entry
|
||||
; out: if not found: CF=1
|
||||
; push 0x8000
|
||||
; pop es
|
||||
; read current cluster: first cluster goes to 8000:0000, others - to 8200:0000
|
||||
mov es, [bp-7C00h + curseg]
|
||||
push es
|
||||
push eax
|
||||
call read_cluster
|
||||
mov ax, es
|
||||
cmp ah, 82h
|
||||
jb @f
|
||||
mov ax, 8200h
|
||||
@@:
|
||||
mov [bp-7C00h + curseg], ax
|
||||
pop eax
|
||||
pop es
|
||||
; scan for filename
|
||||
shl cx, 4
|
||||
xor di, di
|
||||
sloop:
|
||||
cmp byte [es:di], bl
|
||||
jz snotfound
|
||||
test byte [es:di+11], 8 ; volume label?
|
||||
jnz scont ; ignore volume labels
|
||||
pusha
|
||||
mov cx, 11
|
||||
repz cmpsb
|
||||
popa
|
||||
jz sdone
|
||||
scont:
|
||||
add di, 0x20
|
||||
loop sloop
|
||||
; next cluster
|
||||
push 0x6000
|
||||
pop es
|
||||
push es ax
|
||||
shr eax, 7
|
||||
cmp eax, [bp-14]
|
||||
mov [bp-14], eax
|
||||
jz @f
|
||||
add eax, [bp-6]
|
||||
mov cx, 1
|
||||
call read_sectors32
|
||||
@@:
|
||||
pop di es
|
||||
and di, 0x7F
|
||||
shl di, 2
|
||||
and byte [es:di+3], 0x0F
|
||||
mov eax, [es:di]
|
||||
;and eax, 0x0FFFFFFF
|
||||
cmp eax, 0x0FFFFFF7
|
||||
jb lookup_in_dir
|
||||
snotfound:
|
||||
stc
|
||||
sdone:
|
||||
ret
|
||||
|
||||
out_string:
|
||||
; in: ds:si -> ASCIIZ string
|
||||
lodsb
|
||||
test al, al
|
||||
jz sdone
|
||||
mov ah, 0Eh
|
||||
mov bx, 7
|
||||
int 10h
|
||||
jmp out_string
|
||||
|
||||
aReadError db 'Read error',0
|
||||
if use_lba
|
||||
aNoLBA db 'The drive does not support LBA!',0
|
||||
end if
|
||||
aLoaderNotFound db 'Loader not found',0
|
||||
aPressAnyKey db 13,10,'Press any key...',13,10,0
|
||||
main_loader db 'KORDLDR F32'
|
||||
|
||||
db 56h
|
||||
; just to make file 512 bytes long :)
|
||||
db 'd' xor 'i' xor 'a' xor 'm' xor 'o' xor 'n' xor 'd'
|
||||
|
||||
; bootsector signature
|
||||
dw 0xAA55
|
||||
|
||||
; display offsets of all procedures used by kordldr.f12.asm
|
||||
macro show [procedure]
|
||||
{
|
||||
bits = 16
|
||||
display `procedure,' = '
|
||||
repeat bits/4
|
||||
d = '0' + procedure shr (bits - %*4) and 0Fh
|
||||
if d > '9'
|
||||
d = d + 'A'-'9'-1
|
||||
end if
|
||||
display d
|
||||
end repeat
|
||||
display 13,10
|
||||
}
|
||||
|
||||
show read_sectors32, read_sectors2, err_, noloader
|
||||
@@ -0,0 +1,333 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
Читай между строк - там никогда не бывает опечаток.
|
||||
|
||||
Бутсектор для FAT32-тома на носителе с размером сектора 0x200 = 512 байт.
|
||||
|
||||
=====================================================================
|
||||
|
||||
Есть две версии в зависимости от того, поддерживает ли носитель LBA,
|
||||
выбор осуществляется установкой константы use_lba в первой строке исходника.
|
||||
Требования для работы:
|
||||
1) Сам бутсектор, первая копия FAT и все используемые файлы
|
||||
должны быть читабельны. (Если дело происходит на носителе с разбиением на
|
||||
разделы и загрузочный код в MBR достаточно умный, то читабельности резервной
|
||||
копии бутсектора (сектор номер 6 на томе) достаточно вместо читабельности
|
||||
самого бутсектора).
|
||||
2) Минимальный процессор - 80386.
|
||||
3) В системе должно быть как минимум 584K свободной базовой памяти.
|
||||
|
||||
=====================================================================
|
||||
|
||||
Документация в тему (ссылки проверялись на валидность 15.05.2008):
|
||||
официальная спецификация FAT: http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
|
||||
в формате PDF: http://staff.washington.edu/dittrich/misc/fatgen103.pdf
|
||||
русский перевод: http://wasm.ru/docs/11/fatgen103-rus.zip
|
||||
официальная спецификация расширения EDD BIOS 3.0: http://www.phoenix.com/NR/rdonlyres/19FEBD17-DB40-413C-A0B1-1F3F560E222F/0/specsedd30.pdf
|
||||
то же, версия 1.1: http://www.phoenix.com/NR/rdonlyres/9BEDED98-6B3F-4DAC-BBB7-FA89FA5C30F0/0/specsedd11.pdf
|
||||
описание функций BIOS: Interrupt List by Ralf Brown: http://www.cs.cmu.edu/~ralf/files.html
|
||||
официальная спецификация Boot BIOS: http://www.phoenix.com/NR/rdonlyres/56E38DE2-3E6F-4743-835F-B4A53726ABED/0/specsbbs101.pdf
|
||||
|
||||
=====================================================================
|
||||
|
||||
Схема используемой памяти:
|
||||
...-7C00 стек
|
||||
7C00-7E00 код бутсектора
|
||||
7E00-8200 вспомогательный файл загрузчика (kordldr.f32)
|
||||
8400-8C00 информация о кэше для таблицы FAT: 100h входов по 8
|
||||
байт: 4 байта (две ссылки - вперёд и назад) для
|
||||
организации L2-списка всех прочитанных секторов в
|
||||
порядке возрастания последнего времени использования
|
||||
+ 4 байта для номера сектора; при переполнении кэша
|
||||
выкидывается элемент из головы списка, то есть тот,
|
||||
к которому дольше всех не было обращений
|
||||
60000-80000 кэш для таблицы FAT (100h секторов)
|
||||
80000-90000 текущий кластер текущей рассматриваемой папки
|
||||
90000-... кэш для содержимого папок (каждой папке отводится
|
||||
2000h байт = 100h входов, одновременно в кэше
|
||||
может находиться не более 8 папок;
|
||||
точный размер определяется размером доступной
|
||||
физической памяти - как правило, непосредственно
|
||||
перед A0000 размещается EBDA, Extended BIOS Data Area)
|
||||
|
||||
=====================================================================
|
||||
|
||||
Основной процесс загрузки.
|
||||
Точка входа (start): получает управление от BIOS при загрузке, при этом
|
||||
dl содержит идентификатор диска, с которого идёт загрузка
|
||||
1. Настраивает стек ss:sp = 0:7C00 (стек располагается непосредственно перед
|
||||
кодом), сегмент данных ds = 0, и устанавливает ss:bp на начало
|
||||
бутсектора (в дальнейшем данные будут адресоваться через [bp+N] -
|
||||
это освобождает ds и экономит на размере кода). Сохраняет в стеке
|
||||
идентификатор загрузочного диска для последующего обращения
|
||||
через byte [bp-2].
|
||||
2. LBA-версия: проверяет, поддерживает ли носитель LBA, вызовом функции 41h
|
||||
прерывания 13h. Если нет, переходит на код обработки ошибок с
|
||||
сообщением об отсутствии LBA.
|
||||
CHS-версия: определяет геометрию носителя вызовом функции 8 прерывания 13h и
|
||||
записывает полученные данные поверх BPB. Если вызов завершился ошибкой,
|
||||
предполагает уже существующие данные корректными.
|
||||
3. Вычисляет начало данных FAT-тома, сохраняет его в стек для последующего
|
||||
обращения через dword [bp-10]. В процессе вычисления узнаёт начало
|
||||
первой FAT, сохраняет и его в стек для последующего обращения через
|
||||
dword [bp-6].
|
||||
4. (Заканчивая тему параметров в стеке) Помещает в стек dword-значение -1
|
||||
для последующего обращения через dword [bp-14] - инициализация
|
||||
переменной, содержащей текущий сектор, находящийся в кэше FAT
|
||||
(-1 не является валидным значением для номера сектора FAT).
|
||||
5. Ищет в корневой папке элемент kordldr.f32. Если не находит - переходит на
|
||||
код обработки ошибок с сообщением о ненайденном загрузчике.
|
||||
Замечание: на этом этапе загрузки искать можно только в корневой
|
||||
папке и только имена, заданные в формате файловой системе FAT
|
||||
(8+3 - 8 байт на имя, 3 байта на расширение, все буквы должны
|
||||
быть заглавными, при необходимости имя и расширение дополняются
|
||||
пробелами, разделяющей точки нет, завершающего нуля нет).
|
||||
6. Загружает первый кластер файла kordldr.f32 по адресу 0:7E00 и передаёт
|
||||
ему управление. При этом в регистре eax оказывается абсолютный
|
||||
номер первого сектора kordldr.f32, а в cx - число считанных секторов
|
||||
(равное размеру кластера).
|
||||
|
||||
Вспомогательные процедуры бутсектора.
|
||||
Код обработки ошибок (err):
|
||||
1. Выводит строку с сообщением об ошибке.
|
||||
2. Выводит строку "Press any key...".
|
||||
3. Ждёт нажатия any key.
|
||||
4. Вызывает int 18h, давая шанс BIOSу попытаться загрузиться откуда-нибудь ещё.
|
||||
5. Для подстраховки зацикливается.
|
||||
|
||||
Процедура чтения кластера (read_cluster):
|
||||
на входе должно быть установлено:
|
||||
ss:bp = 0:7C00
|
||||
es:bx = указатель на начало буфера, куда будут прочитаны данные
|
||||
eax = номер кластера
|
||||
на выходе: ecx = число прочитанных секторов (размер кластера),
|
||||
es:bx указывает на конец буфера, в который были прочитаны данные,
|
||||
eax и старшие слова других 32-битных регистров разрушаются
|
||||
Загружает в ecx размер кластера, перекодирует номер кластера в номер сектора
|
||||
и переходит к следующей процедуре.
|
||||
|
||||
Процедура чтения секторов (read_sectors32 и read_sectors2):
|
||||
на входе должно быть установлено:
|
||||
ss:bp = 0:7C00
|
||||
es:bx = указатель на начало буфера, куда будут прочитаны данные
|
||||
eax = стартовый сектор (относительно начала логического диска
|
||||
для read_sectors32, относительно начала данных
|
||||
для read_sectors2)
|
||||
cx = число секторов (должно быть больше нуля)
|
||||
на выходе: es:bx указывает на конец буфера, в который были прочитаны данные
|
||||
старшие слова 32-битных регистров могут разрушиться
|
||||
0. Если вызывается read_sectors2, она переводит указанный ей номер сектора
|
||||
в номер относительно начала логического диска, прибавляя номер сектора
|
||||
начала данных, хранящийся в стеке как [bp-10].
|
||||
1. Переводит стартовый сектор (отсчитываемый от начала тома) в сектор на
|
||||
устройстве, прибавляя значение соответствующего поля из BPB.
|
||||
2. В цикле (шаги 3-6) читает секторы, следит за тем, чтобы на каждой итерации
|
||||
CHS-версия: все читаемые секторы были на одной дорожке.
|
||||
LBA-версия: число читаемых секторов не превосходило 7Fh (требование
|
||||
спецификации EDD BIOS).
|
||||
CHS-версия:
|
||||
3. Переводит абсолютный номер сектора в CHS-систему: сектор рассчитывается как
|
||||
единица плюс остаток от деления абсолютного номера на число секторов
|
||||
на дорожке; дорожка рассчитывается как остаток от деления частного,
|
||||
полученного на предыдущем шаге, на число дорожек, а цилиндр - как
|
||||
частное от этого же деления. Если число секторов для чтения больше,
|
||||
чем число секторов до конца дорожки, уменьшает число секторов для
|
||||
чтения.
|
||||
4. Формирует данные для вызова int 13h (ah=2 - чтение, al=число секторов,
|
||||
dh=головка, (младшие 6 бит cl)=сектор,
|
||||
(старшие 2 бита cl и весь ch)=дорожка, dl=диск, es:bx->буфер).
|
||||
5. Вызывает BIOS. Если BIOS рапортует об ошибке, выполняет сброс диска
|
||||
и повторяет попытку чтения, всего делается не более трёх попыток
|
||||
(несколько попыток нужно в случае дискеты для гарантии того, что
|
||||
мотор раскрутился). Если все три раза происходит ошибка чтения,
|
||||
переходит на код обработки ошибок с сообщением "Read error".
|
||||
6. В соответствии с числом прочитанных на текущей итерации секторов
|
||||
корректирует текущий сектор, число оставшихся секторов и указатель на
|
||||
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
|
||||
работу, иначе возвращается на шаг 3.
|
||||
LBA-версия:
|
||||
3. Если число секторов для чтения больше 7Fh, уменьшает его (для текущей
|
||||
итерации) до 7Fh.
|
||||
4. Формирует в стеке пакет для int 13h (кладёт все нужные данные командами
|
||||
push, причём в обратном порядке: стек - структура LIFO, и данные в
|
||||
стеке хранятся в обратном порядке по отношению к тому, как их туда
|
||||
клали).
|
||||
5. Вызывает BIOS. Если BIOS рапортует об ошибке, переходит на код обработки
|
||||
ошибок с сообщением "Read error". Очищает стек от пакета,
|
||||
сформированного на предыдущем шаге.
|
||||
6. В соответствии с числом прочитанных на текущей итерации секторов
|
||||
корректирует текущий сектор, число оставшихся секторов и указатель на
|
||||
буфер (в паре es:bx корректируется es). Если всё прочитано, заканчивает
|
||||
работу, иначе возвращается на шаг 3.
|
||||
|
||||
Процедура поиска элемента в папке (lookup_in_dir):
|
||||
на входе должно быть установлено:
|
||||
ss:bp = 0:7C00
|
||||
ds:si = указатель на имя файла в формате FAT (см. выше)
|
||||
eax = начальный кластер папки
|
||||
bx = 0
|
||||
на выходе: флаг CF определяет, удалось ли найти файл; если удалось, то
|
||||
CF сброшен и es:di указывает на элемент папки
|
||||
В цикле считывает кластеры папки и ищет запрошенный элемент в прочитанных
|
||||
данных. Для чтения кластера использует уже описанную процедуру read_clusters,
|
||||
для продвижения по цепочке кластеров - описанную далее процедуру
|
||||
get_next_clusters. Данные читаются в область памяти, начинающуюся с адреса
|
||||
8000:0000, при этом первые 2000h байт из данных папки (может быть, меньше,
|
||||
если чтение прервётся раньше) не перекрываются последующими чтениями
|
||||
(это будет использовано позднее, в системе кэширования из kordldr.f32).
|
||||
Выход осуществляется в любом из следующих случаев: найден запрошенный элемент;
|
||||
кончились элементы в папке (первый байт очередного элемента нулевой);
|
||||
кончились данные папки в соответствии с цепочкой кластеров из FAT.
|
||||
|
||||
Процедура вывода на экран ASCIIZ-строки (out_string):
|
||||
на входе: ds:si -> строка
|
||||
В цикле, пока не достигнут завершающий ноль, вызывает функцию int 10h/ah=0Eh.
|
||||
|
||||
=====================================================================
|
||||
|
||||
Работа вспомогательного загрузчика kordldr.f32:
|
||||
1. Определяет, был ли он загружен CHS- или LBA-версией бутсектора.
|
||||
В зависимости от этого устанавливает смещения используемых процедур
|
||||
бутсектора. Критерий проверки: в CHS-версии по адресу err находится
|
||||
байт 0xE8 (машинная команда call), в LBA-версии по тому же адресу
|
||||
находится байт 0x14, а адрес процедуры err другой.
|
||||
2. Узнаёт размер свободной базовой памяти (т.е. свободного непрерывного куска
|
||||
адресов памяти, начинающегося с 0) вызовом int 12h. В соответствии с
|
||||
ним вычисляет число элементов в кэше папок. Хотя бы для одного элемента
|
||||
место должно быть, отсюда ограничение в 592 Kb (94000h байт).
|
||||
Замечание: этот размер не может превосходить 0A0000h байт и
|
||||
на практике оказывается немного (на 1-2 килобайта) меньшим из-за
|
||||
наличия дополнительной области данных BIOS "вверху" базовой памяти.
|
||||
3. Инициализирует кэширование папок. Бутсектор уже загрузил какую-то часть
|
||||
данных корневой папки; копирует загруженные данные в кэш и запоминает,
|
||||
что в кэше есть корневая папка.
|
||||
4. Инициализирует кэширование FAT. Бутсектор имеет дело с FAT в том и только
|
||||
том случае, когда ему приходится загружать данные корневой папки,
|
||||
не поместившиеся в один кластер. В этом случае в памяти присутствует
|
||||
один сектор FAT (если было несколько обращений - последний из
|
||||
использованных).
|
||||
5. Если кластер равен сектору, то бутсектор загрузил только часть файла
|
||||
kordldr.f32, и загрузчик подгружает вторую свою часть, используя
|
||||
значения регистров на входе в kordldr.f32.
|
||||
6. Загружает вторичный загрузчик kord/loader по адресу 1000:0000. Если файл не
|
||||
найден, или оказался папкой, или оказался слишком большим, то переходит
|
||||
на код обработки ошибок из бутсектора с сообщением
|
||||
"Fatal error: cannot load the secondary loader".
|
||||
Замечание: на этом этапе имя файла уже можно указывать вместе с путём
|
||||
и в формате ASCIIZ, хотя поддержки длинных имён и неанглийских символов
|
||||
по-прежнему нет.
|
||||
7. Изменяет код обработки ошибок бутсектора на переход на метку hooked_err.
|
||||
Это нужно, чтобы последующие обращения к коду бутсектора в случае
|
||||
ошибок чтения не выводил соответствующее сообщение с последующей
|
||||
перезагрузкой, а рапортовал об ошибке чтения, которую могло бы
|
||||
как-нибудь обработать ядро.
|
||||
8. Если загрузочный диск имеет идентификатор меньше 0x80,
|
||||
то устанавливает al='f' ("floppy"), ah=идентификатор диска,
|
||||
иначе al='h' ("hard"), ah=идентификатор диска-0x80 (номер диска).
|
||||
(Говорите, дискеток с FAT32 не бывает? В чём-то Вы правы... но
|
||||
уверены ли Вы, что нет загрузочных устройств, подобных дискетам,
|
||||
но большего размера, и для которых BIOS-идентификатор меньше 0x80?)
|
||||
Устанавливает bx='32' (тип файловой системы - FAT32).
|
||||
Устанавливает si=смещение функции обратного вызова. Поскольку в этот
|
||||
момент ds=0, то ds:si образуют полный адрес.
|
||||
9. Передаёт управление по адресу 1000:0000.
|
||||
|
||||
Функция обратного вызова для вторичного загрузчика:
|
||||
предоставляет возможность чтения файла.
|
||||
Вход и выход описаны в спецификации на загрузчик.
|
||||
1. Сохраняет стек вызывающего кода и устанавливает свой стек:
|
||||
ss:sp = 0:(7C00-10), bp=7C00: пара ss:bp при работе с остальным
|
||||
кодом должна указывать на 0:7C00, а -10 берётся от того, что
|
||||
инициализирующий код бутсектора уже поместил в стек 10 байт параметров,
|
||||
и они должны сохраняться в неизменности. (Значение [ebp-14],
|
||||
"текущий сектор, находящийся в кэше FAT", не используется после
|
||||
инициализации кэширования в kordldr.f32.)
|
||||
2. Разбирает переданные параметры и вызывает нужную из вспомогательных
|
||||
процедур (загрузки файла либо продолжения загрузки файла).
|
||||
3. Восстанавливает стек вызывающего кода и возвращает управление.
|
||||
|
||||
Вспомогательные процедуры kordldr.f32.
|
||||
Процедура получения следующего кластера в FAT (get_next_cluster):
|
||||
1. Вычисляет номер сектора в FAT, в котором находится запрошенный элемент.
|
||||
(В секторе 0x200 байт, каждый вход занимает 4 байта.)
|
||||
2. Проверяет, есть ли сектор в кэше. Если есть, пропускает шаги 3 и 4.
|
||||
3. Если нет, то в кэш нужно вставить новый элемент. Если кэш ещё не заполнен,
|
||||
выделяет очередной элемент в конце кэша. Если заполнен, удаляет
|
||||
самый старый элемент (тот, к которому дольше всего не было обращений);
|
||||
для того, чтобы отслеживать порядок элементов по времени последнего
|
||||
обращения, все (выделенные) элементы кэша связаны в двусвязный список,
|
||||
в котором первым элементом является самый старый, а ссылки вперёд
|
||||
указывают на следующий по времени последнего обращения.
|
||||
4. Читает соответствующий сектор FAT с диска.
|
||||
5. Корректирует список: текущий обрабатываемый элемент удаляется с той позиции,
|
||||
где он находится, и добавляется в конец. (В случае со свежедобавленными
|
||||
в кэш элементами удаления не делается, поскольку их в списке ещё нет.)
|
||||
6. Считывает нужный вход в FAT, сбрасывая старшие 4 бита.
|
||||
7. Сравнивает прочитанное значение с пределом: если оно строго меньше
|
||||
0x0FFFFFF7, то оно задаёт номер следующего кластера в цепочке;
|
||||
в противном случае цепочка закончилась.
|
||||
|
||||
Процедура загрузки файла (load_file):
|
||||
1. Текущая рассматриваемая папка - корневая. В цикле выполняет шаги 2-4.
|
||||
2. Конвертирует имя текущего рассматриваемого компонента имени (компоненты
|
||||
разделяются символом '/') в FAT-формат 8+3. Если это невозможно
|
||||
(больше 8 символов в имени, больше 3 символов в расширении или
|
||||
больше одной точки), возвращается с ошибкой.
|
||||
3. Ищет элемент с таким именем в текущей рассматриваемой папке.
|
||||
а) Проверяет, есть ли такая папка в кэше папок. (Идентификация папок
|
||||
осуществляется по номеру начального кластера.) Если такой папки ещё
|
||||
нет, добавляет её в кэш; если тот переполняется, выкидывает папку,
|
||||
к которой дольше всего не было обращений. (Для каждого элемента кэша
|
||||
хранится метка от 0 до (размер кэша)-1, определяющая его номер при
|
||||
сортировке по давности последнего обращения. При обращении к какому-то
|
||||
элементу его метка становится нулевой, а те метки, которые меньше
|
||||
старого значения, увеличиваются на единицу.)
|
||||
б) Просматривает в поисках запрошенного имени все элементы из кэша,
|
||||
используя процедуру из бутсектора. Если обнаруживает искомый элемент,
|
||||
переходит к шагу 4. Если обнаруживает конец папки, возвращается из
|
||||
процедуры с ошибкой.
|
||||
в) В цикле считывает папку посекторно. При этом пропускает начальные
|
||||
секторы, которые уже находятся в кэше и уже были просмотрены. Каждый
|
||||
прочитанный сектор копирует в кэш, если там ещё остаётся место,
|
||||
и просматривает в нём все элементы. Работает, пока не случится одно из
|
||||
трёх событий: найден искомый элемент; кончились кластеры (судя по
|
||||
цепочке кластеров в FAT); очередной элемент папки сигнализирует о конце
|
||||
(первый байт нулевой). В двух последних случаях возвращается с ошибкой.
|
||||
4. Проверяет тип найденного элемента (файл/папка): последний элемент в
|
||||
запрошенном имени должен быть файлом, все промежуточные - папками.
|
||||
Если текущий компонент имени - промежуточный, продвигает текущую
|
||||
рассматриваемую папку и возвращается к пункту 2.
|
||||
5. Проходит по цепочке кластеров в FAT и считывает все кластеры в указанный
|
||||
при вызове буфер последовательными вызовами функции бутсектора;
|
||||
при этом если несколько кластеров файла расположены на диске
|
||||
последовательно, то их чтение объединяется в одну операцию.
|
||||
Следит за тем, чтобы не превысить указанный при вызове процедуры
|
||||
лимит числа секторов для чтения.
|
||||
|
||||
Процедура продолжения загрузки файла (continue_load_file): встроена
|
||||
внутрь шага 5 load_file; загружает в регистры нужные значения (ранее
|
||||
сохранённые из load_file) и продолжает шаг 5.
|
||||
@@ -0,0 +1,3 @@
|
||||
@fasm -m 65535 bootsect.asm bootsect.bin
|
||||
@fasm -m 65535 kordldr.f32.asm kordldr.f32
|
||||
@pause
|
||||
@@ -0,0 +1,673 @@
|
||||
; Copyright (c) 2008-2009, diamond
|
||||
; All rights reserved.
|
||||
;
|
||||
; Redistribution and use in source and binary forms, with or without
|
||||
; modification, are permitted provided that the following conditions are met:
|
||||
; * Redistributions of source code must retain the above copyright
|
||||
; notice, this list of conditions and the following disclaimer.
|
||||
; * Redistributions in binary form must reproduce the above copyright
|
||||
; notice, this list of conditions and the following disclaimer in the
|
||||
; documentation and/or other materials provided with the distribution.
|
||||
; * Neither the name of the <organization> nor the
|
||||
; names of its contributors may be used to endorse or promote products
|
||||
; derived from this software without specific prior written permission.
|
||||
;
|
||||
; THIS SOFTWARE IS PROVIDED BY Alexey Teplov aka <Lrz> ''AS IS'' AND ANY
|
||||
; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
; DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
|
||||
; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
; (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
; ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
;*****************************************************************************
|
||||
|
||||
org 0x7E00
|
||||
; the KordOS FAT32 bootsector loads first cluster of this file to 0:7E00 and transfers control to here
|
||||
; ss:bp = 0:7C00
|
||||
; ds = 0
|
||||
virtual at bp
|
||||
rb 3 ; BS_jmpBoot
|
||||
rb 8 ; BS_OEMName, ignored
|
||||
dw ? ; BPB_BytsPerSec
|
||||
BPB_SecsPerClus db ?
|
||||
BPB_RsvdSecCnt dw ?
|
||||
BPB_NumFATs db ?
|
||||
BPB_RootEntCnt dw ?
|
||||
dw ? ; BPB_TotSec16
|
||||
db ? ; BPB_Media
|
||||
dw ? ; BPB_FATSz16 = 0 for FAT32
|
||||
BPB_SecPerTrk dw ?
|
||||
BPB_NumHeads dw ?
|
||||
BPB_HiddSec dd ?
|
||||
dd ? ; BPB_TotSec32
|
||||
BPB_FATSz32 dd ?
|
||||
BPB_ExtFlags dw ?
|
||||
dw ? ; BPB_FSVer
|
||||
BPB_RootClus dd ?
|
||||
filesize:
|
||||
dw ? ; BPB_FSInfo
|
||||
dw ? ; BPB_BkBootSec
|
||||
rb 12 ; BPB_Reserved
|
||||
BS_DrvNum db ?
|
||||
db ? ; BS_Reserved1
|
||||
db ? ; BS_BootSig
|
||||
dd ? ; BS_VolID
|
||||
; rb 11 ; BS_VolLab
|
||||
; rb 5 ; BS_FilSysType, first 5 bytes
|
||||
read_sectors32 dw ?
|
||||
read_sectors2 dw ?
|
||||
err_ dw ?
|
||||
noloader dw ?
|
||||
cachelimit dw ?
|
||||
fatcachehead rw 2
|
||||
fatcacheend dw ?
|
||||
rb 3 ; BS_FilSysType, last 3 bytes
|
||||
curseg dw ?
|
||||
num_sectors dd ?
|
||||
cur_cluster dd ?
|
||||
next_cluster dd ?
|
||||
flags dw ?
|
||||
cur_delta dd ?
|
||||
end virtual
|
||||
|
||||
; procedures from boot sector
|
||||
; LBA version
|
||||
lba_read_sectors2 = 7CD6h
|
||||
lba_err = 7CAAh
|
||||
lba_noloader = 7CA7h ; = lba_err - 3
|
||||
; CHS version
|
||||
chs_read_sectors2 = 7CD2h
|
||||
chs_err = 7CA6h
|
||||
chs_noloader = 7CA3h ; = chs_err - 3
|
||||
|
||||
push eax cx ; save our position on disk
|
||||
; determine version of bootsector (LBA vs CHS)
|
||||
mov [read_sectors2], chs_read_sectors2
|
||||
mov bx, chs_err
|
||||
mov [err_], bx
|
||||
; mov [noloader], chs_noloader
|
||||
cmp byte [bx], 0xE8 ; [chs_err] = 0xE8 for CHS version, 0x14 for LBA version
|
||||
jz @f
|
||||
add [read_sectors2], lba_read_sectors2 - chs_read_sectors2
|
||||
add [err_], lba_err - chs_err
|
||||
; mov [noloader], lba_noloader
|
||||
@@:
|
||||
xor bx, bx
|
||||
; determine size of cache for folders
|
||||
int 12h ; ax = size of available base memory in Kb
|
||||
sub ax, 92000h / 1024
|
||||
jae @f
|
||||
nomem:
|
||||
mov si, nomem_str
|
||||
jmp [err_]
|
||||
@@:
|
||||
shr ax, 3
|
||||
mov [cachelimit], ax ; size of cache - 1
|
||||
mov es, bx
|
||||
; no folders in cache yet
|
||||
mov di, foldcache_clus
|
||||
mov cx, 8*4/2 + 1
|
||||
xor ax, ax
|
||||
rep stosw
|
||||
; bootsector code caches one FAT sector, [bp-14], in 6000:0000
|
||||
; initialize our (more advanced) FAT caching from this
|
||||
mov di, 8400h
|
||||
mov cx, di
|
||||
lea si, [fatcachehead]
|
||||
mov [si], si ; no sectors in cache:
|
||||
mov [si+2], si ; 'prev' & 'next' links point to self
|
||||
mov [fatcacheend], di ; first free item = 8400h
|
||||
stosw ; 'next cached sector' link
|
||||
stosw ; 'prev cached sector' link
|
||||
mov eax, [bp-14]
|
||||
stosd ; first sector number in cache
|
||||
test eax, eax
|
||||
js @f
|
||||
mov [si], cx ; 'first cached sector' link = 8400h
|
||||
mov [si+2], cx ; 'next cached sector' link = 8400h
|
||||
mov [fatcacheend], di ; first free item = 8406h
|
||||
@@:
|
||||
; if cluster = sector, we need to read second part of our file
|
||||
; (bootsector loads only first cluster of kordldr.f32)
|
||||
pop cx eax ; restore our position on disk
|
||||
cmp cx, 1
|
||||
ja kordldr_full
|
||||
sub eax, [bp-10]
|
||||
inc eax
|
||||
inc eax ; eax = first cluster of kordldr.f32
|
||||
call get_next_cluster
|
||||
jc @f
|
||||
; jmp [noloader]
|
||||
mov ax, [err_]
|
||||
sub ax, 3
|
||||
jmp ax
|
||||
@@:
|
||||
dec eax
|
||||
dec eax
|
||||
push 0x800
|
||||
pop es
|
||||
call [read_sectors2]
|
||||
kordldr_full:
|
||||
; bootsector code has read some data of root directory to 8000:0000
|
||||
; initialize our folder caching from this
|
||||
mov eax, [BPB_RootClus]
|
||||
mov [foldcache_clus], eax
|
||||
mov cx, [curseg]
|
||||
mov ax, 8000h
|
||||
sub cx, ax ; cx = size of data read in paragraphs (0x10 bytes)
|
||||
shr cx, 1 ; cx = size of folder data read in entries (0x20 bytes)
|
||||
mov [foldcache_size], cx
|
||||
shl cx, 4
|
||||
push ds
|
||||
mov ds, ax
|
||||
push 0x9000
|
||||
pop es
|
||||
xor si, si
|
||||
xor di, di
|
||||
rep movsw
|
||||
pop ds
|
||||
; ...continue loading...
|
||||
mov di, secondary_loader_info
|
||||
call load_file
|
||||
test bx, bx
|
||||
mov bx, [err_]
|
||||
jz @f
|
||||
mov si, aKernelNotFound
|
||||
jmp bx
|
||||
@@:
|
||||
; for subsequent calls to callback function, hook error handler
|
||||
; push hooked_err / ret
|
||||
mov dword [bx], 0x68 + (hooked_err shl 8) + (0xC3 shl 24)
|
||||
; set registers for secondary loader
|
||||
mov ah, [bp-2] ; drive id
|
||||
mov al, 'f'
|
||||
btr ax, 15
|
||||
jnc @f
|
||||
mov al, 'h'
|
||||
@@:
|
||||
mov bx, '32'
|
||||
mov si, callback
|
||||
jmp far [si+secondary_loader_info-callback]
|
||||
|
||||
nomem_str db 'No memory',0
|
||||
|
||||
cluster2sector:
|
||||
sub eax, 2
|
||||
clustersz2sectorsz:
|
||||
movzx ecx, [BPB_SecsPerClus]
|
||||
mul ecx
|
||||
ret
|
||||
|
||||
get_next_cluster:
|
||||
; in: eax = cluster
|
||||
; out: if there is next cluster: CF=1, eax = next cluster
|
||||
; out: if there is no next cluster: CF=0
|
||||
push di bx
|
||||
push ds es
|
||||
push ss
|
||||
pop ds
|
||||
push ss
|
||||
pop es
|
||||
push ax
|
||||
shr eax, 7
|
||||
; eax = FAT sector number; look in cache
|
||||
mov di, 8400h
|
||||
.cache_lookup:
|
||||
cmp di, [fatcacheend]
|
||||
jae .not_in_cache
|
||||
scasd
|
||||
scasd
|
||||
jnz .cache_lookup
|
||||
.in_cache:
|
||||
sub di, 8
|
||||
; delete this sector from the list
|
||||
push si
|
||||
mov si, [di]
|
||||
mov bx, [di+2]
|
||||
mov [si+2], bx
|
||||
mov [bx], si
|
||||
pop si
|
||||
jmp @f
|
||||
.not_in_cache:
|
||||
; cache miss
|
||||
; cache is full?
|
||||
mov di, [fatcacheend]
|
||||
cmp di, 8C00h
|
||||
jnz .cache_not_full
|
||||
; yes, delete the oldest entry
|
||||
mov di, [fatcachehead]
|
||||
mov bx, [di]
|
||||
mov [fatcachehead], bx
|
||||
push word [di+2]
|
||||
pop word [bx+2]
|
||||
jmp .cache_append
|
||||
.cache_not_full:
|
||||
; no, allocate new sector
|
||||
add [fatcacheend], 8
|
||||
.cache_append:
|
||||
; read FAT
|
||||
mov [di+4], eax
|
||||
pushad
|
||||
lea cx, [di + 0x10000 - 0x8400 + (0x6000 shr (9-4-3))] ; +0x10000 - for FASM
|
||||
shl cx, 9-4-3
|
||||
mov es, cx
|
||||
xor bx, bx
|
||||
mov cx, 1
|
||||
add eax, [bp-6] ; FAT start
|
||||
sub eax, [bp-10]
|
||||
call [read_sectors2]
|
||||
popad
|
||||
@@:
|
||||
; add new sector to the end of list
|
||||
mov bx, di
|
||||
xchg bx, [fatcachehead+2]
|
||||
push word [bx]
|
||||
pop word [di]
|
||||
mov [bx], di
|
||||
mov [di+2], bx
|
||||
; get requested item
|
||||
lea ax, [di + 0x10000 - 0x8400 + (0x6000 shr (9-4-3))]
|
||||
pop di
|
||||
and di, 0x7F
|
||||
shl di, 2
|
||||
shl ax, 9-4-3
|
||||
mov ds, ax
|
||||
and byte [di+3], 0x0F
|
||||
mov eax, [di]
|
||||
pop es ds
|
||||
pop bx di
|
||||
;and eax, 0x0FFFFFFF
|
||||
cmp eax, 0x0FFFFFF7
|
||||
ret
|
||||
|
||||
if $ > 0x8000
|
||||
error 'get_next_cluster must fit in first sector of kordldr.f32!'
|
||||
end if
|
||||
|
||||
load_file:
|
||||
; in: ss:bp = 0:7C00
|
||||
; in: ds:di -> information structure
|
||||
; dw:dw address
|
||||
; dw limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
|
||||
; ASCIIZ name
|
||||
; out: bx = status: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=2 - file not found
|
||||
; out: dx:ax = file size (0xFFFFFFFF if file not found)
|
||||
mov eax, [BPB_RootClus] ; start from root directory
|
||||
or dword [filesize], -1 ; initialize file size with invalid value
|
||||
lea si, [di+6]
|
||||
parse_dir_loop:
|
||||
; convert name to FAT name
|
||||
push di
|
||||
push ax
|
||||
push ss
|
||||
pop es
|
||||
; convert ASCIIZ filename to FAT name
|
||||
filename equ bp
|
||||
mov di, filename
|
||||
push di
|
||||
mov cx, 8+3
|
||||
mov al, ' '
|
||||
rep stosb
|
||||
pop di
|
||||
mov cl, 8 ; 8 symbols per name
|
||||
mov bl, 1
|
||||
nameloop:
|
||||
lodsb
|
||||
test al, al
|
||||
jz namedone
|
||||
cmp al, '/'
|
||||
jz namedone
|
||||
cmp al, '.'
|
||||
jz namedot
|
||||
dec cx
|
||||
js badname
|
||||
cmp al, 'a'
|
||||
jb @f
|
||||
cmp al, 'z'
|
||||
ja @f
|
||||
sub al, 'a'-'A'
|
||||
@@:
|
||||
stosb
|
||||
jmp nameloop
|
||||
namedot:
|
||||
inc bx
|
||||
jp badname
|
||||
add di, cx
|
||||
mov cl, 3
|
||||
jmp nameloop
|
||||
badname: ; do not make direct js/jp to notfound_pop:
|
||||
; this generates long forms of conditional jumps and results in longer code
|
||||
jmp notfound_pop
|
||||
namedone:
|
||||
; scan directory
|
||||
pop ax ; eax = cluster of directory
|
||||
; high word of eax is preserved by operations above
|
||||
push ds
|
||||
push si
|
||||
; read a folder sector-by-sector and scan
|
||||
; first, try to use the cache
|
||||
push ss
|
||||
pop ds
|
||||
mov di, foldcache_mark
|
||||
xor bx, bx
|
||||
mov cx, [cachelimit]
|
||||
@@:
|
||||
lea si, [di+bx]
|
||||
mov edx, dword [foldcache_clus+si-foldcache_mark+bx]
|
||||
cmp edx, eax
|
||||
jz cacheok
|
||||
test edx, edx
|
||||
jz cacheadd ; the cache has place for new entry
|
||||
inc bx
|
||||
inc bx
|
||||
dec cx
|
||||
jns @b
|
||||
; the folder is not present in the cache, so add it
|
||||
; the cache is full; find the oldest entry and replace it with the new one
|
||||
mov bx, -2
|
||||
mov dx, [cachelimit]
|
||||
@@:
|
||||
inc bx
|
||||
inc bx
|
||||
cmp word [di+bx], dx ; marks have values 0 through [cachelimit]
|
||||
jnz @b
|
||||
lea si, [di+bx]
|
||||
cacheadd:
|
||||
or word [di+bx], 0xFFFF ; very big value, it will be changed soon
|
||||
and [foldcache_size+di-foldcache_mark+bx], 0 ; no folder items yet
|
||||
mov dword [foldcache_clus+si-foldcache_mark+bx], eax
|
||||
cacheok:
|
||||
; update cache marks
|
||||
mov dx, [di+bx]
|
||||
mov cx, [foldcache_size+di-foldcache_mark+bx]
|
||||
mov di, [cachelimit]
|
||||
add di, di
|
||||
cacheupdate:
|
||||
cmp [foldcache_mark+di], dx
|
||||
adc [foldcache_mark+di], 0
|
||||
dec di
|
||||
dec di
|
||||
jns cacheupdate
|
||||
and [foldcache_mark+bx], 0
|
||||
; done, bx contains (position in cache)*2
|
||||
;mov dx, bx
|
||||
;shl dx, 8 ; dx = (position in cache)*0x2000/0x10
|
||||
;add dx, 0x9000
|
||||
lea dx, [bx + 0x90]
|
||||
xchg dl, dh
|
||||
mov ds, dx
|
||||
mov si, filename ; ss:si -> filename in FAT style
|
||||
call scan_for_filename
|
||||
jz lookup_done
|
||||
; cache miss, read folder data from disk
|
||||
mov bx, cx
|
||||
shr bx, 4
|
||||
shl cx, 5
|
||||
mov di, cx ; es:di -> free space in cache entry
|
||||
; external loop: scan clusters
|
||||
folder_next_cluster:
|
||||
; internal loop: scan sectors in cluster
|
||||
push eax
|
||||
call cluster2sector
|
||||
folder_next_sector:
|
||||
; skip first bx sectors
|
||||
dec bx
|
||||
jns folder_skip_sector
|
||||
push cx
|
||||
push es di
|
||||
push 0x8000
|
||||
pop es
|
||||
xor bx, bx
|
||||
mov cx, 1
|
||||
push es
|
||||
push eax
|
||||
call [read_sectors2]
|
||||
pop eax
|
||||
; copy data to the cache...
|
||||
pop ds
|
||||
pop di es
|
||||
cmp di, 0x2000 ; ...if there is free space, of course
|
||||
jae @f
|
||||
pusha
|
||||
mov cx, 0x100
|
||||
xor si, si
|
||||
rep movsw
|
||||
mov di, es
|
||||
shr di, 8
|
||||
add [ss:foldcache_size+di-0x90], 0x10 ; 0x10 new entries in the cache
|
||||
popa
|
||||
@@:
|
||||
push es
|
||||
mov cl, 0x10 ; ch=0 at this point
|
||||
call scan_for_filename
|
||||
pop es
|
||||
pop cx
|
||||
jz lookup_done_pop
|
||||
folder_skip_sector:
|
||||
inc eax
|
||||
loop folder_next_sector
|
||||
pop eax ; eax = current cluster
|
||||
call get_next_cluster
|
||||
jc folder_next_cluster
|
||||
stc
|
||||
push eax
|
||||
lookup_done_pop:
|
||||
pop eax
|
||||
lookup_done:
|
||||
pop si
|
||||
; CF=1 <=> failed
|
||||
jnc found
|
||||
pop ds
|
||||
notfound:
|
||||
pop di
|
||||
notfound2:
|
||||
mov bx, 2 ; file not found
|
||||
mov ax, 0xFFFF
|
||||
mov dx, ax ; invalid file size
|
||||
ret
|
||||
notfound_pop:
|
||||
pop ax
|
||||
jmp notfound
|
||||
found:
|
||||
mov eax, [di+20-2]
|
||||
mov edx, [di+28]
|
||||
mov ax, [di+26] ; get cluster
|
||||
test byte [di+11], 10h ; directory?
|
||||
pop ds
|
||||
pop di
|
||||
jz regular_file
|
||||
cmp byte [si-1], 0
|
||||
jz notfound2 ; don't read directories as regular files
|
||||
; ok, we have found a directory and the caller requested a file into it
|
||||
jmp parse_dir_loop ; restart with new cluster in ax
|
||||
regular_file:
|
||||
cmp byte [si-1], 0
|
||||
jnz notfound2 ; file does not contain another files
|
||||
; ok, we have found a regular file and the caller requested it
|
||||
; save file size
|
||||
mov [filesize], edx
|
||||
mov si, [di+4] ; [ds:di+4] = limit in 4K blocks
|
||||
shl si, 3
|
||||
push si
|
||||
les bx, [di] ; es:bx -> buffer
|
||||
clusloop:
|
||||
; eax = first cluster, top of stack contains limit in sectors
|
||||
mov esi, eax ; remember current cluster
|
||||
xor ecx, ecx ; ecx will contain number of consecutive clusters
|
||||
mov [cur_delta], ecx
|
||||
mov edi, eax
|
||||
clusfind:
|
||||
inc edi
|
||||
inc ecx
|
||||
call get_next_cluster
|
||||
jnc clusread
|
||||
cmp eax, edi
|
||||
jz clusfind
|
||||
stc
|
||||
clusread:
|
||||
pop di ; limit in sectors
|
||||
movzx edi, di
|
||||
push eax ; save next cluster
|
||||
pushf ; save flags
|
||||
; read cx clusters, starting from si
|
||||
; calculate number of sectors
|
||||
xchg eax, ecx
|
||||
call clustersz2sectorsz
|
||||
mov [num_sectors], eax
|
||||
jmp @f
|
||||
continue_load_file:
|
||||
les bx, [di] ; es:bx -> buffer
|
||||
movzx edi, word [di+4] ; di = limit in 4K blocks
|
||||
shl di, 3 ; now di = limit in sectors
|
||||
mov eax, [num_sectors]
|
||||
mov esi, [cur_cluster]
|
||||
push [next_cluster]
|
||||
push [flags]
|
||||
test eax, eax
|
||||
jz nextclus
|
||||
@@:
|
||||
; eax = number of sectors; compare with limit
|
||||
cmp eax, edi
|
||||
seta dl
|
||||
push dx ; limit was exceeded?
|
||||
jbe @f
|
||||
mov eax, edi
|
||||
@@:
|
||||
sub di, ax ; calculate new limit
|
||||
sub [num_sectors], eax
|
||||
mov [cur_cluster], esi
|
||||
; calculate starting sector
|
||||
push ax
|
||||
xchg eax, esi
|
||||
call cluster2sector
|
||||
pop cx
|
||||
add eax, [cur_delta]
|
||||
add [cur_delta], ecx
|
||||
; read
|
||||
call [read_sectors2]
|
||||
pop dx
|
||||
; next cluster?
|
||||
nextclus:
|
||||
popf
|
||||
pop eax
|
||||
mov [next_cluster], eax
|
||||
pushf
|
||||
pop [flags]
|
||||
jnc @f ; no next cluster => return
|
||||
mov dl, 1
|
||||
test di, di
|
||||
jz @f ; if there is next cluster but current limit is 0 => return: limit exceeded
|
||||
push di
|
||||
jmp clusloop ; all is ok, continue
|
||||
hooked_err:
|
||||
mov sp, 7C00h-14-2 ; restore stack
|
||||
mov dl, 3 ; return: read error
|
||||
@@:
|
||||
mov bl, dl
|
||||
mov bh, 0
|
||||
mov ax, [filesize]
|
||||
mov dx, [filesize+2]
|
||||
ret
|
||||
|
||||
scan_for_filename:
|
||||
; in: ss:si -> 11-bytes FAT name
|
||||
; in: ds:0 -> part of directory data
|
||||
; in: cx = number of entries
|
||||
; in: bh = 0
|
||||
; out: if found: CF=0, ZF=1, es:di -> directory entry
|
||||
; out: if not found, but continue required: CF=1 and ZF=0
|
||||
; out: if not found and zero item reached: CF=1 and ZF=1
|
||||
push ds
|
||||
pop es
|
||||
xor di, di
|
||||
push cx
|
||||
jcxz snoent
|
||||
sloop:
|
||||
cmp byte [di], bh
|
||||
jz snotfound
|
||||
test byte [di+11], 8 ; volume label?
|
||||
jnz scont ; ignore volume labels
|
||||
pusha
|
||||
mov cx, 11
|
||||
repz cmps byte [ss:si], byte [es:di]
|
||||
popa
|
||||
jz sdone
|
||||
scont:
|
||||
add di, 0x20
|
||||
loop sloop
|
||||
snoent:
|
||||
inc cx ; clear ZF flag
|
||||
snotfound:
|
||||
stc
|
||||
sdone:
|
||||
pop cx
|
||||
lrdret:
|
||||
ret
|
||||
|
||||
; Callback function for secondary loader
|
||||
callback:
|
||||
; in: ax = function number; only functions 1 and 2 are defined for now
|
||||
; save caller's stack
|
||||
mov dx, ss
|
||||
mov cx, sp
|
||||
; set our stack (required because we need ss=0)
|
||||
xor si, si
|
||||
mov ss, si
|
||||
mov sp, 7C00h-10
|
||||
mov bp, 7C00h
|
||||
push dx
|
||||
push cx
|
||||
; call our function
|
||||
stc ; unsupported function
|
||||
dec ax
|
||||
jz callback_readfile
|
||||
dec ax
|
||||
jnz callback_ret
|
||||
; function 2: continue loading file
|
||||
; can be called only after function 1 returned value bx=1 (only part of file was loaded)
|
||||
; in: ds:di -> information structure
|
||||
; dw:dw address
|
||||
; dw limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
|
||||
; out: bx=0 - ok, bx=1 - still only part of file was loaded, bx=3 - read error
|
||||
; out: dx:ax = file size
|
||||
call continue_load_file
|
||||
jmp callback_ret_succ
|
||||
callback_readfile:
|
||||
; function 1: read file
|
||||
; in: ds:di -> information structure
|
||||
; dw:dw address
|
||||
; dw limit in 4Kb blocks (0x1000 bytes) (must be non-zero and not greater than 0x100)
|
||||
; ASCIIZ name
|
||||
; out: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=2 - file not found, bx=3 - read error
|
||||
; out: dx:ax = file size (0xFFFFFFFF if file was not found)
|
||||
call load_file
|
||||
callback_ret_succ:
|
||||
clc ; function is supported
|
||||
callback_ret:
|
||||
; restore caller's stack
|
||||
pop cx
|
||||
pop ss
|
||||
mov sp, cx
|
||||
; return to caller
|
||||
retf
|
||||
|
||||
secondary_loader_info:
|
||||
dw 0, 0x1000
|
||||
dw 0x30000 / 0x1000
|
||||
db 'kernel.mnt',0
|
||||
aKernelNotFound db 'Fatal error: cannot load the kernel',0
|
||||
|
||||
;if $ > 0x8200
|
||||
;error 'total size of kordldr.f32 must not exceed 1024 bytes!'
|
||||
;end if
|
||||
|
||||
;foldcache_clus dd 0,0,0,0,0,0,0,0 ; start with no folders in cache
|
||||
;foldcache_mark dw 0
|
||||
; rw 7
|
||||
;foldcache_size rw 8
|
||||
foldcache_clus rd 8
|
||||
foldcache_mark rw 8
|
||||
foldcache_size rw 8
|
||||
26
kernel/branches/kolibri-lldw/bootloader/floppy1440.inc
Normal file
26
kernel/branches/kolibri-lldw/bootloader/floppy1440.inc
Normal file
@@ -0,0 +1,26 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
BS_OEMName db 'KOLIBRI ' ; db 8
|
||||
BPB_BytsPerSec dw 512 ; bytes per sector
|
||||
BPB_SecPerClus db 1 ; sectors per cluster
|
||||
BPB_RsvdSecCnt dw 1 ; number of reserver sectors
|
||||
BPB_NumFATs db 2 ; count of FAT data structures
|
||||
BPB_RootEntCnt dw 224 ; count of 32-byte dir. entries (224*32 = 14 sectors)
|
||||
BPB_TotSec16 dw 2880 ; count of sectors on the volume (2880 for 1.44 mbytes disk)
|
||||
BPB_Media db 0f0h ; f0 - used for removable media
|
||||
BPB_FATSz16 dw 9 ; count of sectors by one copy of FAT
|
||||
BPB_SecPerTrk dw 18 ; sectors per track
|
||||
BPB_NumHeads dw 2 ; number of heads
|
||||
BPB_HiddSec dd 0 ; count of hidden sectors
|
||||
BPB_TotSec32 dd 0 ; count of sectors on the volume (if > 65535)
|
||||
BS_DrvNum db 0 ; int 13h drive number
|
||||
BS_Reserved db 0 ; reserved
|
||||
BS_BootSig db 29h ; Extended boot signature
|
||||
BS_VolID dd 0 ; Volume serial number
|
||||
BS_VolLab db 'KOLIBRI ' ; Volume label (db 11)
|
||||
BS_FilSysType db 'FAT12 ' ; file system type (db 8)
|
||||
26
kernel/branches/kolibri-lldw/bootloader/floppy1680.inc
Normal file
26
kernel/branches/kolibri-lldw/bootloader/floppy1680.inc
Normal file
@@ -0,0 +1,26 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
BS_OEMName db 'KOLIBRI ' ; db 8
|
||||
BPB_BytsPerSec dw 512 ; bytes per sector
|
||||
BPB_SecPerClus db 1 ; sectors per cluster
|
||||
BPB_RsvdSecCnt dw 1 ; number of reserver sectors
|
||||
BPB_NumFATs db 2 ; count of FAT data structures
|
||||
BPB_RootEntCnt dw 112 ; count of 32-byte dir. entries (112*32 = 7 sectors)
|
||||
BPB_TotSec16 dw 3360 ; count of sectors on the volume (3360 for 1.68 mbytes disk)
|
||||
BPB_Media db 0f0h ; f0 - used for removable media
|
||||
BPB_FATSz16 dw 10 ; count of sectors by one copy of FAT
|
||||
BPB_SecPerTrk dw 21 ; sectors per track
|
||||
BPB_NumHeads dw 2 ; number of heads
|
||||
BPB_HiddSec dd 0 ; count of hidden sectors
|
||||
BPB_TotSec32 dd 0 ; count of sectors on the volume (if > 65535)
|
||||
BS_DrvNum db 0 ; int 13h drive number
|
||||
BS_Reserved db 0 ; reserved
|
||||
BS_BootSig db 29h ; Extended boot signature
|
||||
BS_VolID dd 0 ; Volume serial number
|
||||
BS_VolLab db 'KOLIBRI ' ; Volume label (db 11)
|
||||
BS_FilSysType db 'FAT12 ' ; file system type (db 8)
|
||||
26
kernel/branches/kolibri-lldw/bootloader/floppy1743.inc
Normal file
26
kernel/branches/kolibri-lldw/bootloader/floppy1743.inc
Normal file
@@ -0,0 +1,26 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
BS_OEMName db 'KOLIBRI ' ; db 8
|
||||
BPB_BytsPerSec dw 512 ; bytes per sector
|
||||
BPB_SecPerClus db 1 ; sectors per cluster
|
||||
BPB_RsvdSecCnt dw 1 ; number of reserver sectors
|
||||
BPB_NumFATs db 2 ; count of FAT data structures
|
||||
BPB_RootEntCnt dw 224 ; count of 32-byte dir. entries (224*32 = 14 sectors)
|
||||
BPB_TotSec16 dw 3486 ; count of sectors on the volume (3486 for 1.74 mbytes disk)
|
||||
BPB_Media db 0f0h ; f0 - used for removable media
|
||||
BPB_FATSz16 dw 11 ; count of sectors by one copy of FAT
|
||||
BPB_SecPerTrk dw 21 ; sectors per track
|
||||
BPB_NumHeads dw 2 ; number of heads
|
||||
BPB_HiddSec dd 0 ; count of hidden sectors
|
||||
BPB_TotSec32 dd 0 ; count of sectors on the volume (if > 65535)
|
||||
BS_DrvNum db 0 ; int 13h drive number
|
||||
BS_Reserved db 0 ; reserved
|
||||
BS_BootSig db 29h ; Extended boot signature
|
||||
BS_VolID dd 0 ; Volume serial number
|
||||
BS_VolLab db 'KOLIBRI ' ; Volume label (db 11)
|
||||
BS_FilSysType db 'FAT12 ' ; file system type (db 8)
|
||||
26
kernel/branches/kolibri-lldw/bootloader/floppy2880.inc
Normal file
26
kernel/branches/kolibri-lldw/bootloader/floppy2880.inc
Normal file
@@ -0,0 +1,26 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
BS_OEMName db 'KOLIBRI ' ; db 8
|
||||
BPB_BytsPerSec dw 512 ; bytes per sector
|
||||
BPB_SecPerClus db 2 ; sectors per cluster
|
||||
BPB_RsvdSecCnt dw 1 ; number of reserver sectors
|
||||
BPB_NumFATs db 2 ; count of FAT data structures
|
||||
BPB_RootEntCnt dw 240 ; count of 32-byte dir. entries (240*32 = 15 sectors)
|
||||
BPB_TotSec16 dw 5760 ; count of sectors on the volume (5760 for 2.88 mbytes disk)
|
||||
BPB_Media db 0f0h ; f0 - used for removable media
|
||||
BPB_FATSz16 dw 9 ; count of sectors by one copy of FAT
|
||||
BPB_SecPerTrk dw 36 ; sectors per track
|
||||
BPB_NumHeads dw 2 ; number of heads
|
||||
BPB_HiddSec dd 0 ; count of hidden sectors
|
||||
BPB_TotSec32 dd 0 ; count of sectors on the volume (if > 65535)
|
||||
BS_DrvNum db 0 ; int 13h drive number
|
||||
BS_Reserved db 0 ; reserved
|
||||
BS_BootSig db 29h ; Extended boot signature
|
||||
BS_VolID dd 0 ; Volume serial number
|
||||
BS_VolLab db 'KOLIBRI ' ; Volume label (db 11)
|
||||
BS_FilSysType db 'FAT12 ' ; file system type (db 8)
|
||||
296
kernel/branches/kolibri-lldw/bootloader/grub4kos.asm
Normal file
296
kernel/branches/kolibri-lldw/bootloader/grub4kos.asm
Normal file
@@ -0,0 +1,296 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2014-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; Kolibri OS support loader for GRUB
|
||||
;
|
||||
; Copyright (C) Alex Nogueira Teixeira
|
||||
; Copyright (C) Diamond
|
||||
; Copyright (C) Dmitry Kartashov aka shurf
|
||||
; Copyright (C) Serge
|
||||
;
|
||||
; Distributed under GPL, see file COPYING for details
|
||||
;
|
||||
; Version 1.0
|
||||
|
||||
lf = 0x0A
|
||||
cr = 0x0D
|
||||
|
||||
use32
|
||||
|
||||
|
||||
org 0x100000
|
||||
|
||||
mboot:
|
||||
dd 0x1BADB002
|
||||
dd 0x00010003
|
||||
dd -(0x1BADB002 + 0x00010003)
|
||||
dd mboot
|
||||
dd 0x100000
|
||||
dd __edata
|
||||
dd __end
|
||||
dd __start
|
||||
|
||||
align 16
|
||||
__start:
|
||||
|
||||
virtual at ebp+3
|
||||
.BS_OEMName rb 8
|
||||
.BPB_BytsPerSec rw 1 ; bytes per sector
|
||||
.BPB_SecPerClus rb 1 ; sectors per cluster
|
||||
.BPB_RsvdSecCnt rw 1 ; number of reserver sectors
|
||||
.BPB_NumFATs rb 1 ; count of FAT data structures
|
||||
.BPB_RootEntCnt rw 1 ; count of 32-byte dir. entries (224*32 = 14 sectors)
|
||||
.BPB_TotSec16 rw 1 ; count of sectors on the volume (2880 for 1.44 mbytes disk)
|
||||
.BPB_Media rb 1 ; f0 - used for removable media
|
||||
.BPB_FATSz16 rw 1 ; count of sectors by one copy of FAT
|
||||
.BPB_SecPerTrk rw 1 ; sectors per track
|
||||
.BPB_NumHeads rw 1 ; number of heads
|
||||
.BPB_HiddSec rd 1 ; count of hidden sectors
|
||||
.BPB_TotSec32 rd 1 ; count of sectors on the volume (if > 65535)
|
||||
end virtual
|
||||
|
||||
cld
|
||||
mov esi, mboot
|
||||
mov edi, 0x80000
|
||||
mov ecx, 624/4 ;magic value
|
||||
rep movsd
|
||||
jmp .check_mbi
|
||||
|
||||
org $-0x80000
|
||||
align 4
|
||||
.check_mbi:
|
||||
cmp eax, 0x2BADB002
|
||||
mov esi, sz_invboot
|
||||
jne .panic
|
||||
|
||||
bt dword [ebx], 3
|
||||
mov esi, sz_nomods
|
||||
jnc .panic
|
||||
|
||||
mov edx, [ebx+20] ;mods_count
|
||||
mov edi, [ebx+24] ;mods_addr
|
||||
cmp edx, 1
|
||||
mov esi, sz_nomods
|
||||
jne .panic
|
||||
|
||||
.scan_mod:
|
||||
mov ebp, [edi] ;image start
|
||||
mov ecx, [edi+4] ;image end
|
||||
sub ecx, ebp ;image size
|
||||
cmp ecx, 512*18*80*2 ;1.44 floppy
|
||||
mov esi, sz_image
|
||||
jne .panic
|
||||
|
||||
mov [_image_start], ebp
|
||||
mov [_image_size], ecx
|
||||
|
||||
; calculate some disk parameters
|
||||
; - beginning sector of RootDir
|
||||
|
||||
movzx eax, word [.BPB_FATSz16]
|
||||
movzx ecx, byte [.BPB_NumFATs]
|
||||
mul ecx
|
||||
add ax, [.BPB_RsvdSecCnt]
|
||||
mov [FirstRootDirSecNum], eax
|
||||
mov esi, eax
|
||||
|
||||
; - count of sectors in RootDir
|
||||
movzx ebx, word [.BPB_BytsPerSec]
|
||||
mov cl, 5 ; divide ax by 32
|
||||
shr ebx, cl ; bx = directory entries per sector
|
||||
movzx eax, word [.BPB_RootEntCnt]
|
||||
xor edx, edx
|
||||
div ebx
|
||||
mov [RootDirSecs], eax
|
||||
|
||||
; - data start
|
||||
add esi, eax ; add beginning sector of RootDir and count sectors in RootDir
|
||||
mov [data_start], esi
|
||||
|
||||
; reading root directory
|
||||
; al=count root dir sectrors !!!! TODO: al, max 255 sectors !!!!
|
||||
|
||||
mov eax, [FirstRootDirSecNum]
|
||||
mul word [.BPB_BytsPerSec]
|
||||
lea esi, [ebp+eax]
|
||||
|
||||
mov eax, [RootDirSecs]
|
||||
mul word [.BPB_BytsPerSec]
|
||||
add eax, esi ; EAX = end of root dir. in buffer pos_read_tmp
|
||||
|
||||
; find kernel file in root directory
|
||||
|
||||
.loop_find_dir_entry:
|
||||
push esi
|
||||
mov ecx, 11
|
||||
mov edi, kernel_name
|
||||
rep cmpsb ; compare es:si and es:di, cx bytes long
|
||||
pop esi
|
||||
je .found_kernel_file
|
||||
add esi, 32 ; next dir. entry
|
||||
cmp esi, eax ; end of directory
|
||||
jb .loop_find_dir_entry
|
||||
|
||||
mov esi, sz_kernel
|
||||
jmp .panic
|
||||
|
||||
; === KERNEL FOUND. LOADING... ===
|
||||
|
||||
.found_kernel_file:
|
||||
|
||||
movzx ecx, word [esi+01ah] ; first cluster of kernel file
|
||||
|
||||
; reading first FAT table
|
||||
movzx eax, word [.BPB_RsvdSecCnt] ; begin first FAT abs sector number
|
||||
mul word [.BPB_BytsPerSec]
|
||||
lea ebx, [ebp+eax] ; FAT address
|
||||
|
||||
;ebx = FAT
|
||||
;ecx = cluster
|
||||
;esi = src
|
||||
;edi = dst
|
||||
;ebp = image
|
||||
|
||||
; copy kernel file
|
||||
|
||||
movzx eax, word [.BPB_BytsPerSec]
|
||||
movsx edx, byte [.BPB_SecPerClus]
|
||||
mul edx
|
||||
shr eax, 2
|
||||
mov [cluster_size], eax
|
||||
|
||||
mov edi, 0x10000 ;kernel base address
|
||||
|
||||
.copy_kernel:
|
||||
|
||||
; convert cluster number to sector number
|
||||
mov eax, ecx ; data cluster to read
|
||||
sub eax, 2
|
||||
movzx edx, byte [.BPB_SecPerClus]
|
||||
mul edx
|
||||
add eax, [data_start]
|
||||
movzx edx, word [.BPB_BytsPerSec]
|
||||
mul edx
|
||||
|
||||
lea esi, [ebp+eax]
|
||||
mov edx, ecx
|
||||
mov ecx, [cluster_size]
|
||||
rep movsd
|
||||
mov ecx, edx
|
||||
|
||||
shr edx, 1
|
||||
pushf
|
||||
add edx, ecx ; di = bp * 1.5
|
||||
mov ax, word [ebx+edx] ; read next entry from FAT-chain
|
||||
popf
|
||||
jc .move_4_right
|
||||
and ax, 0fffh
|
||||
jmp .verify_end_sector
|
||||
.move_4_right:
|
||||
shr ax, 4
|
||||
.verify_end_sector:
|
||||
cmp ax, 0ff8h ; last cluster
|
||||
jae .execute_kernel
|
||||
movzx ecx, ax
|
||||
jmp .copy_kernel
|
||||
|
||||
.execute_kernel:
|
||||
|
||||
mov edi, 0x100000
|
||||
mov esi, [_image_start]
|
||||
mov ecx, [_image_size]
|
||||
shr ecx, 2
|
||||
rep movsd
|
||||
xor eax, eax
|
||||
mov ecx, 1024
|
||||
rep stosd
|
||||
|
||||
xor ebx, ebx
|
||||
xor ecx, ecx
|
||||
xor edx, edx
|
||||
xor esi, esi
|
||||
xor edi, edi
|
||||
xor ebp, ebp
|
||||
xor esp, esp
|
||||
|
||||
lgdt [.tmp_gdt]
|
||||
jmp far 0x08:.mode_16 and 0xFFFF
|
||||
|
||||
.panic:
|
||||
mov ebx, sz_halt
|
||||
mov edx, 0xb8000+160*10+2
|
||||
mov ah, 0x07
|
||||
.line:
|
||||
mov edi, edx
|
||||
.print:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .print_next
|
||||
stosw
|
||||
jmp .print
|
||||
|
||||
.print_next:
|
||||
test ebx, ebx
|
||||
jz ._hlt
|
||||
|
||||
mov esi, ebx
|
||||
xor ebx, ebx
|
||||
add edx, 160
|
||||
jmp .line
|
||||
|
||||
._hlt:
|
||||
hlt
|
||||
jmp ._hlt
|
||||
|
||||
align 8
|
||||
.tmp_gdt: dw 15
|
||||
dd .tmp_gdt
|
||||
dw 0
|
||||
|
||||
.code16: dw 0xFFFF
|
||||
dw 0
|
||||
db 8
|
||||
db 10011010b
|
||||
dw 0
|
||||
|
||||
use16
|
||||
.mode_16:
|
||||
mov eax, cr0
|
||||
and eax, not 0x80000001
|
||||
mov cr0, eax
|
||||
jmp far 0x8000:.real_mode and 0xFFFF
|
||||
|
||||
.real_mode:
|
||||
xor eax, eax
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov ss, ax
|
||||
mov gs, ax
|
||||
mov fs, ax
|
||||
jmp far 0x1000:0000
|
||||
|
||||
|
||||
sz_invboot db 'Invalid multiboot loader magic value',0
|
||||
sz_nomods db 'No image loaded',0
|
||||
sz_image db 'Image size invalid',0
|
||||
sz_halt db 'Halted',0
|
||||
|
||||
sz_kernel db cr
|
||||
kernel_name db 'KERNEL MNT ?',0
|
||||
|
||||
org $+0x80000
|
||||
__edata:
|
||||
|
||||
align 4
|
||||
_image_start rd 1
|
||||
_image_size rd 1
|
||||
|
||||
FirstRootDirSecNum rd 1
|
||||
RootDirSecs rd 1
|
||||
data_start rd 1
|
||||
cluster_size rd 1
|
||||
__end:
|
||||
50
kernel/branches/kolibri-lldw/bootloader/readme
Normal file
50
kernel/branches/kolibri-lldw/bootloader/readme
Normal file
@@ -0,0 +1,50 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
Загрузочный сектор для ОС Колибри (FAT12, дискета)
|
||||
|
||||
- Описание
|
||||
Позволяет загружать KERNEL.MNT с дискет/образов
|
||||
объёмом 1.44M, 1.68M, 1.72M и 2.88M
|
||||
Для выбора объёма диска, для которого надо собрать
|
||||
загрузочный сектор, необходимо в файле boot_fat12.asm
|
||||
раскомментировать строку вида:
|
||||
include 'floppy????.inc'
|
||||
для необходимого объёма диска. Доступные варианты:
|
||||
floppy1440.inc,
|
||||
floppy1680.inc,
|
||||
floppy1743.inc и floppy2880.inc
|
||||
|
||||
- Сборка
|
||||
fasm boot_fat12.asm
|
||||
|
||||
- Для записи загрузочного сектора на диск/образ под Linux
|
||||
можно воспользоваться следующей командой:
|
||||
dd if=boot_fat12.bin of=288.img bs=512 count=1 conv=notrunc
|
||||
|
||||
---------------------------------------------------------------------
|
||||
|
||||
Floppy FAT12 boot sector for KolibriOS.
|
||||
|
||||
- Description
|
||||
Allows booting KERNEL.MNT floppies/images
|
||||
with volumes of 1.44M, 1.68M, 1.72M and 2.88M
|
||||
To select the volume of the disk, which should gather
|
||||
boot sector, it was necessary in file boot_fat12.asm
|
||||
uncomment line:
|
||||
include 'floppy????. inc'
|
||||
for the necessary disk volume. Available options is:
|
||||
floppy1440.inc,
|
||||
floppy1680.inc,
|
||||
floppy1743.inc and floppy2880.inc
|
||||
|
||||
- Compile
|
||||
fasm boot_fat12.asm
|
||||
|
||||
- To write boot sector to the floppy/image under Linux
|
||||
you can use the following command:
|
||||
dd if=boot_fat12.bin of=288.img bs=512 count=1 conv=notrunc
|
||||
@@ -0,0 +1,3 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("uefi64kos.asm", "fasm -dUEFI=1 -dextended_primary_loader=1 %f %o", "bootx64.efi")
|
||||
tup.rule("uefi32kos.asm", "fasm -dUEFI=1 -dextended_primary_loader=1 %f %o", "bootia32.efi")
|
||||
21
kernel/branches/kolibri-lldw/bootloader/uefi4kos/kolibri.ini
Normal file
21
kernel/branches/kolibri-lldw/bootloader/uefi4kos/kolibri.ini
Normal file
@@ -0,0 +1,21 @@
|
||||
; Screen resolution
|
||||
resolution=1024x768
|
||||
|
||||
; Duplicate debug output to the screen
|
||||
debug_print=0
|
||||
|
||||
; Start LAUNCHER app after kernel is loaded
|
||||
launcher_start=1
|
||||
|
||||
; Configure MTRR's
|
||||
mtrr=1
|
||||
|
||||
; 3: use ramdisk loaded from kolibri.img
|
||||
; 5: don't use ramdisk, use /sys directory
|
||||
imgfrom=3
|
||||
|
||||
; Path to /sys directory, only internal
|
||||
; disk drives are alowed (no usbdisk).
|
||||
; Example: syspath=/HD0/1/KOLIBRIOS
|
||||
syspath=/rd/1
|
||||
|
||||
272
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi.inc
Normal file
272
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi.inc
Normal file
@@ -0,0 +1,272 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2020. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; Version 2, or (at your option) any later version. ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Based on UEFI library for fasm by bzt, Public Domain. ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
EFI_LOCATE_SEARCH_TYPE:
|
||||
.AllHandles = 0
|
||||
.ByRegisterNotify = 1
|
||||
.ByProtocol = 2
|
||||
|
||||
; EFI_MEMORY_TYPE
|
||||
EFI_RESERVED_MEMORY_TYPE = 0
|
||||
EFI_LOADER_CODE = 1
|
||||
EFI_LOADER_DATA = 2
|
||||
EFI_BOOT_SERVICES_CODE = 3
|
||||
EFI_BOOT_SERVICES_DATA = 4
|
||||
EFI_RUNTIME_SERVICES_CODE = 5
|
||||
EFI_RUNTIME_SERVICES_DATA = 6
|
||||
EFI_CONVENTIONAL_MEMORY = 7
|
||||
EFI_UNUSABLE_MEMORY = 8
|
||||
EFI_ACPI_RECLAIM_MEMORY = 9
|
||||
EFI_ACPI_MEMORY_NVS = 10
|
||||
EFI_MEMORY_MAPPED_IO = 11
|
||||
EFI_MEMORY_MAPPED_IO_PORT_SPACE = 12
|
||||
EFI_PAL_CODE = 13
|
||||
EFI_PERSISTENT_MEMORY = 14
|
||||
EFI_MAX_MEMORY_TYPE = 15
|
||||
|
||||
; EFI_ALLOCATE_TYPE
|
||||
EFI_ALLOCATE_ANY_PAGES = 0
|
||||
EFI_ALLOCATE_MAX_ADDRESS = 1
|
||||
EFI_ALLOCATE_ADDRESS = 2
|
||||
|
||||
EFI_MEMORY_UC = 0x00000001
|
||||
EFI_MEMORY_WC = 0x00000002
|
||||
EFI_MEMORY_WT = 0x00000004
|
||||
EFI_MEMORY_WB = 0x00000008
|
||||
EFI_MEMORY_UCE = 0x00000010
|
||||
EFI_MEMORY_WP = 0x00001000
|
||||
EFI_MEMORY_RP = 0x00002000
|
||||
EFI_MEMORY_XP = 0x00004000
|
||||
EFI_MEMORY_NV = 0x00008000
|
||||
EFI_MEMORY_MORE_RELIABLE = 0x00010000
|
||||
EFI_MEMORY_RO = 0x00020000
|
||||
|
||||
EFI_SUCCESS = 0
|
||||
EFI_LOAD_ERROR = EFIERR or 1
|
||||
EFI_INVALID_PARAMETER = EFIERR or 2
|
||||
EFI_UNSUPPORTED = EFIERR or 3
|
||||
EFI_BAD_BUFFER_SIZE = EFIERR or 4
|
||||
EFI_BUFFER_TOO_SMALL = EFIERR or 5
|
||||
EFI_NOT_READY = EFIERR or 6
|
||||
EFI_DEVICE_ERROR = EFIERR or 7
|
||||
EFI_WRITE_PROTECTED = EFIERR or 8
|
||||
EFI_OUT_OF_RESOURCES = EFIERR or 9
|
||||
EFI_VOLUME_CORRUPTED = EFIERR or 10
|
||||
EFI_VOLUME_FULL = EFIERR or 11
|
||||
EFI_NO_MEDIA = EFIERR or 12
|
||||
EFI_MEDIA_CHANGED = EFIERR or 13
|
||||
EFI_NOT_FOUND = EFIERR or 14
|
||||
EFI_ACCESS_DENIED = EFIERR or 15
|
||||
EFI_NO_RESPONSE = EFIERR or 16
|
||||
EFI_NO_MAPPING = EFIERR or 17
|
||||
EFI_TIMEOUT = EFIERR or 18
|
||||
EFI_NOT_STARTED = EFIERR or 19
|
||||
EFI_ALREADY_STARTED = EFIERR or 20
|
||||
EFI_ABORTED = EFIERR or 21
|
||||
EFI_ICMP_ERROR = EFIERR or 22
|
||||
EFI_TFTP_ERROR = EFIERR or 23
|
||||
EFI_PROTOCOL_ERROR = EFIERR or 24
|
||||
|
||||
|
||||
EFI_FILE_SYSTEM_INFO_ID equ 0x93,0x6e,0x57,0x09,0x3f,0x6d,0xd2,0x11, \
|
||||
0x39,0x8e,0x00,0xa0,0xc9,0x69,0x72,0x3b
|
||||
|
||||
EFI_SYSTEM_TABLE_SIGNATURE equ 0x49,0x42,0x49,0x20,0x53,0x59,0x53,0x54
|
||||
|
||||
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID equ 0x22,0x5b,0x4e,0x96, \
|
||||
0x59,0x64,0xd2,0x11, \
|
||||
0x8e,0x39,0x00,0xa0, \
|
||||
0xc9,0x69,0x72,0x3b
|
||||
|
||||
EFI_LOADED_IMAGE_PROTOCOL_GUID equ 0xA1,0x31,0x1b,0x5b,0x62,0x95,0xd2,0x11, \
|
||||
0x8E,0x3F,0x00,0xA0,0xC9,0x69,0x72,0x3B
|
||||
|
||||
EFI_BLOCK_IO_PROTOCOL_GUID equ 0x21,0x5b,0x4e,0x96,0x59,0x64,0xd2,0x11, \
|
||||
0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b
|
||||
|
||||
EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID equ 0xde,0xa9,0x42,0x90,0xdc,0x23,0x38,0x4a, \
|
||||
0x96,0xfb,0x7a,0xde,0xd0,0x80,0x51,0x6a
|
||||
|
||||
EFI_FILE_MODE_READ = 1
|
||||
EFI_FILE_MODE_WRITE = 2
|
||||
EFI_FILE_MODE_CREATE = 0x8000000000000000
|
||||
|
||||
struct EFI_MEMORY_DESCRIPTOR
|
||||
Type dd ?
|
||||
dd ? ; align
|
||||
PhysicalStart DQ ?
|
||||
VirtualStart DQ ?
|
||||
NumberOfPages DQ ?
|
||||
Attribute DQ ?
|
||||
ends
|
||||
|
||||
struct EFI_FILE_SYSTEM_INFO
|
||||
Size DQ ?
|
||||
ReadOnly db ?
|
||||
rb 7
|
||||
VolumeSize DQ ?
|
||||
FreeSpace DQ ?
|
||||
BlockSize dd ?
|
||||
VolumeLabel rw 32
|
||||
ends
|
||||
|
||||
struct EFI_TABLE_HEADER
|
||||
Signature DQ ?
|
||||
Revision dd ?
|
||||
HeaderSize dd ?
|
||||
CRC32 dd ?
|
||||
Reserved dd ?
|
||||
ends
|
||||
|
||||
struct EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
|
||||
Reset DN ?
|
||||
OutputString DN ?
|
||||
TestString DN ?
|
||||
QueryMode DN ?
|
||||
SetMode DN ?
|
||||
SetAttribute DN ?
|
||||
ClearScreen DN ?
|
||||
SetCursorPosition DN ?
|
||||
EnableCursor DN ?
|
||||
Mode DN ?
|
||||
ends
|
||||
|
||||
|
||||
struct SIMPLE_INPUT_INTERFACE
|
||||
Reset DN ?
|
||||
ReadKeyStroke DN ?
|
||||
WaitForKey DN ?
|
||||
ends
|
||||
|
||||
struct EFI_BOOT_SERVICES
|
||||
Hdr EFI_TABLE_HEADER
|
||||
RaisePriority DN ?
|
||||
RestorePriority DN ?
|
||||
AllocatePages DN ?
|
||||
FreePages DN ?
|
||||
GetMemoryMap DN ?
|
||||
AllocatePool DN ?
|
||||
FreePool DN ?
|
||||
CreateEvent DN ?
|
||||
SetTimer DN ?
|
||||
WaitForEvent DN ?
|
||||
SignalEvent DN ?
|
||||
CloseEvent DN ?
|
||||
CheckEvent DN ?
|
||||
InstallProtocolInterface DN ?
|
||||
ReInstallProtocolInterface DN ?
|
||||
UnInstallProtocolInterface DN ?
|
||||
HandleProtocol DN ?
|
||||
Reserved DN ?
|
||||
RegisterProtocolNotify DN ?
|
||||
LocateHandle DN ?
|
||||
LocateDevicePath DN ?
|
||||
InstallConfigurationTable DN ?
|
||||
ImageLoad DN ?
|
||||
ImageStart DN ?
|
||||
Exit DN ?
|
||||
ImageUnLoad DN ?
|
||||
ExitBootServices DN ?
|
||||
GetNextMonotonicCount DN ?
|
||||
Stall DN ?
|
||||
SetWatchdogTimer DN ?
|
||||
ConnectController DN ?
|
||||
DisConnectController DN ?
|
||||
OpenProtocol DN ?
|
||||
CloseProtocol DN ?
|
||||
OpenProtocolInformation DN ?
|
||||
ProtocolsPerHandle DN ?
|
||||
LocateHandleBuffer DN ?
|
||||
LocateProtocol DN ?
|
||||
InstallMultipleProtocolInterfaces DN ?
|
||||
UnInstallMultipleProtocolInterfaces DN ?
|
||||
CalculateCrc32 DN ?
|
||||
CopyMem DN ?
|
||||
SetMem DN ?
|
||||
ends
|
||||
|
||||
struct EFI_RUNTIME_SERVICES
|
||||
Hdr EFI_TABLE_HEADER
|
||||
GetTime DN ?
|
||||
SetTime DN ?
|
||||
GetWakeUpTime DN ?
|
||||
SetWakeUpTime DN ?
|
||||
SetVirtualAddressMap DN ?
|
||||
ConvertPointer DN ?
|
||||
GetVariable DN ?
|
||||
GetNextVariableName DN ?
|
||||
SetVariable DN ?
|
||||
GetNextHighMonoCount DN ?
|
||||
ResetSystem DN ?
|
||||
ends
|
||||
|
||||
struct EFI_SIMPLE_FILE_SYSTEM_PROTOCOL
|
||||
Revision DQ ?
|
||||
OpenVolume DN ?
|
||||
ends
|
||||
|
||||
struct EFI_FILE_PROTOCOL
|
||||
Revision DQ ?
|
||||
Open DN ?
|
||||
Close DN ?
|
||||
Delete DN ?
|
||||
Read DN ?
|
||||
Write DN ?
|
||||
GetPosition DN ?
|
||||
SetPosition DN ?
|
||||
GetInfo DN ?
|
||||
SetInfo DN ?
|
||||
Flush DN ?
|
||||
OpenEx DN ?
|
||||
ReadEx DN ?
|
||||
WriteEx DN ?
|
||||
FlushEx DN ?
|
||||
ends
|
||||
|
||||
struct EFI_GRAPHICS_OUTPUT_PROTOCOL
|
||||
QueryMode DN ?
|
||||
SetMode DN ?
|
||||
Blt DN ?
|
||||
Mode DN ?
|
||||
ends
|
||||
|
||||
struct EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE
|
||||
MaxMode dd ?
|
||||
Mode dd ?
|
||||
Info DN ?
|
||||
SizeOfInfo DN ?
|
||||
FrameBufferBase DQ ?
|
||||
FrameBufferSize DN ?
|
||||
ends
|
||||
|
||||
EFI_GRAPHICS_PIXEL_FORMAT:
|
||||
.PixelRedGreenBlueReserved8BitPerColor = 0
|
||||
.PixelBlueGreenRedReserved8BitPerColor = 1
|
||||
.PixelBitMask = 2
|
||||
.PixelBltOnly = 3
|
||||
.PixelFormatMax = 4
|
||||
|
||||
struct EFI_PIXEL_BITMASK
|
||||
RedMask dd ?
|
||||
GreenMask dd ?
|
||||
BlueMask dd ?
|
||||
ReservedMask dd ?
|
||||
ends
|
||||
|
||||
struct EFI_GRAPHICS_OUTPUT_MODE_INFORMATION
|
||||
Version dd ?
|
||||
HorizontalResolution dd ?
|
||||
VerticalResolution dd ?
|
||||
PixelFormat dd ?
|
||||
PixelInformation EFI_PIXEL_BITMASK
|
||||
PixelsPerScanLine dd ?
|
||||
ends
|
||||
58
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi32.inc
Normal file
58
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi32.inc
Normal file
@@ -0,0 +1,58 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2020. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; Version 2, or (at your option) any later version. ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Based on UEFI library for fasm by bzt, Public Domain. ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
DN fix dd ; native
|
||||
|
||||
include "uefi.inc"
|
||||
|
||||
EFIERR = 0x80000000
|
||||
|
||||
struct EFI_SYSTEM_TABLE
|
||||
Hdr EFI_TABLE_HEADER
|
||||
FirmwareVendor dd ?
|
||||
FirmwareRevision dd ?
|
||||
ConsoleInHandle dd ?
|
||||
ConIn dd ?
|
||||
ConsoleOutHandle dd ?
|
||||
ConOut dd ?
|
||||
StandardErrorHandle dd ?
|
||||
StdErr dd ?
|
||||
RuntimeServices dd ?
|
||||
BootServices dd ?
|
||||
NumberOfTableEntries dd ?
|
||||
ConfigurationTable dd ?
|
||||
ends
|
||||
|
||||
struct EFI_CONFIGURATION_TABLE
|
||||
VendorGUID rd 4
|
||||
VendorTable dd ?
|
||||
ends
|
||||
|
||||
struct EFI_LOADED_IMAGE_PROTOCOL
|
||||
Revision dd ?
|
||||
ParentHandle dd ?
|
||||
SystemTable dd ?
|
||||
DeviceHandle dd ?
|
||||
FilePath dd ?
|
||||
Reserved dd ?
|
||||
LoadOptionsSize dd ?
|
||||
ImageBase dd ?
|
||||
ImageSize DQ ?
|
||||
ImageCodeType dd ?
|
||||
ImageDataType dd ?
|
||||
UnLoad dd ?
|
||||
ends
|
||||
|
||||
section '.text' code executable readable
|
||||
|
||||
uefifunc:
|
||||
ret
|
||||
990
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi32kos.asm
Normal file
990
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi32kos.asm
Normal file
@@ -0,0 +1,990 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2020. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; Version 2, or (at your option) any later version. ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
format pe efi
|
||||
entry main
|
||||
|
||||
section '.text' code executable readable
|
||||
|
||||
include '../../struct.inc'
|
||||
include '../../macros.inc'
|
||||
include '../../proc32.inc'
|
||||
include '../../const.inc'
|
||||
include 'uefi32.inc'
|
||||
|
||||
MEMORY_MAP_SIZE = 0x4000
|
||||
GOP_BUFFER_SIZE = 0x100
|
||||
LIP_BUFFER_SIZE = 0x100
|
||||
FILE_BUFFER_SIZE = 0x1000
|
||||
|
||||
KERNEL_BASE = 0x10000
|
||||
RAMDISK_BASE = 0x100000
|
||||
MAX_FILE_SIZE = 0x10000000
|
||||
|
||||
CODE_32_SELECTOR = 8
|
||||
DATA_32_SELECTOR = 16
|
||||
|
||||
; linux/arch/x86/include/uapi/asm/e820.h
|
||||
E820_RAM = 1
|
||||
E820_RESERVED = 2
|
||||
E820_ACPI = 3
|
||||
E820_NVS = 4
|
||||
E820_UNUSABLE = 5
|
||||
E820_PMEM = 7
|
||||
|
||||
proc load_file stdcall uses ebx esi edi, _root, _name, _buffer, _size, _fatal
|
||||
mov eax, [_root]
|
||||
ccall [eax+EFI_FILE_PROTOCOL.Open], eax, file_handle, [_name], \
|
||||
EFI_FILE_MODE_READ, 0
|
||||
test eax, eax
|
||||
jz @f
|
||||
xor eax, eax
|
||||
cmp [_fatal], 1
|
||||
jnz .done
|
||||
mov ebx, [efi_table]
|
||||
mov ebx, [ebx+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [ebx+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], ebx, \
|
||||
msg_error_open_file
|
||||
ccall [ebx+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], ebx, \
|
||||
[_name]
|
||||
jmp $
|
||||
@@:
|
||||
mov eax, [file_handle]
|
||||
lea ecx, [_size]
|
||||
ccall [eax+EFI_FILE_PROTOCOL.Read], eax, ecx, [_buffer]
|
||||
mov eax, [file_handle]
|
||||
ccall [eax+EFI_FILE_PROTOCOL.Close], eax
|
||||
mov eax, [_size]
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc skip_whitespace
|
||||
.next_char:
|
||||
cmp byte[esi], 0
|
||||
jz .done
|
||||
cmp byte[esi], 0x20 ; ' '
|
||||
jz .whitespace
|
||||
cmp byte[esi], 9 ; '\t'
|
||||
jz .whitespace
|
||||
jmp .done
|
||||
.whitespace:
|
||||
inc esi
|
||||
jmp .next_char
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc skip_until_newline
|
||||
.next_char:
|
||||
cmp byte[esi], 0
|
||||
jz .done
|
||||
cmp byte[esi], 0xd ; '\r'
|
||||
jz .done
|
||||
cmp byte[esi], 0xa ; '\n'
|
||||
jz .done
|
||||
inc esi
|
||||
jmp .next_char
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc skip_newline
|
||||
.next_char:
|
||||
cmp byte[esi], 0xd ; '\r'
|
||||
jz .newline
|
||||
cmp byte[esi], 0xa ; '\n'
|
||||
jz .newline
|
||||
jmp .done
|
||||
.newline:
|
||||
inc esi
|
||||
jmp .next_char
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc skip_line
|
||||
call skip_until_newline
|
||||
call skip_newline
|
||||
ret
|
||||
endp
|
||||
|
||||
proc dec2bin
|
||||
mov edx, 0
|
||||
.next_char:
|
||||
movzx eax, byte[esi]
|
||||
test eax, eax
|
||||
jz .done
|
||||
sub eax, '0'
|
||||
jb .done
|
||||
cmp eax, 9
|
||||
ja .done
|
||||
inc esi
|
||||
imul edx, 10
|
||||
add edx, eax
|
||||
jmp .next_char
|
||||
.done:
|
||||
mov eax, edx
|
||||
ret
|
||||
endp
|
||||
|
||||
proc parse_option
|
||||
mov ebx, config_options-3*4
|
||||
.try_next_option:
|
||||
add ebx, 3*4
|
||||
mov edi, esi
|
||||
mov edx, [ebx] ; option name
|
||||
test edx, edx
|
||||
jz .done
|
||||
.next_char:
|
||||
cmp byte[edx], 0
|
||||
jnz @f
|
||||
cmp byte[edi], '='
|
||||
jz .opt_name_ok
|
||||
@@:
|
||||
cmp byte[edi], 0
|
||||
jz .done
|
||||
movzx eax, byte[edi]
|
||||
cmp [edx], al
|
||||
jnz .try_next_option
|
||||
inc edi
|
||||
inc edx
|
||||
jmp .next_char
|
||||
.opt_name_ok:
|
||||
inc edi
|
||||
mov esi, edi
|
||||
call dword[ebx+4]
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc parse_line
|
||||
.next_line:
|
||||
cmp byte[esi], 0
|
||||
jz .done
|
||||
cmp byte[esi], 0xd ; '\r'
|
||||
jz .skip
|
||||
cmp byte[esi], 0xa ; '\n'
|
||||
jz .skip
|
||||
cmp byte[esi], '#'
|
||||
jz .skip
|
||||
call parse_option
|
||||
call skip_line
|
||||
jmp .next_line
|
||||
.skip:
|
||||
call skip_line
|
||||
jmp .next_line
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc cfg_opt_func_resolution
|
||||
call dec2bin
|
||||
xor edx, edx
|
||||
mov [edx+BOOT_LO.x_res], ax
|
||||
cmp byte[esi], 'x'
|
||||
jz @f
|
||||
cmp byte[esi], '*'
|
||||
jz @f
|
||||
jmp .done
|
||||
@@:
|
||||
inc esi
|
||||
call dec2bin
|
||||
xor edx, edx
|
||||
mov [edx+BOOT_LO.y_res], ax
|
||||
mov [cfg_opt_used_resolution], 1
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc cfg_opt_func_acpi
|
||||
call dec2bin
|
||||
mov [cfg_opt_used_acpi], 1
|
||||
mov [cfg_opt_value_acpi], al
|
||||
ret
|
||||
endp
|
||||
|
||||
proc cfg_opt_func_debug_print
|
||||
call dec2bin
|
||||
mov [cfg_opt_used_debug_print], 1
|
||||
mov [cfg_opt_value_debug_print], al
|
||||
ret
|
||||
endp
|
||||
|
||||
proc cfg_opt_func_launcher_start
|
||||
call dec2bin
|
||||
mov [cfg_opt_used_launcher_start], 1
|
||||
mov [cfg_opt_value_launcher_start], al
|
||||
ret
|
||||
endp
|
||||
|
||||
proc cfg_opt_func_mtrr
|
||||
call dec2bin
|
||||
mov [cfg_opt_used_mtrr], 1
|
||||
mov [cfg_opt_value_mtrr], al
|
||||
ret
|
||||
endp
|
||||
|
||||
proc cfg_opt_func_ask_params
|
||||
call dec2bin
|
||||
mov [cfg_opt_used_ask_params], 1
|
||||
mov [cfg_opt_value_ask_params], al
|
||||
ret
|
||||
endp
|
||||
|
||||
proc cfg_opt_func_imgfrom
|
||||
call dec2bin
|
||||
mov [cfg_opt_used_imgfrom], 1
|
||||
mov [cfg_opt_value_imgfrom], al
|
||||
ret
|
||||
endp
|
||||
|
||||
proc cfg_opt_func_syspath
|
||||
mov edi, cfg_opt_value_syspath
|
||||
.next_char:
|
||||
movzx eax, byte[esi]
|
||||
cmp al, 0xd ; \r
|
||||
jz .done
|
||||
cmp al, 0xa ; \n
|
||||
jz .done
|
||||
inc esi
|
||||
stosb
|
||||
jmp .next_char
|
||||
.done:
|
||||
mov byte[edi], 0
|
||||
ret
|
||||
endp
|
||||
|
||||
proc parse_config stdcall uses ebx esi edi, _buffer
|
||||
; mov esi, [_buffer]
|
||||
mov esi, KERNEL_BASE
|
||||
.next_line:
|
||||
call parse_line
|
||||
cmp byte[esi], 0
|
||||
jnz .next_line
|
||||
ret
|
||||
endp
|
||||
|
||||
proc read_options_from_config stdcall uses ebx esi edi
|
||||
mov ebx, [efi_table]
|
||||
mov ebx, [ebx+EFI_SYSTEM_TABLE.BootServices]
|
||||
ccall [ebx+EFI_BOOT_SERVICES.HandleProtocol], [efi_handle], \
|
||||
lipuuid, lip_interface
|
||||
test eax, eax
|
||||
jnz .error
|
||||
mov eax, [lip_interface]
|
||||
|
||||
mov ebx, [efi_table]
|
||||
mov ebx, [ebx+EFI_SYSTEM_TABLE.BootServices]
|
||||
ccall [ebx+EFI_BOOT_SERVICES.HandleProtocol], \
|
||||
[eax+EFI_LOADED_IMAGE_PROTOCOL.DeviceHandle], sfspguid, \
|
||||
sfsp_interface
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
mov eax, [sfsp_interface]
|
||||
ccall [eax+EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume], eax, esp_root
|
||||
test eax, eax
|
||||
jnz .error
|
||||
|
||||
stdcall load_file, [esp_root], file_name, KERNEL_BASE, \
|
||||
FILE_BUFFER_SIZE, 0
|
||||
test eax, eax
|
||||
jz @f
|
||||
stdcall parse_config, KERNEL_BASE
|
||||
@@:
|
||||
.error:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc print_vmode uses eax ebx ecx esi edi, _gop_if
|
||||
mov ebx, [_gop_if]
|
||||
call clearbuf
|
||||
mov eax, [ebx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.HorizontalResolution]
|
||||
mov edi, msg
|
||||
call num2dec
|
||||
mov eax, [ebx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.VerticalResolution]
|
||||
mov edi, msg+8*2
|
||||
call num2dec
|
||||
|
||||
mov eax, [ebx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelFormat]
|
||||
mov edi, msg+16*2
|
||||
call num2dec
|
||||
|
||||
mov eax, [ebx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelsPerScanLine]
|
||||
mov edi, msg+24*2
|
||||
call num2dec
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, msg
|
||||
ret
|
||||
endp
|
||||
|
||||
proc find_vmode_index_by_resolution uses ebx esi edi
|
||||
mov [cfg_opt_value_vmode], 0
|
||||
.next_mode:
|
||||
; mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
; ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
; msg_query_vmode
|
||||
|
||||
movzx ecx, [cfg_opt_value_vmode]
|
||||
mov eax, [gop_interface]
|
||||
ccall [eax+EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode], eax, ecx, \
|
||||
gop_info_size, gop_info
|
||||
test eax, eax
|
||||
jz @f
|
||||
call clearbuf
|
||||
mov edi, msg
|
||||
call num2hex
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, msg
|
||||
jmp .skip_mode
|
||||
@@:
|
||||
mov ecx, [gop_info]
|
||||
stdcall print_vmode, ecx
|
||||
; PixelBlueGreenRedReserved8BitPerColor
|
||||
cmp [ecx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelFormat], 1
|
||||
jnz .skip_mode
|
||||
xor edx, edx
|
||||
mov eax, [ecx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.HorizontalResolution]
|
||||
cmp ax, [edx+BOOT_LO.x_res]
|
||||
jnz .skip_mode
|
||||
mov eax, [ecx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.VerticalResolution]
|
||||
cmp ax, [edx+BOOT_LO.y_res]
|
||||
jnz .skip_mode
|
||||
jmp .done
|
||||
.skip_mode:
|
||||
inc [cfg_opt_value_vmode]
|
||||
movzx eax, [cfg_opt_value_vmode]
|
||||
mov ecx, [gop_interface]
|
||||
mov edx, [ecx+EFI_GRAPHICS_OUTPUT_PROTOCOL.Mode]
|
||||
cmp eax, [edx+EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.MaxMode]
|
||||
jnz .next_mode
|
||||
mov [cfg_opt_used_resolution], 0
|
||||
mov [cfg_opt_value_ask_params], 1
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_error_no_such_vmode
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, msg_error
|
||||
jmp $
|
||||
.error:
|
||||
.done:
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_vmode_found
|
||||
ret
|
||||
endp
|
||||
|
||||
proc ask_for_params
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_ask_for_params
|
||||
jmp $
|
||||
.error:
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
main:
|
||||
mov esi, [esp+4]
|
||||
mov [efi_handle], esi
|
||||
mov esi, [esp+8]
|
||||
mov [efi_table], esi
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset], eax, 1
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_u4k_loaded
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_read_options
|
||||
call read_options_from_config
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_load_kernel
|
||||
stdcall load_file, [esp_root], kernel_name, KERNEL_BASE, MAX_FILE_SIZE, 1
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_load_ramdisk
|
||||
stdcall load_file, [esp_root], ramdisk_name, RAMDISK_BASE, MAX_FILE_SIZE, 1
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_alloc_devicesdat
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.BootServices]
|
||||
ccall [eax+EFI_BOOT_SERVICES.AllocatePages], \
|
||||
EFI_ALLOCATE_MAX_ADDRESS, EFI_RESERVED_MEMORY_TYPE, 1, \
|
||||
devicesdat_data
|
||||
call halt_on_error
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_load_devicesdat
|
||||
|
||||
ccall load_file, [esp_root], devicesdat_name, [devicesdat_data], \
|
||||
[devicesdat_size], 0
|
||||
mov [devicesdat_size], eax
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_locate_gop_handlers
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.BootServices]
|
||||
ccall [eax+EFI_BOOT_SERVICES.LocateHandle], \
|
||||
EFI_LOCATE_SEARCH_TYPE.ByProtocol, gopuuid, 0, \
|
||||
gop_buffer_size, gop_buffer
|
||||
mov [status], eax
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_gop_buffer_size
|
||||
call clearbuf
|
||||
mov eax, [gop_buffer_size]
|
||||
mov edi, msg
|
||||
call num2hex
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, msg
|
||||
|
||||
mov eax, [status]
|
||||
call halt_on_error
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_look_for_gop_handler
|
||||
|
||||
mov ebx, gop_buffer
|
||||
.next_gop_handle:
|
||||
mov eax, ebx
|
||||
sub eax, gop_buffer
|
||||
cmp eax, [gop_buffer_size]
|
||||
jb @f
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_error_out_of_handlers
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, msg_error
|
||||
jmp $
|
||||
@@:
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_query_handler
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.BootServices]
|
||||
ccall [eax+EFI_BOOT_SERVICES.HandleProtocol], \
|
||||
[ebx], gopuuid, gop_interface
|
||||
;mov eax, 0x80000003
|
||||
test eax, eax
|
||||
jz @f
|
||||
call clearbuf
|
||||
mov edi, msg
|
||||
call num2hex
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, msg
|
||||
|
||||
add ebx, 4
|
||||
jmp .next_gop_handle
|
||||
@@:
|
||||
|
||||
call find_rsdp
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_acpi_tables_done
|
||||
|
||||
cmp [cfg_opt_used_resolution], 0
|
||||
jz .not_used_resolution
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_opt_resolution
|
||||
call clearbuf
|
||||
xor edx, edx
|
||||
movzx eax, [edx+BOOT_LO.x_res]
|
||||
mov edi, msg
|
||||
call num2dec
|
||||
xor edx, edx
|
||||
movzx eax, [edx+BOOT_LO.y_res]
|
||||
mov edi, msg+8*2
|
||||
call num2dec
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, msg
|
||||
|
||||
call find_vmode_index_by_resolution
|
||||
.not_used_resolution:
|
||||
cmp [cfg_opt_used_debug_print], 0
|
||||
jz .not_used_debug_print
|
||||
movzx eax, [cfg_opt_value_debug_print]
|
||||
xor edx, edx
|
||||
mov [edx+BOOT_LO.debug_print], al
|
||||
.not_used_debug_print:
|
||||
|
||||
cmp [cfg_opt_value_ask_params], 0
|
||||
jz @f
|
||||
call ask_for_params
|
||||
@@:
|
||||
|
||||
movzx ecx, [cfg_opt_value_vmode]
|
||||
mov eax, [gop_interface]
|
||||
ccall [eax+EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode], eax, ecx
|
||||
call halt_on_error
|
||||
|
||||
mov ecx, [gop_interface]
|
||||
mov edx, [ecx+EFI_GRAPHICS_OUTPUT_PROTOCOL.Mode]
|
||||
mov edi, [edx+EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.FrameBufferBase.lo]
|
||||
mov [fb_base], edi
|
||||
|
||||
|
||||
mov ebx, [edx+EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.Mode]
|
||||
mov eax, [gop_interface]
|
||||
ccall [eax+EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode], eax, ebx, \
|
||||
gop_info_size, gop_info
|
||||
test eax, eax
|
||||
jnz .error
|
||||
mov ecx, [gop_info]
|
||||
mov eax, [ecx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.HorizontalResolution]
|
||||
xor edx, edx
|
||||
mov [edx+BOOT_LO.x_res], ax
|
||||
mov eax, [ecx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.VerticalResolution]
|
||||
mov [edx+BOOT_LO.y_res], ax
|
||||
mov eax, [ecx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelsPerScanLine]
|
||||
shl eax, 2
|
||||
mov [edx+BOOT_LO.pitch], ax
|
||||
|
||||
mov byte[edx+BOOT_LO.pci_data+0], 1 ; PCI access mechanism
|
||||
mov byte[edx+BOOT_LO.pci_data+1], 8 ; last bus, don't know how to count them
|
||||
mov byte[edx+BOOT_LO.pci_data+2], 0x10 ; PCI version
|
||||
mov byte[edx+BOOT_LO.pci_data+3], 0x02
|
||||
mov dword[edx+BOOT_LO.pci_data+4], 0xe3
|
||||
|
||||
; kernel
|
||||
; eficall BootServices, AllocatePages, EFI_RESERVED_MEMORY_TYPE, \
|
||||
; 450000/0x1000, EFI_ALLOCATE_ADDRESS
|
||||
|
||||
; ramdisk
|
||||
; eficall BootServices, AllocatePages, EFI_RESERVED_MEMORY_TYPE, \
|
||||
; 2880*512/0x1000, EFI_ALLOCATE_ADDRESS
|
||||
|
||||
call calc_memmap
|
||||
; call dump_memmap
|
||||
|
||||
mov eax, [efi_table]
|
||||
mov eax, [eax+EFI_SYSTEM_TABLE.BootServices]
|
||||
ccall [eax+EFI_BOOT_SERVICES.ExitBootServices], [efi_handle], \
|
||||
[memory_map_key]
|
||||
call halt_on_error
|
||||
|
||||
cli
|
||||
|
||||
xor edx, edx
|
||||
xor esi, esi
|
||||
mov [esi+BOOT_LO.bpp], 32
|
||||
mov [esi+BOOT_LO.vesa_mode], dx
|
||||
mov [esi+BOOT_LO.bank_switch], edx
|
||||
mov edi, [fb_base]
|
||||
mov [esi+BOOT_LO.lfb], edi
|
||||
|
||||
movzx eax, [cfg_opt_value_mtrr]
|
||||
mov [esi+BOOT_LO.mtrr], al
|
||||
|
||||
movzx eax, [cfg_opt_value_launcher_start]
|
||||
mov [esi+BOOT_LO.launcher_start], al
|
||||
|
||||
movzx eax, [cfg_opt_value_debug_print]
|
||||
mov [esi+BOOT_LO.debug_print], al
|
||||
|
||||
mov [esi+BOOT_LO.dma], dl
|
||||
; mov qword[esi+BOOT_LO.pci_data], 0
|
||||
mov [esi+BOOT_LO.apm_entry], edx
|
||||
mov [esi+BOOT_LO.apm_version], dx
|
||||
mov [esi+BOOT_LO.apm_flags], dx
|
||||
mov [esi+BOOT_LO.apm_code_32], dx
|
||||
mov [esi+BOOT_LO.apm_code_16], dx
|
||||
mov [esi+BOOT_LO.apm_data_16], dx
|
||||
mov [esi+BOOT_LO.bios_hd_cnt], dl
|
||||
|
||||
movzx eax, [cfg_opt_value_imgfrom]
|
||||
mov [esi+BOOT_LO.rd_load_from], al
|
||||
|
||||
mov eax, dword[devicesdat_size]
|
||||
mov [edx+BOOT_LO.devicesdat_size], eax
|
||||
mov eax, dword[devicesdat_data]
|
||||
mov [edx+BOOT_LO.devicesdat_data], eax
|
||||
|
||||
mov esi, cfg_opt_value_syspath
|
||||
mov edi, BOOT_LO.syspath
|
||||
mov ecx, 0x17
|
||||
rep movsb
|
||||
|
||||
lgdt [cs:GDTR]
|
||||
|
||||
mov ax, DATA_32_SELECTOR
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, ax
|
||||
mov gs, ax
|
||||
mov ss, ax
|
||||
|
||||
push CODE_32_SELECTOR
|
||||
lea eax, [.next]
|
||||
push eax
|
||||
retf
|
||||
|
||||
.next:
|
||||
mov eax, cr0
|
||||
and eax, not CR0_PG
|
||||
mov cr0, eax
|
||||
|
||||
mov eax, cr4
|
||||
and eax, not CR4_PAE
|
||||
mov cr4, eax
|
||||
|
||||
push KERNEL_BASE
|
||||
retn
|
||||
|
||||
.error:
|
||||
mov esi, [efi_table]
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_error
|
||||
jmp $
|
||||
|
||||
halt_on_error:
|
||||
test eax, eax
|
||||
jz @f
|
||||
call clearbuf
|
||||
mov edi, msg
|
||||
call num2hex
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_error
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, msg
|
||||
jmp $
|
||||
@@:
|
||||
ret
|
||||
|
||||
proc find_rsdp
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_look_for_rsdp
|
||||
|
||||
mov edi, [esi+EFI_SYSTEM_TABLE.ConfigurationTable]
|
||||
mov ecx, [esi+EFI_SYSTEM_TABLE.NumberOfTableEntries]
|
||||
.next_table:
|
||||
dec ecx
|
||||
js .all_tables_done
|
||||
; EFI_ACPI_TABLE_GUID
|
||||
cmp dword[edi+EFI_CONFIGURATION_TABLE.VendorGUID+0x0], 0x8868e871
|
||||
jnz .not_acpi20
|
||||
cmp dword[edi+EFI_CONFIGURATION_TABLE.VendorGUID+0x4], 0x11d3e4f1
|
||||
jnz .not_acpi20
|
||||
cmp dword[edi+EFI_CONFIGURATION_TABLE.VendorGUID+0x8], 0x800022bc
|
||||
jnz .not_acpi20
|
||||
cmp dword[edi+EFI_CONFIGURATION_TABLE.VendorGUID+0xc], 0x81883cc7
|
||||
jnz .not_acpi20
|
||||
mov eax, [edi+EFI_CONFIGURATION_TABLE.VendorTable]
|
||||
mov edx, BOOT_LO.acpi_rsdp
|
||||
mov [edx], eax
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.ConOut]
|
||||
ccall [eax+EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString], eax, \
|
||||
msg_rsdp_found
|
||||
jmp .all_tables_done
|
||||
.not_acpi20:
|
||||
add edi, sizeof.EFI_CONFIGURATION_TABLE
|
||||
jmp .next_table
|
||||
.all_tables_done:
|
||||
ret
|
||||
endp
|
||||
|
||||
proc calc_memmap
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.BootServices]
|
||||
ccall [eax+EFI_BOOT_SERVICES.AllocatePages], EFI_ALLOCATE_ANY_PAGES, \
|
||||
EFI_RESERVED_MEMORY_TYPE, MEMORY_MAP_SIZE/0x1000, memory_map
|
||||
call halt_on_error
|
||||
|
||||
mov eax, [esi+EFI_SYSTEM_TABLE.BootServices]
|
||||
ccall [eax+EFI_BOOT_SERVICES.GetMemoryMap], memory_map_size, \
|
||||
[memory_map], memory_map_key, descriptor_size, descriptor_ver
|
||||
call halt_on_error
|
||||
|
||||
push esi
|
||||
mov edi, BOOT_LO.memmap_blocks
|
||||
mov dword[edi-4], 0 ; memmap_block_cnt
|
||||
mov esi, [memory_map]
|
||||
mov ebx, esi
|
||||
add ebx, [memory_map_size]
|
||||
.next_descr:
|
||||
call add_uefi_memmap
|
||||
add esi, [descriptor_size]
|
||||
cmp esi, ebx
|
||||
jb .next_descr
|
||||
pop esi
|
||||
ret
|
||||
endp
|
||||
|
||||
; linux/arch/x86/platform/efi/efi.c
|
||||
; do_add_efi_memmap
|
||||
proc add_uefi_memmap
|
||||
cmp [BOOT_LO.memmap_block_cnt], MAX_MEMMAP_BLOCKS
|
||||
jz .done
|
||||
|
||||
mov eax, [esi+EFI_MEMORY_DESCRIPTOR.PhysicalStart.lo]
|
||||
mov edx, [esi+EFI_MEMORY_DESCRIPTOR.PhysicalStart.hi]
|
||||
mov [edi+e820entry.addr.lo], eax
|
||||
mov [edi+e820entry.addr.hi], edx
|
||||
|
||||
mov eax, [esi+EFI_MEMORY_DESCRIPTOR.NumberOfPages.lo]
|
||||
mov edx, [esi+EFI_MEMORY_DESCRIPTOR.NumberOfPages.hi]
|
||||
shld edx, eax, 12
|
||||
shl eax, 12
|
||||
mov [edi+e820entry.size.lo], eax
|
||||
mov [edi+e820entry.size.hi], edx
|
||||
|
||||
mov ecx, [esi+EFI_MEMORY_DESCRIPTOR.Type]
|
||||
cmp ecx, EFI_LOADER_CODE
|
||||
jz .mem_ram_if_wb
|
||||
cmp ecx, EFI_LOADER_DATA
|
||||
jz .mem_ram_if_wb
|
||||
cmp ecx, EFI_BOOT_SERVICES_CODE
|
||||
jz .mem_ram_if_wb
|
||||
cmp ecx, EFI_BOOT_SERVICES_DATA
|
||||
jz .mem_ram_if_wb
|
||||
cmp ecx, EFI_CONVENTIONAL_MEMORY
|
||||
jz .mem_ram_if_wb
|
||||
cmp ecx, EFI_ACPI_RECLAIM_MEMORY
|
||||
mov eax, E820_ACPI
|
||||
jz .type_done
|
||||
cmp ecx, EFI_ACPI_MEMORY_NVS
|
||||
mov eax, E820_NVS
|
||||
jz .type_done
|
||||
cmp ecx, EFI_UNUSABLE_MEMORY
|
||||
mov eax, E820_UNUSABLE
|
||||
jz .type_done
|
||||
cmp ecx, EFI_PERSISTENT_MEMORY
|
||||
mov eax, E820_PMEM
|
||||
jz .type_done
|
||||
jmp .reserved
|
||||
.mem_ram_if_wb:
|
||||
test [esi+EFI_MEMORY_DESCRIPTOR.Attribute.lo], EFI_MEMORY_WB
|
||||
mov eax, E820_RAM
|
||||
jnz .type_done
|
||||
.reserved:
|
||||
mov eax, E820_RESERVED
|
||||
.type_done:
|
||||
mov [edi+e820entry.type], eax
|
||||
cmp eax, E820_RAM
|
||||
jnz @f
|
||||
inc [BOOT_LO.memmap_block_cnt]
|
||||
add edi, sizeof.e820entry
|
||||
@@:
|
||||
.done:
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
proc num2dec
|
||||
pushad
|
||||
|
||||
xor ecx, ecx
|
||||
mov ebx, 10
|
||||
.next_digit:
|
||||
xor edx, edx
|
||||
div ebx
|
||||
push edx
|
||||
inc ecx
|
||||
test eax, eax
|
||||
jnz .next_digit
|
||||
|
||||
.next_char:
|
||||
pop eax
|
||||
add eax, '0'
|
||||
stosw
|
||||
loop .next_char
|
||||
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
proc num2hex
|
||||
pushad
|
||||
|
||||
xchg edx, eax
|
||||
mov ecx, 8
|
||||
.next_tetra:
|
||||
rol edx, 4
|
||||
movzx eax, dl
|
||||
and eax, 0x0f
|
||||
movzx eax, byte[hex+eax]
|
||||
stosw
|
||||
loop .next_tetra
|
||||
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
hex db '0123456789ABCDEF'
|
||||
|
||||
proc clearbuf
|
||||
pushad
|
||||
mov eax, 0x0020
|
||||
mov ecx, 79
|
||||
mov edi, msg
|
||||
rep stosw
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
section '.rodata' data readable
|
||||
align 16
|
||||
GDTR:
|
||||
dw 3*8-1
|
||||
dq GDT
|
||||
align 16
|
||||
GDT:
|
||||
dw 0, 0, 0, 0
|
||||
dw 0FFFFh,0,9A00h,0CFh ; 32-bit code
|
||||
dw 0FFFFh,0,9200h,0CFh ; flat data
|
||||
|
||||
gopuuid db EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID
|
||||
lipuuid db EFI_LOADED_IMAGE_PROTOCOL_GUID
|
||||
sfspguid db EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID
|
||||
|
||||
file_name du "\EFI\KOLIBRIOS\KOLIBRI.INI",0
|
||||
kernel_name du "\EFI\KOLIBRIOS\KOLIBRI.KRN",0
|
||||
ramdisk_name du "\EFI\KOLIBRIOS\KOLIBRI.IMG",0
|
||||
devicesdat_name du "\EFI\KOLIBRIOS\DEVICES.DAT",0
|
||||
|
||||
config_options dd cfg_opt_name_resolution, cfg_opt_func_resolution, \
|
||||
cfg_opt_cmnt_resolution, \
|
||||
cfg_opt_name_acpi, cfg_opt_func_acpi, cfg_opt_cmnt_acpi, \
|
||||
cfg_opt_name_debug_print, cfg_opt_func_debug_print, \
|
||||
cfg_opt_cmnt_debug_print, \
|
||||
cfg_opt_name_launcher_start, cfg_opt_func_launcher_start, \
|
||||
cfg_opt_cmnt_launcher_start, \
|
||||
cfg_opt_name_mtrr, cfg_opt_func_mtrr, cfg_opt_cmnt_mtrr, \
|
||||
cfg_opt_name_ask_params, cfg_opt_func_ask_params, \
|
||||
cfg_opt_cmnt_ask_params, \
|
||||
cfg_opt_name_imgfrom, cfg_opt_func_imgfrom, \
|
||||
cfg_opt_cmnt_imgfrom, \
|
||||
cfg_opt_name_syspath, cfg_opt_func_syspath, \
|
||||
cfg_opt_cmnt_syspath, \
|
||||
0
|
||||
|
||||
cfg_opt_name_resolution db "resolution",0
|
||||
cfg_opt_name_acpi db "acpi",0
|
||||
cfg_opt_name_debug_print db "debug_print",0
|
||||
cfg_opt_name_launcher_start db "launcher_start",0
|
||||
cfg_opt_name_mtrr db "mtrr",0
|
||||
cfg_opt_name_ask_params db "ask_params",0
|
||||
cfg_opt_name_imgfrom db "imgfrom",0
|
||||
cfg_opt_name_syspath db "syspath",0
|
||||
|
||||
cfg_opt_cmnt_resolution db "# Graphic mode",0
|
||||
cfg_opt_cmnt_acpi db "# ACPI settings",0xa, \
|
||||
"# 0: don't use",0xa, \
|
||||
"# 1: parse ACPI tables",0xa, \
|
||||
"# 2: + call _PIC method",0xa, \
|
||||
"# 3: + get APIC interrupts",0xa,0
|
||||
cfg_opt_cmnt_debug_print db "# Duplicate debug output to the screen",0
|
||||
cfg_opt_cmnt_launcher_start db "# Start LAUNCHER app after kernel is loaded",0
|
||||
cfg_opt_cmnt_mtrr db "# Configure MTRR's",0
|
||||
cfg_opt_cmnt_ask_params db "# Interrupt booting to ask the user for boot", \
|
||||
" params",0
|
||||
cfg_opt_cmnt_imgfrom db "# Where to load ramdisk image from",0
|
||||
cfg_opt_cmnt_syspath db "# Path to /sys directory",0
|
||||
|
||||
msg_u4k_loaded du "uefi32kos loaded",13,10,0
|
||||
msg_read_options du "Read options from config file",13,10,0
|
||||
msg_load_kernel du "Load kernel",13,10,0
|
||||
msg_load_ramdisk du "Load ramdisk",13,10,0
|
||||
msg_load_devicesdat du "Load DEVICES.DAT",13,10,0
|
||||
msg_alloc_devicesdat du "Allocate memory for DEVICES.DAT",13,10,0
|
||||
msg_locate_gop_handlers du "Locate GOP handlers",13,10,0
|
||||
msg_look_for_gop_handler du "Look for GOP handler",13,10,0
|
||||
msg_query_handler du "Query handler",13,10,0
|
||||
msg_query_vmode du "Query vmode",13,10,0
|
||||
msg_vmode_found du "Video mode found",13,10,0
|
||||
msg_look_for_rsdp du "Look for RSDP",13,10,0
|
||||
msg_rsdp_found du "RSDP found",13,10,0
|
||||
msg_acpi_tables_done du "ACPI tables done",13,10,0
|
||||
msg_ask_for_params du "Ask for params",13,10,0
|
||||
msg_set_graphic_mode du "Set graphic mode",13,10,0
|
||||
msg_success du "Success!",13,10,0
|
||||
msg_gop_buffer_size du "GOP buffer size",13,10,0
|
||||
msg_opt_resolution du "option resolution: ",0
|
||||
msg_error du "Error!",13,10,0
|
||||
msg_error_no_such_vmode du "No such vmode",13,10,0
|
||||
msg_error_out_of_handlers du "Out of handlers",13,10,0
|
||||
msg_error_open_file du "Error: can't open file ",0
|
||||
msg du 79 dup " ",13,10,0
|
||||
|
||||
|
||||
section '.data' data readable writeable
|
||||
efi_handle dd 0
|
||||
efi_table dd 0
|
||||
|
||||
fb_base dd 0
|
||||
|
||||
gop_buffer_size dd GOP_BUFFER_SIZE
|
||||
gop_handle dd 0
|
||||
gop_interface dd 0
|
||||
gop_info_size dd 0
|
||||
gop_info dd 0
|
||||
|
||||
lip_buffer_size dd LIP_BUFFER_SIZE
|
||||
lip_handle dd 0
|
||||
lip_interface dd 0
|
||||
|
||||
sfsp_interface dd 0
|
||||
|
||||
esp_root dd ?
|
||||
file_handle dd ?
|
||||
file_buffer_size dd FILE_BUFFER_SIZE-1 ; leave the last byte for \0
|
||||
|
||||
cfg_opt_used_resolution db 0
|
||||
cfg_opt_used_acpi db 0
|
||||
cfg_opt_used_debug_print db 0
|
||||
cfg_opt_used_launcher_start db 0
|
||||
cfg_opt_used_mtrr db 0
|
||||
cfg_opt_used_ask_params db 0
|
||||
cfg_opt_used_imgfrom db 0
|
||||
cfg_opt_used_syspath db 0
|
||||
|
||||
cfg_opt_value_vmode db 0
|
||||
cfg_opt_value_acpi db 0
|
||||
cfg_opt_value_debug_print db 0
|
||||
cfg_opt_value_launcher_start db 1
|
||||
cfg_opt_value_mtrr db 0
|
||||
cfg_opt_value_ask_params db 0
|
||||
cfg_opt_value_imgfrom db RD_LOAD_FROM_MEMORY
|
||||
cfg_opt_value_syspath db "/RD/1",0
|
||||
rb 20
|
||||
|
||||
memory_map_key dd 0
|
||||
descriptor_size dd 0
|
||||
descriptor_ver dd 0
|
||||
memory_map_size dd MEMORY_MAP_SIZE
|
||||
|
||||
efi_fs_info_id db EFI_FILE_SYSTEM_INFO_ID
|
||||
efi_fs_info_size dq sizeof.EFI_FILE_SYSTEM_INFO
|
||||
efi_fs_info EFI_FILE_SYSTEM_INFO
|
||||
|
||||
memory_map dd ?
|
||||
gop_buffer rd GOP_BUFFER_SIZE/4
|
||||
devicesdat_data dd 0xffffffff
|
||||
devicesdat_size dd 0x1000
|
||||
status dd ?
|
||||
|
||||
section '.reloc' fixups data discardable
|
||||
196
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi64.inc
Normal file
196
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi64.inc
Normal file
@@ -0,0 +1,196 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2020. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; Version 2, or (at your option) any later version. ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Based on UEFI library for fasm by bzt, Public Domain. ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
DN fix dq ; native
|
||||
|
||||
include "uefi.inc"
|
||||
|
||||
EFIERR = 0x8000000000000000
|
||||
|
||||
struct EFI_SYSTEM_TABLE
|
||||
Hdr EFI_TABLE_HEADER
|
||||
FirmwareVendor dq ?
|
||||
FirmwareRevision dd ?
|
||||
dd ?
|
||||
ConsoleInHandle dq ?
|
||||
ConIn dq ?
|
||||
ConsoleOutHandle dq ?
|
||||
ConOut dq ?
|
||||
StandardErrorHandle dq ?
|
||||
StdErr dq ?
|
||||
RuntimeServices dq ?
|
||||
BootServices dq ?
|
||||
NumberOfTableEntries dq ?
|
||||
ConfigurationTable dq ?
|
||||
ends
|
||||
|
||||
struct EFI_LOADED_IMAGE_PROTOCOL
|
||||
Revision dd ?
|
||||
dd ?
|
||||
ParentHandle dq ?
|
||||
SystemTable dq ?
|
||||
DeviceHandle dq ?
|
||||
FilePath dq ?
|
||||
Reserved dq ?
|
||||
LoadOptionsSize dd ?
|
||||
dd ?
|
||||
ImageBase dq ?
|
||||
ImageSize dq ?
|
||||
ImageCodeType dd ?
|
||||
ImageDataType dd ?
|
||||
UnLoad dq ?
|
||||
ends
|
||||
|
||||
macro eficall interface,function,arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9,arg10,arg11
|
||||
{
|
||||
numarg = 0
|
||||
|
||||
if ~ arg11 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg11 eq rdi
|
||||
mov rdi, arg11
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg10 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg10 eq rsi
|
||||
mov rsi, arg10
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg9 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg9 eq r14
|
||||
mov r14, arg9
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg8 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg8 eq r13
|
||||
mov r13, arg8
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg7 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg7 eq r12
|
||||
mov r12, arg7
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg6 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg6 eq r11
|
||||
mov r11, arg6
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg5 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg5 eq r10
|
||||
mov r10, arg5
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg4 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg4 eq r9
|
||||
mov r9, arg4
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg3 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg3 eq r8
|
||||
mov r8, arg3
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg2 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg2 eq rdx
|
||||
mov rdx, arg2
|
||||
end if
|
||||
end if
|
||||
|
||||
if ~ arg1 eq
|
||||
numarg = numarg + 1
|
||||
if ~ arg1 eq rcx
|
||||
mov rcx, arg1
|
||||
end if
|
||||
end if
|
||||
|
||||
xor eax, eax
|
||||
mov al, numarg
|
||||
|
||||
if ~ interface eq rbx
|
||||
mov rbx, interface
|
||||
end if
|
||||
|
||||
mov rbx, [rbx + function]
|
||||
call uefifunc
|
||||
}
|
||||
|
||||
section '.text' code executable readable
|
||||
|
||||
uefifunc:
|
||||
;save stack pointer
|
||||
mov [uefi_rsptmp], rsp
|
||||
;set up new aligned stack
|
||||
and esp, 0xFFFFFFF0
|
||||
;alignment check on arguments
|
||||
bt eax, 0
|
||||
jnc @f
|
||||
push rax
|
||||
;arguments
|
||||
@@:
|
||||
cmp al, 11
|
||||
jb @f
|
||||
push rdi
|
||||
@@:
|
||||
cmp al, 10
|
||||
jb @f
|
||||
push rsi
|
||||
@@:
|
||||
cmp al, 9
|
||||
jb @f
|
||||
push r14
|
||||
@@:
|
||||
cmp al, 8
|
||||
jb @f
|
||||
push r13
|
||||
@@:
|
||||
cmp al, 7
|
||||
jb @f
|
||||
push r12
|
||||
@@:
|
||||
cmp al, 6
|
||||
jb @f
|
||||
push r11
|
||||
@@:
|
||||
cmp al, 5
|
||||
jb @f
|
||||
push r10
|
||||
@@:
|
||||
;space for
|
||||
;r9
|
||||
;r8
|
||||
;rdx
|
||||
;rcx
|
||||
sub rsp, 4*8
|
||||
;call function
|
||||
call rbx
|
||||
;restore old stack
|
||||
mov rsp, [uefi_rsptmp]
|
||||
ret
|
||||
1249
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi64kos.asm
Normal file
1249
kernel/branches/kolibri-lldw/bootloader/uefi4kos/uefi64kos.asm
Normal file
File diff suppressed because it is too large
Load Diff
39
kernel/branches/kolibri-lldw/build.bat
Normal file
39
kernel/branches/kolibri-lldw/build.bat
Normal file
@@ -0,0 +1,39 @@
|
||||
@echo off
|
||||
cls
|
||||
|
||||
call :Target_kernel
|
||||
|
||||
if ERRORLEVEL 0 goto Exit_OK
|
||||
|
||||
echo There was an error executing script.
|
||||
echo For any help, please send a report.
|
||||
pause
|
||||
goto :eof
|
||||
|
||||
:Target_kernel
|
||||
rem valid languages: en ru ge et sp
|
||||
set lang=en
|
||||
|
||||
echo *** building kernel with language '%lang%' ...
|
||||
|
||||
echo lang fix %lang% > lang.inc
|
||||
fasm -m 65536 bootbios.asm bootbios.bin
|
||||
fasm -m 65536 kernel.asm kernel.mnt
|
||||
fasm -m 65536 kernel.asm kernel.bin -dUEFI=1
|
||||
if not %errorlevel%==0 goto :Error_FasmFailed
|
||||
erase lang.inc
|
||||
goto :eof
|
||||
|
||||
|
||||
:Error_FasmFailed
|
||||
echo error: fasm execution failed
|
||||
erase lang.inc >nul 2>&1
|
||||
echo.
|
||||
pause
|
||||
exit 1
|
||||
|
||||
:Exit_OK
|
||||
echo.
|
||||
echo all operations have been done
|
||||
pause
|
||||
exit 0
|
||||
22
kernel/branches/kolibri-lldw/build.sh
Executable file
22
kernel/branches/kolibri-lldw/build.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh
|
||||
# Compile the KolibriOS kernel on Linux
|
||||
# 2017, The KolibriOS team
|
||||
|
||||
KERPACK=$HOME/kolibrios/programs/other/kpack/kerpack_linux/kerpack
|
||||
KOLIBRI_IMG=$HOME/nightly/kolibri.img
|
||||
|
||||
replace=0; # Replace kernel in the image file?
|
||||
echo 'lang fix en' > lang.inc
|
||||
fasm -m 65536 bootbios.asm bootbios.bin
|
||||
fasm -m 65536 kernel.asm kernel.mnt
|
||||
$KERPACK kernel.mnt kernel.mnt
|
||||
|
||||
[[ $replace -eq 1 ]] && {
|
||||
mntpt=$(mktemp -d)
|
||||
|
||||
sudo mount -o loop $KOLIBRI_IMG $mntpt
|
||||
sudo mount -o remount,rw $mntpt
|
||||
sudo cp kernel.mnt ${mntpt}/KERNEL.MNT
|
||||
sudo umount $mntpt
|
||||
rmdir $mntpt
|
||||
}
|
||||
119
kernel/branches/kolibri-lldw/bus/pci/PCIe.inc
Normal file
119
kernel/branches/kolibri-lldw/bus/pci/PCIe.inc
Normal file
@@ -0,0 +1,119 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2010-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; ;;
|
||||
;; PCIe.INC ;;
|
||||
;; ;;
|
||||
;; Extended PCI express services ;;
|
||||
;; ;;
|
||||
;; art_zh <artem@jerdev.co.uk> ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
;***************************************************************************
|
||||
; Function
|
||||
; pci_ext_config:
|
||||
;
|
||||
; Description
|
||||
; PCIe extended (memory-mapped) config space detection
|
||||
;
|
||||
; WARNINGs:
|
||||
; 1) Very Experimental!
|
||||
; 2) direct HT-detection (no ACPI or BIOS service used)
|
||||
; 3) Only AMD/HT processors currently supported
|
||||
;
|
||||
;***************************************************************************
|
||||
|
||||
PCIe_CONFIG_SPACE = 0xF0000000 ; to be moved to const.inc
|
||||
mmio_pcie_cfg_addr dd 0x0 ; intel pcie space may be defined here
|
||||
mmio_pcie_cfg_lim dd 0x0 ; upper pcie space address
|
||||
|
||||
|
||||
align 4
|
||||
|
||||
pci_ext_config:
|
||||
|
||||
mov ebx, [mmio_pcie_cfg_addr]
|
||||
or ebx, ebx
|
||||
jz @f
|
||||
or ebx, 0x7FFFFFFF ; required by PCI-SIG standards
|
||||
jnz .pcie_failed
|
||||
add ebx, 0x0FFFFC
|
||||
cmp ebx, [mmio_pcie_cfg_lim]; is the space limit correct?
|
||||
ja .pcie_failed
|
||||
jmp .pcie_cfg_mapped
|
||||
@@:
|
||||
mov ebx, [cpu_vendor]
|
||||
cmp ebx, dword [AMD_str]
|
||||
jne .pcie_failed
|
||||
mov bx, 0xC184 ; dev = 24, fn = 01, reg = 84h
|
||||
|
||||
.check_HT_mmio:
|
||||
mov cx, bx
|
||||
mov ax, 0x0002 ; bus = 0, 1dword to read
|
||||
call pci_read_reg
|
||||
mov bx, cx
|
||||
sub bl, 4
|
||||
and al, 0x80 ; check the NP bit
|
||||
jz .no_pcie_cfg
|
||||
shl eax, 8 ; bus:[27..20], dev:[19:15]
|
||||
or eax, 0x00007FFC ; fun:[14..12], reg:[11:2]
|
||||
mov [mmio_pcie_cfg_lim], eax
|
||||
mov cl, bl
|
||||
mov ax, 0x0002 ; bus = 0, 1dword to read
|
||||
call pci_read_reg
|
||||
mov bx, cx
|
||||
test al, 0x03 ; MMIO Base RW enabled?
|
||||
jz .no_pcie_cfg
|
||||
test al, 0x0C ; MMIO Base locked?
|
||||
jnz .no_pcie_cfg
|
||||
xor al, al
|
||||
shl eax, 8
|
||||
test eax, 0x000F0000 ; MMIO Base must be bus0-aligned
|
||||
jnz .no_pcie_cfg
|
||||
mov [mmio_pcie_cfg_addr], eax
|
||||
add eax, 0x000FFFFC
|
||||
sub eax, [mmio_pcie_cfg_lim]; MMIO must cover at least one bus
|
||||
ja .no_pcie_cfg
|
||||
|
||||
; -- it looks like a true PCIe config space;
|
||||
mov eax, [mmio_pcie_cfg_addr] ; physical address
|
||||
or eax, (PG_SHARED + PG_LARGE + PG_USER)
|
||||
mov ebx, PCIe_CONFIG_SPACE ; linear address
|
||||
mov ecx, ebx
|
||||
shr ebx, 20
|
||||
add ebx, sys_pgdir ; PgDir entry @
|
||||
@@:
|
||||
mov dword[ebx], eax ; map 4 buses
|
||||
invlpg [ecx]
|
||||
cmp bl, 4
|
||||
jz .pcie_cfg_mapped ; fix it later
|
||||
add bl, 4 ; next PgDir entry
|
||||
add eax, 0x400000 ; eax += 4M
|
||||
add ecx, 0x400000
|
||||
jmp @b
|
||||
|
||||
.pcie_cfg_mapped:
|
||||
|
||||
; -- glad to have the extended PCIe config field found
|
||||
; mov esi, boot_pcie_ok
|
||||
; call boot_log
|
||||
ret ; <<<<<<<<<<< OK >>>>>>>>>>>
|
||||
|
||||
.no_pcie_cfg:
|
||||
|
||||
xor eax, eax
|
||||
mov [mmio_pcie_cfg_addr], eax
|
||||
mov [mmio_pcie_cfg_lim], eax
|
||||
add bl, 12
|
||||
cmp bl, 0xC0 ; MMIO regs lay below this offset
|
||||
jb .check_HT_mmio
|
||||
.pcie_failed:
|
||||
; mov esi, boot_pcie_fail
|
||||
; call boot_log
|
||||
ret ; <<<<<<<<< FAILURE >>>>>>>>>
|
||||
|
||||
51
kernel/branches/kolibri-lldw/bus/pci/pci16.inc
Normal file
51
kernel/branches/kolibri-lldw/bus/pci/pci16.inc
Normal file
@@ -0,0 +1,51 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; PCI16.INC ;;
|
||||
;; ;;
|
||||
;; 16 bit PCI driver code ;;
|
||||
;; ;;
|
||||
;; Version 0.2 December 21st, 2002 ;;
|
||||
;; ;;
|
||||
;; Author: Victor Prodan, victorprodan@yahoo.com ;;
|
||||
;; ;;
|
||||
;; See file COPYING for details ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
init_pci_16:
|
||||
|
||||
pushad
|
||||
|
||||
xor ax, ax
|
||||
mov es, ax
|
||||
mov byte [es:BOOT_LO.pci_data], 1;default mechanism:1
|
||||
mov ax, 0xb101
|
||||
int 0x1a
|
||||
or ah, ah
|
||||
jnz pci16skip
|
||||
|
||||
mov [es:BOOT_LO.pci_data+1], cl;last PCI bus in system
|
||||
mov word[es:BOOT_LO.pci_data+2], bx
|
||||
mov dword[es:BOOT_LO.pci_data+4], edi
|
||||
|
||||
; we have a PCI BIOS, so check which configuration mechanism(s)
|
||||
; it supports
|
||||
; AL = PCI hardware characteristics (bit0 => mechanism1, bit1 => mechanism2)
|
||||
test al, 1
|
||||
jnz pci16skip
|
||||
test al, 2
|
||||
jz pci16skip
|
||||
mov byte [es:BOOT_LO.pci_data], 2; if (al&3)==2 => mechanism 2
|
||||
|
||||
pci16skip:
|
||||
|
||||
mov ax, 0x1000
|
||||
mov es, ax
|
||||
|
||||
popad
|
||||
679
kernel/branches/kolibri-lldw/bus/pci/pci32.inc
Normal file
679
kernel/branches/kolibri-lldw/bus/pci/pci32.inc
Normal file
@@ -0,0 +1,679 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;; ;;
|
||||
;; PCI32.INC ;;
|
||||
;; ;;
|
||||
;; 32 bit PCI driver code ;;
|
||||
;; ;;
|
||||
;; Version 0.3 April 9, 2007 ;;
|
||||
;; Version 0.2 December 21st, 2002 ;;
|
||||
;; ;;
|
||||
;; Author: Victor Prodan, victorprodan@yahoo.com ;;
|
||||
;; Mihailov Ilia, ghost.nsk@gmail.com ;;
|
||||
;; Credits: ;;
|
||||
;; Ralf Brown ;;
|
||||
;; Mike Hibbett, mikeh@oceanfree.net ;;
|
||||
;; ;;
|
||||
;; See file COPYING for details ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
;***************************************************************************
|
||||
; Function
|
||||
; pci_api:
|
||||
;
|
||||
; Description
|
||||
; entry point for system PCI calls
|
||||
;***************************************************************************
|
||||
;mmio_pci_addr = 0x400 ; set actual PCI address here to activate user-MMIO
|
||||
|
||||
iglobal
|
||||
align 4
|
||||
f62call:
|
||||
dd pci_fn_0
|
||||
dd pci_fn_1
|
||||
dd pci_fn_2
|
||||
dd pci_service_not_supported ;3
|
||||
dd pci_read_reg ;4 byte
|
||||
dd pci_read_reg ;5 word
|
||||
dd pci_read_reg ;6 dword
|
||||
dd pci_service_not_supported ;7
|
||||
dd pci_write_reg ;8 byte
|
||||
dd pci_write_reg ;9 word
|
||||
dd pci_write_reg ;10 dword
|
||||
if defined mmio_pci_addr
|
||||
dd pci_mmio_init ;11
|
||||
dd pci_mmio_map ;12
|
||||
dd pci_mmio_unmap ;13
|
||||
end if
|
||||
|
||||
endg
|
||||
|
||||
align 4
|
||||
|
||||
pci_api:
|
||||
|
||||
;cross
|
||||
mov eax, ebx
|
||||
mov ebx, ecx
|
||||
mov ecx, edx
|
||||
|
||||
cmp [pci_access_enabled], 1
|
||||
jne pci_service_not_supported
|
||||
|
||||
movzx edx, al
|
||||
|
||||
if defined mmio_pci_addr
|
||||
cmp al, 13
|
||||
ja pci_service_not_supported
|
||||
else
|
||||
cmp al, 10
|
||||
ja pci_service_not_supported
|
||||
end if
|
||||
|
||||
call dword [f62call+edx*4]
|
||||
mov dword [esp+32], eax
|
||||
ret
|
||||
|
||||
|
||||
align 4
|
||||
pci_api_drv:
|
||||
|
||||
cmp [pci_access_enabled], 1
|
||||
jne .fail
|
||||
|
||||
cmp eax, 2
|
||||
ja .fail
|
||||
|
||||
jmp dword [f62call+eax*4]
|
||||
|
||||
.fail:
|
||||
or eax, -1
|
||||
ret
|
||||
|
||||
|
||||
;; ============================================
|
||||
|
||||
pci_fn_0:
|
||||
; PCI function 0: get pci version (AH.AL)
|
||||
movzx eax, word [BOOT.pci_data+2]
|
||||
ret
|
||||
|
||||
pci_fn_1:
|
||||
; PCI function 1: get last bus in AL
|
||||
mov al, [BOOT.pci_data+1]
|
||||
ret
|
||||
|
||||
pci_fn_2:
|
||||
; PCI function 2: get pci access mechanism
|
||||
mov al, [BOOT.pci_data]
|
||||
ret
|
||||
|
||||
pci_service_not_supported:
|
||||
or eax, -1
|
||||
mov dword [esp+32], eax
|
||||
ret
|
||||
|
||||
;***************************************************************************
|
||||
; Function
|
||||
; pci_make_config_cmd
|
||||
;
|
||||
; Description
|
||||
; creates a command dword for use with the PCI bus
|
||||
; bus # in ah
|
||||
; device+func in bh (dddddfff)
|
||||
; register in bl
|
||||
;
|
||||
; command dword returned in eax ( 10000000 bbbbbbbb dddddfff rrrrrr00 )
|
||||
;***************************************************************************
|
||||
|
||||
align 4
|
||||
|
||||
pci_make_config_cmd:
|
||||
shl eax, 8 ; move bus to bits 16-23
|
||||
mov ax, bx ; combine all
|
||||
and eax, 0xffffff
|
||||
or eax, 0x80000000
|
||||
ret
|
||||
|
||||
;***************************************************************************
|
||||
; Function
|
||||
; pci_read_reg:
|
||||
;
|
||||
; Description
|
||||
; read a register from the PCI config space into EAX/AX/AL
|
||||
; IN: ah=bus,device+func=bh,register address=bl
|
||||
; number of bytes to read (1,2,4) coded into AL, bits 0-1
|
||||
; (0 - byte, 1 - word, 2 - dword)
|
||||
;***************************************************************************
|
||||
|
||||
align 4
|
||||
|
||||
pci_read_reg:
|
||||
push ebx esi
|
||||
cmp byte [BOOT.pci_data], 2;what mechanism will we use?
|
||||
je pci_read_reg_2
|
||||
|
||||
; mechanism 1
|
||||
mov esi, eax ; save register size into ESI
|
||||
and esi, 3
|
||||
|
||||
call pci_make_config_cmd
|
||||
mov ebx, eax
|
||||
mov dx, 0xcf8
|
||||
; set up addressing to config data
|
||||
mov eax, ebx
|
||||
and al, 0xfc; make address dword-aligned
|
||||
out dx, eax
|
||||
; get requested DWORD of config data
|
||||
mov dl, 0xfc
|
||||
and bl, 3
|
||||
or dl, bl ; add to port address first 2 bits of register address
|
||||
|
||||
or esi, esi
|
||||
jz pci_read_byte1
|
||||
cmp esi, 1
|
||||
jz pci_read_word1
|
||||
cmp esi, 2
|
||||
jz pci_read_dword1
|
||||
jmp pci_fin_read1
|
||||
|
||||
pci_read_byte1:
|
||||
in al, dx
|
||||
jmp pci_fin_read1
|
||||
pci_read_word1:
|
||||
in ax, dx
|
||||
jmp pci_fin_read1
|
||||
pci_read_dword1:
|
||||
in eax, dx
|
||||
pci_fin_read1:
|
||||
pop esi ebx
|
||||
ret
|
||||
pci_read_reg_2:
|
||||
|
||||
test bh, 128 ;mech#2 only supports 16 devices per bus
|
||||
jnz pci_read_reg_err
|
||||
|
||||
mov esi, eax ; save register size into ESI
|
||||
and esi, 3
|
||||
|
||||
mov dx, 0xcfa
|
||||
|
||||
; out 0xcfa,bus
|
||||
mov al, ah
|
||||
out dx, al
|
||||
; out 0xcf8,0x80
|
||||
mov dl, 0xf8
|
||||
mov al, 0x80
|
||||
out dx, al
|
||||
; compute addr
|
||||
shr bh, 3; func is ignored in mechanism 2
|
||||
or bh, 0xc0
|
||||
mov dx, bx
|
||||
|
||||
or esi, esi
|
||||
jz pci_read_byte2
|
||||
cmp esi, 1
|
||||
jz pci_read_word2
|
||||
cmp esi, 2
|
||||
jz pci_read_dword2
|
||||
jmp pci_fin_read2
|
||||
|
||||
pci_read_byte2:
|
||||
in al, dx
|
||||
jmp pci_fin_read2
|
||||
pci_read_word2:
|
||||
in ax, dx
|
||||
jmp pci_fin_read2
|
||||
pci_read_dword2:
|
||||
in eax, dx
|
||||
pci_fin_read2:
|
||||
|
||||
pop esi ebx
|
||||
ret
|
||||
|
||||
pci_read_reg_err:
|
||||
xor eax, eax
|
||||
dec eax
|
||||
pop esi ebx
|
||||
ret
|
||||
|
||||
|
||||
;***************************************************************************
|
||||
; Function
|
||||
; pci_write_reg:
|
||||
;
|
||||
; Description
|
||||
; write a register from ECX/CX/CL into the PCI config space
|
||||
; IN: ah=bus,device+func=bh,register address (dword aligned)=bl,
|
||||
; value to write in ecx
|
||||
; number of bytes to write (1,2,4) coded into AL, bits 0-1
|
||||
; (0 - byte, 1 - word, 2 - dword)
|
||||
;***************************************************************************
|
||||
|
||||
align 4
|
||||
|
||||
pci_write_reg:
|
||||
push esi ebx
|
||||
cmp byte [BOOT.pci_data], 2;what mechanism will we use?
|
||||
je pci_write_reg_2
|
||||
|
||||
; mechanism 1
|
||||
mov esi, eax ; save register size into ESI
|
||||
and esi, 3
|
||||
|
||||
call pci_make_config_cmd
|
||||
mov ebx, eax
|
||||
mov dx, 0xcf8
|
||||
; set up addressing to config data
|
||||
mov eax, ebx
|
||||
and al, 0xfc; make address dword-aligned
|
||||
out dx, eax
|
||||
; write DWORD of config data
|
||||
mov dl, 0xfc
|
||||
and bl, 3
|
||||
or dl, bl
|
||||
mov eax, ecx
|
||||
|
||||
or esi, esi
|
||||
jz pci_write_byte1
|
||||
cmp esi, 1
|
||||
jz pci_write_word1
|
||||
cmp esi, 2
|
||||
jz pci_write_dword1
|
||||
jmp pci_fin_write1
|
||||
|
||||
pci_write_byte1:
|
||||
out dx, al
|
||||
jmp pci_fin_write1
|
||||
pci_write_word1:
|
||||
out dx, ax
|
||||
jmp pci_fin_write1
|
||||
pci_write_dword1:
|
||||
out dx, eax
|
||||
pci_fin_write1:
|
||||
|
||||
xor eax, eax
|
||||
pop ebx esi
|
||||
|
||||
ret
|
||||
pci_write_reg_2:
|
||||
|
||||
test bh, 128 ;mech#2 only supports 16 devices per bus
|
||||
jnz pci_write_reg_err
|
||||
|
||||
|
||||
mov esi, eax ; save register size into ESI
|
||||
and esi, 3
|
||||
|
||||
mov dx, 0xcfa
|
||||
; out 0xcfa,bus
|
||||
mov al, ah
|
||||
out dx, al
|
||||
; out 0xcf8,0x80
|
||||
mov dl, 0xf8
|
||||
mov al, 0x80
|
||||
out dx, al
|
||||
; compute addr
|
||||
shr bh, 3; func is ignored in mechanism 2
|
||||
or bh, 0xc0
|
||||
mov dx, bx
|
||||
; write register
|
||||
mov eax, ecx
|
||||
|
||||
or esi, esi
|
||||
jz pci_write_byte2
|
||||
cmp esi, 1
|
||||
jz pci_write_word2
|
||||
cmp esi, 2
|
||||
jz pci_write_dword2
|
||||
jmp pci_fin_write2
|
||||
|
||||
pci_write_byte2:
|
||||
out dx, al
|
||||
jmp pci_fin_write2
|
||||
pci_write_word2:
|
||||
out dx, ax
|
||||
jmp pci_fin_write2
|
||||
pci_write_dword2:
|
||||
out dx, eax
|
||||
pci_fin_write2:
|
||||
|
||||
xor eax, eax
|
||||
pop ebx esi
|
||||
ret
|
||||
|
||||
pci_write_reg_err:
|
||||
xor eax, eax
|
||||
dec eax
|
||||
pop ebx esi
|
||||
ret
|
||||
|
||||
if defined mmio_pci_addr ; must be set above
|
||||
;***************************************************************************
|
||||
; Function
|
||||
; pci_mmio_init
|
||||
;
|
||||
; Description
|
||||
; IN: bx = device's PCI bus address (bbbbbbbbdddddfff)
|
||||
; Returns eax = user heap space available (bytes)
|
||||
; Error codes
|
||||
; eax = -1 : PCI user access blocked,
|
||||
; eax = -2 : device not registered for uMMIO service
|
||||
; eax = -3 : user heap initialization failure
|
||||
;***************************************************************************
|
||||
pci_mmio_init:
|
||||
cmp bx, mmio_pci_addr
|
||||
jz @f
|
||||
mov eax, -2
|
||||
ret
|
||||
@@:
|
||||
call init_heap ; (if not initialized yet)
|
||||
or eax, eax
|
||||
jz @f
|
||||
ret
|
||||
@@:
|
||||
mov eax, -3
|
||||
ret
|
||||
|
||||
|
||||
;***************************************************************************
|
||||
; Function
|
||||
; pci_mmio_map
|
||||
;
|
||||
; Description
|
||||
; maps a block of PCI memory to user-accessible linear address
|
||||
;
|
||||
; WARNING! This VERY EXPERIMENTAL service is for one chosen PCI device only!
|
||||
; The target device address should be set in kernel var mmio_pci_addr
|
||||
;
|
||||
; IN: ah = BAR#;
|
||||
; IN: ebx = block size (bytes);
|
||||
; IN: ecx = offset in MMIO block (in 4K-pages, to avoid misaligned pages);
|
||||
;
|
||||
; Returns eax = MMIO block's linear address in the userspace (if no error)
|
||||
;
|
||||
;
|
||||
; Error codes
|
||||
; eax = -1 : user access to PCI blocked,
|
||||
; eax = -2 : an invalid BAR register referred
|
||||
; eax = -3 : no i/o space on that BAR
|
||||
; eax = -4 : a port i/o BAR register referred
|
||||
; eax = -5 : dynamic userspace allocation problem
|
||||
;***************************************************************************
|
||||
|
||||
pci_mmio_map:
|
||||
and edx, 0x0ffff
|
||||
cmp ah, 6
|
||||
jc .bar_0_5
|
||||
jz .bar_rom
|
||||
mov eax, -2
|
||||
ret
|
||||
.bar_rom:
|
||||
mov ah, 8 ; bar6 = Expansion ROM base address
|
||||
.bar_0_5:
|
||||
push ecx
|
||||
add ebx, 4095
|
||||
and ebx, -4096
|
||||
push ebx
|
||||
mov bl, ah ; bl = BAR# (0..5), however bl=8 for BAR6
|
||||
shl bl, 1
|
||||
shl bl, 1
|
||||
add bl, 0x10; now bl = BAR offset in PCI config. space
|
||||
mov ax, mmio_pci_addr
|
||||
mov bh, al ; bh = dddddfff
|
||||
mov al, 2 ; al : DW to read
|
||||
call pci_read_reg
|
||||
or eax, eax
|
||||
jnz @f
|
||||
mov eax, -3 ; empty I/O space
|
||||
jmp mmio_ret_fail
|
||||
@@:
|
||||
test eax, 1
|
||||
jz @f
|
||||
mov eax, -4 ; damned ports (not MMIO space)
|
||||
jmp mmio_ret_fail
|
||||
@@:
|
||||
pop ecx ; ecx = block size, bytes (expanded to whole page)
|
||||
mov ebx, ecx; user_alloc destroys eax, ecx, edx, but saves ebx
|
||||
and eax, 0xFFFFFFF0
|
||||
push eax ; store MMIO physical address + keep 2DWords in the stack
|
||||
stdcall user_alloc, ecx
|
||||
or eax, eax
|
||||
jnz mmio_map_over
|
||||
mov eax, -5 ; problem with page allocation
|
||||
|
||||
mmio_ret_fail:
|
||||
pop ecx
|
||||
pop edx
|
||||
ret
|
||||
|
||||
mmio_map_over:
|
||||
mov ecx, ebx; ecx = size (bytes, expanded to whole page)
|
||||
shr ecx, 12 ; ecx = number of pages
|
||||
mov ebx, eax; ebx = linear address
|
||||
pop eax ; eax = MMIO start
|
||||
pop edx ; edx = MMIO shift (pages)
|
||||
shl edx, 12 ; edx = MMIO shift (bytes)
|
||||
add eax, edx; eax = uMMIO physical address
|
||||
or eax, PG_SHARED
|
||||
or eax, PG_UW
|
||||
or eax, PG_NOCACHE
|
||||
mov edi, ebx
|
||||
call commit_pages
|
||||
mov eax, edi
|
||||
ret
|
||||
|
||||
;***************************************************************************
|
||||
; Function
|
||||
; pci_mmio_unmap_page
|
||||
;
|
||||
; Description
|
||||
; unmaps the linear space previously tied to a PCI memory block
|
||||
;
|
||||
; IN: ebx = linear address of space previously allocated by pci_mmio_map
|
||||
; returns eax = 1 if successfully unmapped
|
||||
;
|
||||
; Error codes
|
||||
; eax = -1 if no user PCI access allowed,
|
||||
; eax = 0 if unmapping failed
|
||||
;***************************************************************************
|
||||
|
||||
pci_mmio_unmap:
|
||||
stdcall user_free, ebx
|
||||
ret
|
||||
|
||||
end if
|
||||
|
||||
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
uglobal
|
||||
align 4
|
||||
; VendID (2), DevID (2), Revision = 0 (1), Class Code (3), FNum (1), Bus (1)
|
||||
pci_emu_dat:
|
||||
times 30*10 db 0
|
||||
endg
|
||||
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
|
||||
align 4
|
||||
sys_pcibios:
|
||||
cmp [pci_access_enabled], 1
|
||||
jne .unsupported_func
|
||||
cmp [pci_bios_entry], 0
|
||||
jz .emulate_bios
|
||||
|
||||
push ds
|
||||
mov ax, pci_data_sel
|
||||
mov ds, ax
|
||||
mov eax, ebp
|
||||
mov ah, 0B1h
|
||||
call pword [cs:pci_bios_entry]
|
||||
pop ds
|
||||
|
||||
jmp .return
|
||||
;-=-=-=-=-=-=-=-=
|
||||
.emulate_bios:
|
||||
cmp ebp, 1 ; PCI_FUNCTION_ID
|
||||
jnz .not_PCI_BIOS_PRESENT
|
||||
mov edx, 'PCI '
|
||||
mov al, [BOOT.pci_data]
|
||||
mov bx, word[BOOT.pci_data + 2]
|
||||
mov cl, [BOOT.pci_data + 1]
|
||||
xor ah, ah
|
||||
jmp .return_abcd
|
||||
|
||||
.not_PCI_BIOS_PRESENT:
|
||||
cmp ebp, 2 ; FIND_PCI_DEVICE
|
||||
jne .not_FIND_PCI_DEVICE
|
||||
mov ebx, pci_emu_dat
|
||||
..nxt:
|
||||
cmp [ebx], dx
|
||||
jne ..no
|
||||
cmp [ebx + 2], cx
|
||||
jne ..no
|
||||
dec si
|
||||
jns ..no
|
||||
mov bx, [ebx + 4]
|
||||
xor ah, ah
|
||||
jmp .return_ab
|
||||
..no:
|
||||
cmp word[ebx], 0
|
||||
je ..dev_not_found
|
||||
add ebx, 10
|
||||
jmp ..nxt
|
||||
..dev_not_found:
|
||||
mov ah, 0x86 ; DEVICE_NOT_FOUND
|
||||
jmp .return_a
|
||||
|
||||
.not_FIND_PCI_DEVICE:
|
||||
cmp ebp, 3 ; FIND_PCI_CLASS_CODE
|
||||
jne .not_FIND_PCI_CLASS_CODE
|
||||
mov esi, pci_emu_dat
|
||||
shl ecx, 8
|
||||
..nxt2:
|
||||
cmp [esi], ecx
|
||||
jne ..no2
|
||||
mov bx, [esi]
|
||||
xor ah, ah
|
||||
jmp .return_ab
|
||||
..no2:
|
||||
cmp dword[esi], 0
|
||||
je ..dev_not_found
|
||||
add esi, 10
|
||||
jmp ..nxt2
|
||||
|
||||
.not_FIND_PCI_CLASS_CODE:
|
||||
cmp ebp, 8 ; READ_CONFIG_*
|
||||
jb .not_READ_CONFIG
|
||||
cmp ebp, 0x0A
|
||||
ja .not_READ_CONFIG
|
||||
mov eax, ebp
|
||||
mov ah, bh
|
||||
mov edx, edi
|
||||
mov bh, bl
|
||||
mov bl, dl
|
||||
call pci_read_reg
|
||||
mov ecx, eax
|
||||
xor ah, ah ; SUCCESSFUL
|
||||
jmp .return_abc
|
||||
.not_READ_CONFIG:
|
||||
cmp ebp, 0x0B ; WRITE_CONFIG_*
|
||||
jb .not_WRITE_CONFIG
|
||||
cmp ebp, 0x0D
|
||||
ja .not_WRITE_CONFIG
|
||||
lea eax, [ebp+1]
|
||||
mov ah, bh
|
||||
mov edx, edi
|
||||
mov bh, bl
|
||||
mov bl, dl
|
||||
call pci_write_reg
|
||||
xor ah, ah ; SUCCESSFUL
|
||||
jmp .return_abc
|
||||
.not_WRITE_CONFIG:
|
||||
.unsupported_func:
|
||||
mov ah, 0x81 ; FUNC_NOT_SUPPORTED
|
||||
.return:
|
||||
mov dword[esp + 4 ], edi
|
||||
mov dword[esp + 8], esi
|
||||
.return_abcd:
|
||||
mov dword[esp + 24], edx
|
||||
.return_abc:
|
||||
mov dword[esp + 28], ecx
|
||||
.return_ab:
|
||||
mov dword[esp + 20], ebx
|
||||
.return_a:
|
||||
mov dword[esp + 32], eax
|
||||
ret
|
||||
|
||||
proc pci_enum
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
push 0
|
||||
virtual at ebp-4
|
||||
.devfn db ?
|
||||
.bus db ?
|
||||
end virtual
|
||||
.loop:
|
||||
mov ah, [.bus]
|
||||
mov al, 2
|
||||
mov bh, [.devfn]
|
||||
mov bl, 0
|
||||
call pci_read_reg
|
||||
cmp eax, 0xFFFFFFFF
|
||||
jnz .has_device
|
||||
test byte [.devfn], 7
|
||||
jnz .next_func
|
||||
jmp .no_device
|
||||
.has_device:
|
||||
push eax
|
||||
movi eax, sizeof.PCIDEV
|
||||
call malloc
|
||||
pop ecx
|
||||
test eax, eax
|
||||
jz .nomemory
|
||||
mov edi, eax
|
||||
mov [edi+PCIDEV.vendor_device_id], ecx
|
||||
mov eax, pcidev_list
|
||||
mov ecx, [eax+PCIDEV.bk]
|
||||
mov [edi+PCIDEV.bk], ecx
|
||||
mov [edi+PCIDEV.fd], eax
|
||||
mov [ecx+PCIDEV.fd], edi
|
||||
mov [eax+PCIDEV.bk], edi
|
||||
mov eax, dword [.devfn]
|
||||
mov dword [edi+PCIDEV.devfn], eax
|
||||
mov dword [edi+PCIDEV.owner], 0
|
||||
mov bh, al
|
||||
mov al, 2
|
||||
mov bl, 8
|
||||
call pci_read_reg
|
||||
shr eax, 8
|
||||
mov [edi+PCIDEV.class], eax
|
||||
test byte [.devfn], 7
|
||||
jnz .next_func
|
||||
mov ah, [.bus]
|
||||
mov al, 0
|
||||
mov bh, [.devfn]
|
||||
mov bl, 0Eh
|
||||
call pci_read_reg
|
||||
test al, al
|
||||
js .next_func
|
||||
.no_device:
|
||||
or byte [.devfn], 7
|
||||
.next_func:
|
||||
inc dword [.devfn]
|
||||
mov ah, [.bus]
|
||||
cmp ah, [BOOT.pci_data+1]
|
||||
jbe .loop
|
||||
.nomemory:
|
||||
leave
|
||||
ret
|
||||
endp
|
||||
|
||||
; Export for drivers. Just returns the pointer to the pci-devices list.
|
||||
proc get_pcidev_list
|
||||
mov eax, pcidev_list
|
||||
ret
|
||||
endp
|
||||
462
kernel/branches/kolibri-lldw/bus/usb/common.inc
Normal file
462
kernel/branches/kolibri-lldw/bus/usb/common.inc
Normal file
@@ -0,0 +1,462 @@
|
||||
; Constants and structures that are shared between different parts of
|
||||
; USB subsystem and *HCI drivers.
|
||||
|
||||
; =============================================================================
|
||||
; ================================= Constants =================================
|
||||
; =============================================================================
|
||||
; Version of all structures related to host controllers.
|
||||
; Must be the same in kernel and *hci-drivers.
|
||||
USBHC_VERSION = 2
|
||||
|
||||
; USB device must have at least 100ms of stable power before initializing can
|
||||
; proceed; one timer tick is 10ms, so enforce delay in 10 ticks
|
||||
USB_CONNECT_DELAY = 10
|
||||
; USB requires at least 10 ms for reset signalling. Normally, this is one timer
|
||||
; tick. However, it is possible that we start reset signalling in the end of
|
||||
; interval between timer ticks and then we test time in the start of the next
|
||||
; interval; in this case, the delta between [timer_ticks] is 1, but the real
|
||||
; time passed is significantly less than 10 ms. To avoid this, we add an extra
|
||||
; tick; this guarantees that at least 10 ms have passed.
|
||||
USB_RESET_TIME = 2
|
||||
; USB requires at least 10 ms of reset recovery, a delay between reset
|
||||
; signalling and any commands to device. Add an extra tick for the same reasons
|
||||
; as with the previous constant.
|
||||
USB_RESET_RECOVERY_TIME = 2
|
||||
|
||||
; USB pipe types
|
||||
CONTROL_PIPE = 0
|
||||
ISOCHRONOUS_PIPE = 1
|
||||
BULK_PIPE = 2
|
||||
INTERRUPT_PIPE = 3
|
||||
|
||||
; Status codes for transfer callbacks.
|
||||
; Taken from OHCI as most verbose controller in this sense.
|
||||
USB_STATUS_OK = 0 ; no error
|
||||
USB_STATUS_CRC = 1 ; CRC error
|
||||
USB_STATUS_BITSTUFF = 2 ; bit stuffing violation
|
||||
USB_STATUS_TOGGLE = 3 ; data toggle mismatch
|
||||
USB_STATUS_STALL = 4 ; device returned STALL
|
||||
USB_STATUS_NORESPONSE = 5 ; device not responding
|
||||
USB_STATUS_PIDCHECK = 6 ; invalid PID check bits
|
||||
USB_STATUS_WRONGPID = 7 ; unexpected PID value
|
||||
USB_STATUS_OVERRUN = 8 ; too many data from endpoint
|
||||
USB_STATUS_UNDERRUN = 9 ; too few data from endpoint
|
||||
USB_STATUS_BUFOVERRUN = 12 ; overflow of internal controller buffer
|
||||
USB_STATUS_BUFUNDERRUN = 13 ; underflow of internal controller buffer
|
||||
USB_STATUS_CLOSED = 16 ; pipe closed
|
||||
; either explicitly with USBClosePipe
|
||||
; or implicitly due to device disconnect
|
||||
USB_STATUS_CANCELLED = 17 ; transfer cancelled with USBAbortPipe
|
||||
|
||||
; Possible speeds of USB devices
|
||||
USB_SPEED_FS = 0 ; full-speed
|
||||
USB_SPEED_LS = 1 ; low-speed
|
||||
USB_SPEED_HS = 2 ; high-speed
|
||||
|
||||
; flags for usb_pipe.Flags
|
||||
USB_FLAG_CLOSED = 1 ; pipe is closed, no new transfers
|
||||
; pipe is closed, return error instead of submitting any new transfer
|
||||
USB_FLAG_CAN_FREE = 2
|
||||
; pipe is closed via explicit call to USBClosePipe, so it can be freed without
|
||||
; any driver notification; if this flag is not set, then the pipe is closed due
|
||||
; to device disconnect, so it must remain valid until return from disconnect
|
||||
; callback provided by the driver
|
||||
USB_FLAG_EXTRA_WAIT = 4
|
||||
; The pipe was in wait list, while another event occured;
|
||||
; when the first wait will be done, reinsert the pipe to wait list
|
||||
USB_FLAG_DISABLED = 8
|
||||
; The pipe is temporarily disabled so that it is not visible to hardware
|
||||
; but still remains in software list. Used for usb_abort_pipe.
|
||||
USB_FLAG_CLOSED_BIT = 0 ; USB_FLAG_CLOSED = 1 shl USB_FLAG_CLOSED_BIT
|
||||
|
||||
; =============================================================================
|
||||
; ================================ Structures =================================
|
||||
; =============================================================================
|
||||
|
||||
; Description of controller-specific data and functions.
|
||||
struct usb_hardware_func
|
||||
Version dd ? ; must be USBHC_VERSION
|
||||
ID dd ? ; '*HCI'
|
||||
DataSize dd ? ; sizeof(*hci_controller)
|
||||
BeforeInit dd ?
|
||||
; Early initialization: take ownership from BIOS.
|
||||
; in: [ebp-4] = (bus shl 8) + devfn
|
||||
Init dd ?
|
||||
; Initialize controller-specific part of controller data.
|
||||
; in: eax -> *hci_controller to initialize, [ebp-4] = (bus shl 8) + devfn
|
||||
; out: eax = 0 <=> failed, otherwise eax -> usb_controller
|
||||
ProcessDeferred dd ?
|
||||
; Called regularly from the main loop of USB thread
|
||||
; (either due to timeout from a previous call, or due to explicit wakeup).
|
||||
; in: esi -> usb_controller
|
||||
; out: eax = maximum timeout for next call (-1 = infinity)
|
||||
SetDeviceAddress dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe, cl = address
|
||||
GetDeviceAddress dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe
|
||||
; out: eax = address
|
||||
PortDisable dd ?
|
||||
; Disable the given port in the root hub.
|
||||
; in: esi -> usb_controller, ecx = port (zero-based)
|
||||
InitiateReset dd ?
|
||||
; Start reset signalling on the given port.
|
||||
; in: esi -> usb_controller, ecx = port (zero-based)
|
||||
SetEndpointPacketSize dd ?
|
||||
; in: esi -> usb_controller, ebx -> usb_pipe, ecx = packet size
|
||||
AllocPipe dd ?
|
||||
; out: eax = pointer to allocated usb_pipe
|
||||
FreePipe dd ?
|
||||
; void stdcall with one argument = pointer to previously allocated usb_pipe
|
||||
InitPipe dd ?
|
||||
; in: edi -> usb_pipe for target, ecx -> usb_pipe for config pipe,
|
||||
; esi -> usb_controller, eax -> usb_gtd for the first TD,
|
||||
; [ebp+12] = endpoint, [ebp+16] = maxpacket, [ebp+20] = type
|
||||
UnlinkPipe dd ?
|
||||
; esi -> usb_controller, ebx -> usb_pipe
|
||||
AllocTD dd ?
|
||||
; out: eax = pointer to allocated usb_gtd
|
||||
FreeTD dd ?
|
||||
; void stdcall with one argument = pointer to previously allocated usb_gtd
|
||||
AllocTransfer dd ?
|
||||
; Allocate and initialize one stage of a transfer.
|
||||
; ebx -> usb_pipe, other parameters are passed through the stack:
|
||||
; buffer,size = data to transfer
|
||||
; flags = same as in usb_open_pipe:
|
||||
; bit 0 = allow short transfer, other bits reserved
|
||||
; td = pointer to the current end-of-queue descriptor
|
||||
; direction =
|
||||
; 0000b for normal transfers,
|
||||
; 1000b for control SETUP transfer,
|
||||
; 1101b for control OUT transfer,
|
||||
; 1110b for control IN transfer
|
||||
; returns eax = pointer to the new end-of-queue descriptor
|
||||
; (not included in the queue itself) or 0 on error
|
||||
InsertTransfer dd ?
|
||||
; Activate previously initialized transfer (maybe with multiple stages).
|
||||
; esi -> usb_controller, ebx -> usb_pipe,
|
||||
; [esp+4] -> first usb_gtd for the transfer,
|
||||
; ecx -> last descriptor for the transfer
|
||||
NewDevice dd ?
|
||||
; Initiate configuration of a new device (create pseudo-pipe describing that
|
||||
; device and call usb_new_device).
|
||||
; esi -> usb_controller, eax = speed (one of USB_SPEED_* constants).
|
||||
DisablePipe dd ?
|
||||
; This procedure temporarily removes the given pipe from hardware queue.
|
||||
; esi -> usb_controller, ebx -> usb_pipe
|
||||
EnablePipe dd ?
|
||||
; This procedure reinserts the given pipe to hardware queue
|
||||
; after DisablePipe, with clearing transfer queue.
|
||||
; esi -> usb_controller, ebx -> usb_pipe
|
||||
; edx -> current descriptor, eax -> new last descriptor
|
||||
ends
|
||||
|
||||
; pointers to kernel API functions that are called from *HCI-drivers
|
||||
struct usbhc_func
|
||||
usb_process_gtd dd ?
|
||||
usb_init_static_endpoint dd ?
|
||||
usb_wakeup_if_needed dd ?
|
||||
usb_subscribe_control dd ?
|
||||
usb_subscription_done dd ?
|
||||
usb_allocate_common dd ?
|
||||
usb_free_common dd ?
|
||||
usb_td_to_virt dd ?
|
||||
usb_init_transfer dd ?
|
||||
usb_undo_tds dd ?
|
||||
usb_test_pending_port dd ?
|
||||
usb_get_tt dd ?
|
||||
usb_get_tt_think_time dd ?
|
||||
usb_new_device dd ?
|
||||
usb_disconnect_stage2 dd ?
|
||||
usb_process_wait_lists dd ?
|
||||
usb_unlink_td dd ?
|
||||
usb_is_final_packet dd ?
|
||||
usb_find_ehci_companion dd ?
|
||||
ends
|
||||
|
||||
; Controller descriptor.
|
||||
; This structure represents the common (controller-independent) part
|
||||
; of a controller for the USB code. The corresponding controller-dependent
|
||||
; part *hci_controller is located immediately before usb_controller.
|
||||
struct usb_controller
|
||||
; Two following fields organize all controllers in the global linked list.
|
||||
Next dd ?
|
||||
Prev dd ?
|
||||
HardwareFunc dd ?
|
||||
; Pointer to usb_hardware_func structure with controller-specific functions.
|
||||
NumPorts dd ?
|
||||
; Number of ports in the root hub.
|
||||
PCICoordinates dd ?
|
||||
; Device:function and bus number from PCI.
|
||||
;
|
||||
; The hardware is allowed to cache some data from hardware structures.
|
||||
; Regular operations are designed considering this,
|
||||
; but sometimes it is required to wait for synchronization of hardware cache
|
||||
; with modified structures in memory.
|
||||
; The code keeps two queues of pipes waiting for synchronization,
|
||||
; one for asynchronous (bulk/control) pipes, one for periodic pipes, hardware
|
||||
; cache is invalidated under different conditions for those types.
|
||||
; Both queues are organized in the same way, as single-linked lists.
|
||||
; There are three special positions: the head of list (new pipes are added
|
||||
; here), the first pipe to be synchronized at the current iteration,
|
||||
; the tail of list (all pipes starting from here are synchronized).
|
||||
WaitPipeListAsync dd ?
|
||||
WaitPipeListPeriodic dd ?
|
||||
; List heads.
|
||||
WaitPipeRequestAsync dd ?
|
||||
WaitPipeRequestPeriodic dd ?
|
||||
; Pending request to hardware to refresh cache for items from WaitPipeList*.
|
||||
; (Pointers to some items in WaitPipeList* or NULLs).
|
||||
ReadyPipeHeadAsync dd ?
|
||||
ReadyPipeHeadPeriodic dd ?
|
||||
; Items of RemovingList* which were released by hardware and are ready
|
||||
; for further processing.
|
||||
; (Pointers to some items in WaitPipeList* or NULLs).
|
||||
NewConnected dd ?
|
||||
; bit mask of recently connected ports of the root hub,
|
||||
; bit set = a device was recently connected to the corresponding port;
|
||||
; after USB_CONNECT_DELAY ticks of stable status these ports are moved to
|
||||
; PendingPorts
|
||||
NewDisconnected dd ?
|
||||
; bit mask of disconnected ports of the root hub,
|
||||
; bit set = a device in the corresponding port was disconnected,
|
||||
; disconnect processing is required.
|
||||
PendingPorts dd ?
|
||||
; bit mask of ports which are ready to be initialized
|
||||
ControlLock MUTEX ?
|
||||
; mutex which guards all operations with control queue
|
||||
BulkLock MUTEX ?
|
||||
; mutex which guards all operations with bulk queue
|
||||
PeriodicLock MUTEX ?
|
||||
; mutex which guards all operations with periodic queues
|
||||
WaitSpinlock:
|
||||
; spinlock guarding WaitPipeRequest/ReadyPipeHead (but not WaitPipeList)
|
||||
StartWaitFrame dd ?
|
||||
; USB frame number when WaitPipeRequest* was registered.
|
||||
ResettingHub dd ?
|
||||
; Pointer to usb_hub responsible for the currently resetting port, if any.
|
||||
; NULL for the root hub.
|
||||
ResettingPort db ?
|
||||
; Port that is currently resetting, 0-based.
|
||||
ResettingSpeed db ?
|
||||
; Speed of currently resetting device.
|
||||
ResettingStatus db ?
|
||||
; Status of port reset. 0 = no port is resetting, -1 = reset failed,
|
||||
; 1 = reset in progress, 2 = reset recovery in progress.
|
||||
rb 1 ; alignment
|
||||
ResetTime dd ?
|
||||
; Time when reset signalling or reset recovery has been started.
|
||||
SetAddressBuffer rb 8
|
||||
; Buffer for USB control command SET_ADDRESS.
|
||||
ExistingAddresses rd 128/32
|
||||
; Bitmask for 128 bits; bit i is cleared <=> address i is free for allocating
|
||||
; for new devices. Bit 0 is always set.
|
||||
ConnectedTime rd 16
|
||||
; Time, in timer ticks, when the port i has signalled the connect event.
|
||||
; Valid only if bit i in NewConnected is set.
|
||||
DevicesByPort rd 16
|
||||
; Pointer to usb_pipe for zero endpoint (which serves as device handle)
|
||||
; for each port.
|
||||
ends
|
||||
|
||||
; Pipe descriptor.
|
||||
; * An USB pipe is described by two structures, for hardware and for software.
|
||||
; * This is the software part. The hardware part is defined in a driver
|
||||
; of the corresponding controller.
|
||||
; * The hardware part is located immediately before usb_pipe,
|
||||
; both are allocated at once by controller-specific code
|
||||
; (it knows the total length, which depends on the hardware part).
|
||||
struct usb_pipe
|
||||
Controller dd ?
|
||||
; Pointer to usb_controller structure corresponding to this pipe.
|
||||
; Must be the first dword after hardware part, see *hci_new_device.
|
||||
;
|
||||
; Every endpoint is included into one of processing lists:
|
||||
; * Bulk list contains all Bulk endpoints.
|
||||
; * Control list contains all Control endpoints.
|
||||
; * Several Periodic lists serve Interrupt endpoints with different interval.
|
||||
; - There are N=2^n "leaf" periodic lists for N ms interval, one is processed
|
||||
; in the frames 0,N,2N,..., another is processed in the frames
|
||||
; 1,1+N,1+2N,... and so on. The hardware starts processing of periodic
|
||||
; endpoints in every frame from the list identified by lower n bits of the
|
||||
; frame number; the addresses of these N lists are written to the
|
||||
; controller data area during the initialization.
|
||||
; - We assume that n=5, N=32 to simplify the code and compact the data.
|
||||
; OHCI works in this way. UHCI and EHCI actually have n=10, N=1024,
|
||||
; but this is an overkill for interrupt endpoints; the large value of N is
|
||||
; useful only for isochronous transfers in UHCI and EHCI. UHCI/EHCI code
|
||||
; initializes "leaf" lists k,k+32,k+64,...,k+(1024-32) to the same value,
|
||||
; giving essentially N=32.
|
||||
; This restriction means that the actual maximum interval of polling any
|
||||
; interrupt endpoint is 32ms, which seems to be a reasonable value.
|
||||
; - Similarly, there are 16 lists for 16-ms interval, 8 lists for 8-ms
|
||||
; interval and so on. Finally, there is one list for 1ms interval. Their
|
||||
; addresses are not directly known to the controller.
|
||||
; - The hardware serves endpoints following a physical link from the hardware
|
||||
; part.
|
||||
; - The hardware links are organized as follows. If the list item is not the
|
||||
; last, it's hardware link points to the next item. The hardware link of
|
||||
; the last item points to the first item of the "next" list.
|
||||
; - The "next" list for k-th and (k+M)-th periodic lists for interval 2M ms
|
||||
; is the k-th periodic list for interval M ms, M >= 1. In this scheme,
|
||||
; if two "previous" lists are served in the frames k,k+2M,k+4M,...
|
||||
; and k+M,k+3M,k+5M,... correspondingly, the "next" list is served in
|
||||
; the frames k,k+M,k+2M,k+3M,k+4M,k+5M,..., which is exactly what we want.
|
||||
; - The links between Periodic, Control, Bulk lists and the processing of
|
||||
; Isochronous endpoints are controller-specific.
|
||||
; * The head of every processing list is a static entry which does not
|
||||
; correspond to any real pipe. It is described by usb_static_ep
|
||||
; structure, not usb_pipe. For OHCI and UHCI, sizeof.usb_static_ep plus
|
||||
; sizeof hardware part is 20h, the total number of lists is
|
||||
; 32+16+8+4+2+1+1+1 = 65, so all these structures fit in one page,
|
||||
; leaving space for other data. This is another reason for 32ms limit.
|
||||
; * Static endpoint descriptors are kept in *hci_controller structure.
|
||||
; * All items in every processing list, including the static head, are
|
||||
; organized in a double-linked list using .NextVirt and .PrevVirt fields.
|
||||
; * [[item.NextVirt].PrevVirt] = [[item.PrevVirt].NextVirt] for all items.
|
||||
NextVirt dd ?
|
||||
; Next endpoint in the processing list.
|
||||
; See also PrevVirt field and the description before NextVirt field.
|
||||
PrevVirt dd ?
|
||||
; Previous endpoint in the processing list.
|
||||
; See also NextVirt field and the description before NextVirt field.
|
||||
BaseList dd ?
|
||||
; Pointer to head of the processing list.
|
||||
;
|
||||
; Every pipe has the associated transfer queue, that is, the double-linked
|
||||
; list of Transfer Descriptors aka TD. For Control, Bulk and Interrupt
|
||||
; endpoints this list consists of usb_gtd structures
|
||||
; (GTD = General Transfer Descriptors), for Isochronous endpoints
|
||||
; this list consists of usb_itd structures, which are not developed yet.
|
||||
; The pipe needs to know only the last TD; the first TD can be
|
||||
; obtained as [[pipe.LastTD].NextVirt].
|
||||
LastTD dd ?
|
||||
; Last TD in the transfer queue.
|
||||
;
|
||||
; All opened pipes corresponding to the same physical device are organized in
|
||||
; the double-linked list using .NextSibling and .PrevSibling fields.
|
||||
; The head of this list is kept in usb_device_data structure (OpenedPipeList).
|
||||
; This list is used when the device is disconnected and all pipes for the
|
||||
; device should be closed.
|
||||
; Also, all pipes closed due to disconnect must remain valid at least until
|
||||
; driver-provided disconnect function returns; all should-be-freed-but-not-now
|
||||
; pipes for one device are organized in another double-linked list with
|
||||
; the head in usb_device_data.ClosedPipeList; this list uses the same link
|
||||
; fields, one pipe can never be in both lists.
|
||||
NextSibling dd ?
|
||||
; Next pipe for the physical device.
|
||||
PrevSibling dd ?
|
||||
; Previous pipe for the physical device.
|
||||
;
|
||||
; When hardware part of pipe is changed, some time is needed before further
|
||||
; actions so that hardware reacts on this change. During that time,
|
||||
; all changed pipes are organized in single-linked list with the head
|
||||
; usb_controller.WaitPipeList* and link field NextWait.
|
||||
; Currently there are two possible reasons to change:
|
||||
; change of address/packet size in initial configuration,
|
||||
; close of the pipe. They are distinguished by USB_FLAG_CLOSED.
|
||||
NextWait dd ?
|
||||
Lock MUTEX
|
||||
; Mutex that guards operations with transfer queue for this pipe.
|
||||
Type db ?
|
||||
; Type of pipe, one of {CONTROL,ISOCHRONOUS,BULK,INTERRUPT}_PIPE.
|
||||
Flags db ?
|
||||
; Combination of flags, USB_FLAG_*.
|
||||
rb 2 ; dword alignment
|
||||
DeviceData dd ?
|
||||
; Pointer to usb_device_data, common for all pipes for one device.
|
||||
ends
|
||||
|
||||
; This structure describes the static head of every list of pipes.
|
||||
struct usb_static_ep
|
||||
; software fields
|
||||
Bandwidth dd ?
|
||||
; valid only for interrupt/isochronous USB1 lists
|
||||
; The offsets of the following two fields must be the same in this structure
|
||||
; and in usb_pipe.
|
||||
NextVirt dd ?
|
||||
PrevVirt dd ?
|
||||
ends
|
||||
|
||||
; This structure represents one transfer descriptor
|
||||
; ('g' stands for "general" as opposed to isochronous usb_itd).
|
||||
; Note that one transfer can have several descriptors:
|
||||
; a control transfer has three stages.
|
||||
; Additionally, every controller has a limit on transfer length with
|
||||
; one descriptor (packet size for UHCI, 1K for OHCI, 4K for EHCI),
|
||||
; large transfers must be split into individual packets according to that limit.
|
||||
struct usb_gtd
|
||||
Callback dd ?
|
||||
; Zero for intermediate descriptors, pointer to callback function
|
||||
; for final descriptor. See the docs for description of the callback.
|
||||
UserData dd ?
|
||||
; Dword which is passed to Callback as is, not used by USB code itself.
|
||||
; Two following fields organize all descriptors for one pipe in
|
||||
; the linked list.
|
||||
NextVirt dd ?
|
||||
PrevVirt dd ?
|
||||
Pipe dd ?
|
||||
; Pointer to the parent usb_pipe.
|
||||
Buffer dd ?
|
||||
; Pointer to data for this descriptor.
|
||||
Length dd ?
|
||||
; Length of data for this descriptor.
|
||||
ends
|
||||
|
||||
; Interface-specific data. Several interfaces of one device can operate
|
||||
; independently, each is controlled by some driver and is identified by
|
||||
; some driver-specific data passed as is to the driver.
|
||||
struct usb_interface_data
|
||||
DriverData dd ?
|
||||
; Passed as is to the driver.
|
||||
DriverFunc dd ?
|
||||
; Pointer to USBSRV structure for the driver.
|
||||
ends
|
||||
|
||||
; Device-specific data.
|
||||
struct usb_device_data
|
||||
PipeListLock MUTEX
|
||||
; Lock guarding OpenedPipeList. Must be the first item of the structure,
|
||||
; the code passes pointer to usb_device_data as is to mutex_lock/unlock.
|
||||
OpenedPipeList rd 2
|
||||
; List of all opened pipes for the device.
|
||||
; Used when the device is disconnected, so all pipes should be closed.
|
||||
ClosedPipeList rd 2
|
||||
; List of all closed, but still valid pipes for the device.
|
||||
; A pipe closed with USBClosePipe is just deallocated,
|
||||
; but a pipe closed due to disconnect must remain valid until driver-provided
|
||||
; disconnect handler returns; this list links all such pipes to deallocate them
|
||||
; after disconnect processing.
|
||||
NumPipes dd ?
|
||||
; Number of not-yet-closed pipes.
|
||||
Hub dd ?
|
||||
; NULL if connected to the root hub, pointer to usb_hub otherwise.
|
||||
TTHub dd ?
|
||||
; Pointer to usb_hub for (the) hub with Transaction Translator for the device,
|
||||
; NULL if the device operates in the same speed as the controller.
|
||||
Port db ?
|
||||
; Port on the hub, zero-based.
|
||||
TTPort db ?
|
||||
; Port on the TTHub, zero-based.
|
||||
DeviceDescrSize db ?
|
||||
; Size of device descriptor.
|
||||
Speed db ?
|
||||
; Device speed, one of USB_SPEED_*.
|
||||
Timer dd ?
|
||||
; Handle of timer that handles request timeout.
|
||||
NumInterfaces dd ?
|
||||
; Number of interfaces.
|
||||
ConfigDataSize dd ?
|
||||
; Total size of data associated with the configuration descriptor
|
||||
; (including the configuration descriptor itself).
|
||||
Interfaces dd ?
|
||||
; Offset from the beginning of this structure to Interfaces field.
|
||||
; Variable-length fields:
|
||||
; DeviceDescriptor:
|
||||
; device descriptor starts here
|
||||
; ConfigDescriptor = DeviceDescriptor + DeviceDescrSize
|
||||
; configuration descriptor with all associated data
|
||||
; Interfaces = ALIGN_UP(ConfigDescriptor + ConfigDataSize, 4)
|
||||
; array of NumInterfaces elements of type usb_interface_data
|
||||
ends
|
||||
|
||||
usb_device_data.DeviceDescriptor = sizeof.usb_device_data
|
||||
348
kernel/branches/kolibri-lldw/bus/usb/hccommon.inc
Normal file
348
kernel/branches/kolibri-lldw/bus/usb/hccommon.inc
Normal file
@@ -0,0 +1,348 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
; USB Host Controller support code: hardware-independent part,
|
||||
; common for all controller types.
|
||||
|
||||
iglobal
|
||||
; USB HC support: some functions interesting only for *HCI-drivers.
|
||||
align 4
|
||||
usb_hc_func:
|
||||
dd usb_process_gtd
|
||||
dd usb_init_static_endpoint
|
||||
dd usb_wakeup_if_needed
|
||||
dd usb_subscribe_control
|
||||
dd usb_subscription_done
|
||||
dd slab_alloc
|
||||
dd slab_free
|
||||
dd usb_td_to_virt
|
||||
dd usb_init_transfer
|
||||
dd usb_undo_tds
|
||||
dd usb_test_pending_port
|
||||
dd usb_get_tt
|
||||
dd usb_get_tt_think_time
|
||||
dd usb_new_device
|
||||
dd usb_disconnect_stage2
|
||||
dd usb_process_wait_lists
|
||||
dd usb_unlink_td
|
||||
dd usb_is_final_packet
|
||||
dd usb_find_ehci_companion
|
||||
endg
|
||||
|
||||
; Initializes one controller, called by usb_init for every controller.
|
||||
; eax -> PCIDEV structure for the device.
|
||||
proc usb_init_controller
|
||||
push ebp
|
||||
mov ebp, esp
|
||||
; 1. Store in the stack PCI coordinates and save pointer to PCIDEV:
|
||||
; make [ebp-4] = (bus shl 8) + devfn, used by controller-specific Init funcs.
|
||||
push dword [eax+PCIDEV.devfn]
|
||||
push eax
|
||||
mov edi, [eax+PCIDEV.owner]
|
||||
test edi, edi
|
||||
jz .nothing
|
||||
mov edi, [edi+USBSRV.usb_func]
|
||||
; 2. Allocate *hci_controller + usb_controller.
|
||||
mov ebx, [edi+usb_hardware_func.DataSize]
|
||||
add ebx, sizeof.usb_controller
|
||||
stdcall kernel_alloc, ebx
|
||||
test eax, eax
|
||||
jz .nothing
|
||||
; 3. Zero-initialize both structures.
|
||||
push edi eax
|
||||
mov ecx, ebx
|
||||
shr ecx, 2
|
||||
xchg edi, eax
|
||||
xor eax, eax
|
||||
rep stosd
|
||||
; 4. Initialize usb_controller structure,
|
||||
; except data known only to controller-specific code (like NumPorts)
|
||||
; and link fields
|
||||
; (this structure will be inserted to the overall list at step 6).
|
||||
dec eax
|
||||
mov [edi+usb_controller.ExistingAddresses+4-sizeof.usb_controller], eax
|
||||
mov [edi+usb_controller.ExistingAddresses+8-sizeof.usb_controller], eax
|
||||
mov [edi+usb_controller.ExistingAddresses+12-sizeof.usb_controller], eax
|
||||
mov [edi+usb_controller.ResettingPort-sizeof.usb_controller], al ; no resetting port
|
||||
dec eax ; don't allocate zero address
|
||||
mov [edi+usb_controller.ExistingAddresses-sizeof.usb_controller], eax
|
||||
mov eax, [ebp-4]
|
||||
mov [edi+usb_controller.PCICoordinates-sizeof.usb_controller], eax
|
||||
lea ecx, [edi+usb_controller.PeriodicLock-sizeof.usb_controller]
|
||||
call mutex_init
|
||||
add ecx, usb_controller.ControlLock - usb_controller.PeriodicLock
|
||||
call mutex_init
|
||||
add ecx, usb_controller.BulkLock - usb_controller.ControlLock
|
||||
call mutex_init
|
||||
pop eax edi
|
||||
mov [eax+ebx-sizeof.usb_controller+usb_controller.HardwareFunc], edi
|
||||
push eax
|
||||
; 5. Call controller-specific initialization.
|
||||
; If failed, free memory allocated in step 2 and return.
|
||||
call [edi+usb_hardware_func.Init]
|
||||
test eax, eax
|
||||
jz .fail
|
||||
pop ecx
|
||||
; 6. Insert the controller to the global list.
|
||||
xchg eax, ebx
|
||||
mov ecx, usb_controllers_list_mutex
|
||||
call mutex_lock
|
||||
mov edx, usb_controllers_list
|
||||
mov eax, [edx+usb_controller.Prev]
|
||||
mov [ebx+usb_controller.Next], edx
|
||||
mov [ebx+usb_controller.Prev], eax
|
||||
mov [edx+usb_controller.Prev], ebx
|
||||
mov [eax+usb_controller.Next], ebx
|
||||
call mutex_unlock
|
||||
; 7. Wakeup USB thread to call ProcessDeferred.
|
||||
call usb_wakeup
|
||||
.nothing:
|
||||
; 8. Restore pointer to PCIDEV saved in step 1 and return.
|
||||
pop eax
|
||||
leave
|
||||
ret
|
||||
.fail:
|
||||
call kernel_free
|
||||
jmp .nothing
|
||||
endp
|
||||
|
||||
; Helper function, calculates physical address including offset in page.
|
||||
proc get_phys_addr
|
||||
push ecx
|
||||
mov ecx, eax
|
||||
and ecx, 0xFFF
|
||||
call get_pg_addr
|
||||
add eax, ecx
|
||||
pop ecx
|
||||
ret
|
||||
endp
|
||||
|
||||
; Put the given control/bulk pipe in the wait list;
|
||||
; called when the pipe structure is changed and a possible hardware cache
|
||||
; needs to be synchronized. When it will be known that the cache is updated,
|
||||
; usb_subscription_done procedure will be called.
|
||||
proc usb_subscribe_control
|
||||
cmp [ebx+usb_pipe.NextWait], -1
|
||||
jnz @f
|
||||
mov eax, [esi+usb_controller.WaitPipeListAsync]
|
||||
mov [ebx+usb_pipe.NextWait], eax
|
||||
mov [esi+usb_controller.WaitPipeListAsync], ebx
|
||||
@@:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Same as usb_subscribe_control, but for interrupt/isochronous pipe.
|
||||
proc usb_subscribe_periodic
|
||||
cmp [ebx+usb_pipe.NextWait], -1
|
||||
jnz @f
|
||||
mov eax, [esi+usb_controller.WaitPipeListPeriodic]
|
||||
mov [ebx+usb_pipe.NextWait], eax
|
||||
mov [esi+usb_controller.WaitPipeListPeriodic], ebx
|
||||
@@:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Called after synchronization of hardware cache with software changes.
|
||||
; Continues process of device enumeration based on when it was delayed
|
||||
; due to call to usb_subscribe_control.
|
||||
proc usb_subscription_done
|
||||
mov eax, [ebx+usb_pipe.DeviceData]
|
||||
cmp [eax+usb_device_data.DeviceDescrSize], 0
|
||||
jz usb_after_set_address
|
||||
jmp usb_after_set_endpoint_size
|
||||
endp
|
||||
|
||||
; This function is called when a new device has either passed
|
||||
; or failed first stages of configuration, so the next device
|
||||
; can enter configuration process.
|
||||
proc usb_test_pending_port
|
||||
mov [esi+usb_controller.ResettingPort], -1
|
||||
cmp [esi+usb_controller.PendingPorts], 0
|
||||
jz .nothing
|
||||
bsf ecx, [esi+usb_controller.PendingPorts]
|
||||
btr [esi+usb_controller.PendingPorts], ecx
|
||||
mov eax, [esi+usb_controller.HardwareFunc]
|
||||
jmp [eax+usb_hardware_func.InitiateReset]
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; This procedure is regularly called from controller-specific ProcessDeferred,
|
||||
; it checks whether there are disconnected events and if so, process them.
|
||||
proc usb_disconnect_stage2
|
||||
bsf ecx, [esi+usb_controller.NewDisconnected]
|
||||
jz .nothing
|
||||
lock btr [esi+usb_controller.NewDisconnected], ecx
|
||||
btr [esi+usb_controller.PendingPorts], ecx
|
||||
xor ebx, ebx
|
||||
xchg ebx, [esi+usb_controller.DevicesByPort+ecx*4]
|
||||
test ebx, ebx
|
||||
jz usb_disconnect_stage2
|
||||
call usb_device_disconnected
|
||||
jmp usb_disconnect_stage2
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Initial stage of disconnect processing: called when device is disconnected.
|
||||
proc usb_device_disconnected
|
||||
; Loop over all pipes, close everything, wait until hardware reacts.
|
||||
; The final handling is done in usb_pipe_closed.
|
||||
push ebx
|
||||
mov ecx, [ebx+usb_pipe.DeviceData]
|
||||
call mutex_lock
|
||||
lea eax, [ecx+usb_device_data.OpenedPipeList-usb_pipe.NextSibling]
|
||||
push eax
|
||||
mov ebx, [eax+usb_pipe.NextSibling]
|
||||
.pipe_loop:
|
||||
call usb_close_pipe_nolock
|
||||
mov ebx, [ebx+usb_pipe.NextSibling]
|
||||
cmp ebx, [esp]
|
||||
jnz .pipe_loop
|
||||
pop eax
|
||||
pop ebx
|
||||
mov ecx, [ebx+usb_pipe.DeviceData]
|
||||
call mutex_unlock
|
||||
ret
|
||||
endp
|
||||
|
||||
; Called from controller-specific ProcessDeferred,
|
||||
; processes wait-pipe-done notifications,
|
||||
; returns whether there are more items in wait queues.
|
||||
; in: esi -> usb_controller
|
||||
; out: eax = bitmask of pipe types with non-empty wait queue
|
||||
proc usb_process_wait_lists
|
||||
xor edx, edx
|
||||
push edx
|
||||
call usb_process_one_wait_list
|
||||
jnc @f
|
||||
or byte [esp], 1 shl CONTROL_PIPE
|
||||
@@:
|
||||
movi edx, 4
|
||||
call usb_process_one_wait_list
|
||||
jnc @f
|
||||
or byte [esp], 1 shl INTERRUPT_PIPE
|
||||
@@:
|
||||
xor edx, edx
|
||||
call usb_process_one_wait_list
|
||||
jnc @f
|
||||
or byte [esp], 1 shl CONTROL_PIPE
|
||||
@@:
|
||||
pop eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; Helper procedure for usb_process_wait_lists;
|
||||
; does the same for one wait queue.
|
||||
; in: esi -> usb_controller,
|
||||
; edx=0 for *Async, edx=4 for *Periodic list
|
||||
; out: CF = issue new request
|
||||
proc usb_process_one_wait_list
|
||||
; 1. Check whether there is a pending request. If so, do nothing.
|
||||
mov ebx, [esi+usb_controller.WaitPipeRequestAsync+edx]
|
||||
cmp ebx, [esi+usb_controller.ReadyPipeHeadAsync+edx]
|
||||
clc
|
||||
jnz .nothing
|
||||
; 2. Check whether there are new data. If so, issue a new request.
|
||||
cmp ebx, [esi+usb_controller.WaitPipeListAsync+edx]
|
||||
stc
|
||||
jnz .nothing
|
||||
test ebx, ebx
|
||||
jz .nothing
|
||||
; 3. Clear all lists.
|
||||
xor ecx, ecx
|
||||
mov [esi+usb_controller.WaitPipeListAsync+edx], ecx
|
||||
mov [esi+usb_controller.WaitPipeRequestAsync+edx], ecx
|
||||
mov [esi+usb_controller.ReadyPipeHeadAsync+edx], ecx
|
||||
; 4. Loop over all pipes from the wait list.
|
||||
.pipe_loop:
|
||||
; For every pipe:
|
||||
; 5. Save edx and next pipe in the list.
|
||||
push edx
|
||||
push [ebx+usb_pipe.NextWait]
|
||||
; 6. If USB_FLAG_EXTRA_WAIT is set, reinsert the pipe to the list and continue.
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
|
||||
jz .process
|
||||
mov eax, [esi+usb_controller.WaitPipeListAsync+edx]
|
||||
mov [ebx+usb_pipe.NextWait], eax
|
||||
mov [esi+usb_controller.WaitPipeListAsync+edx], ebx
|
||||
jmp .continue
|
||||
.process:
|
||||
; 7. Call the handler depending on USB_FLAG_CLOSED and USB_FLAG_DISABLED.
|
||||
or [ebx+usb_pipe.NextWait], -1
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
|
||||
jz .nodisconnect
|
||||
call usb_pipe_closed
|
||||
jmp .continue
|
||||
.nodisconnect:
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
|
||||
jz .nodisabled
|
||||
call usb_pipe_disabled
|
||||
jmp .continue
|
||||
.nodisabled:
|
||||
call usb_subscription_done
|
||||
.continue:
|
||||
; 8. Restore edx and next pipe saved in step 5 and continue the loop.
|
||||
pop ebx
|
||||
pop edx
|
||||
test ebx, ebx
|
||||
jnz .pipe_loop
|
||||
.check_new_work:
|
||||
; 9. Set CF depending on whether WaitPipeList* is nonzero.
|
||||
cmp [esi+usb_controller.WaitPipeListAsync+edx], 1
|
||||
cmc
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Called from USB1 controller-specific initialization.
|
||||
; Finds EHCI companion controller for given USB1 controller.
|
||||
; in: bl = PCI device:function for USB1 controller, bh = PCI bus
|
||||
; out: eax -> usb_controller for EHCI companion
|
||||
proc usb_find_ehci_companion
|
||||
; 1. Loop over all registered controllers.
|
||||
mov eax, usb_controllers_list
|
||||
.next:
|
||||
mov eax, [eax+usb_controller.Next]
|
||||
cmp eax, usb_controllers_list
|
||||
jz .notfound
|
||||
; 2. For every controller, check the type, ignore everything that is not EHCI.
|
||||
mov edx, [eax+usb_controller.HardwareFunc]
|
||||
cmp [edx+usb_hardware_func.ID], 'EHCI'
|
||||
jnz .next
|
||||
; 3. For EHCI controller, compare PCI coordinates with input data:
|
||||
; bus and device must be the same, function can be different.
|
||||
mov edx, [eax+usb_controller.PCICoordinates]
|
||||
xor edx, ebx
|
||||
cmp dx, 8
|
||||
jae .next
|
||||
ret
|
||||
.notfound:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; Find Transaction Translator hub and port for the given device.
|
||||
; in: edx = parent hub for the device, ecx = port for the device
|
||||
; out: edx = TT hub for the device, ecx = TT port for the device.
|
||||
proc usb_get_tt
|
||||
; If the parent hub is high-speed, it is TT for the device.
|
||||
; Otherwise, the parent hub itself is behind TT, and the device
|
||||
; has the same TT hub+port as the parent hub.
|
||||
mov eax, [edx+usb_hub.ConfigPipe]
|
||||
mov eax, [eax+usb_pipe.DeviceData]
|
||||
cmp [eax+usb_device_data.Speed], USB_SPEED_HS
|
||||
jz @f
|
||||
movzx ecx, [eax+usb_device_data.TTPort]
|
||||
mov edx, [eax+usb_device_data.TTHub]
|
||||
@@:
|
||||
mov edx, [edx+usb_hub.ConfigPipe]
|
||||
ret
|
||||
endp
|
||||
1285
kernel/branches/kolibri-lldw/bus/usb/hub.inc
Normal file
1285
kernel/branches/kolibri-lldw/bus/usb/hub.inc
Normal file
File diff suppressed because it is too large
Load Diff
268
kernel/branches/kolibri-lldw/bus/usb/init.inc
Normal file
268
kernel/branches/kolibri-lldw/bus/usb/init.inc
Normal file
@@ -0,0 +1,268 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
; Initialization of the USB subsystem.
|
||||
; Provides usb_init procedure, includes all needed files.
|
||||
|
||||
; General notes:
|
||||
; * There is one entry point for external kernel code: usb_init is called
|
||||
; from initialization code and initializes USB subsystem.
|
||||
; * There are several entry points for API; see the docs for description.
|
||||
; * There are several functions which are called from controller-specific
|
||||
; parts of USB subsystem. The most important is usb_new_device,
|
||||
; which is called when a new device has been connected (over some time),
|
||||
; has been reset and is ready to start configuring.
|
||||
; * IRQ handlers are very restricted. They can not take any locks,
|
||||
; since otherwise a deadlock is possible: imagine that a code has taken the
|
||||
; lock and was interrupted by IRQ handler. Now IRQ handler would wait for
|
||||
; releasing the lock, and a lock owner would wait for exiting IRQ handler
|
||||
; to get the control.
|
||||
; * Thus, there is the special USB thread which processes almost all activity.
|
||||
; IRQ handlers do the minimal processing and wake this thread.
|
||||
; * Also the USB thread wakes occasionally to process tasks which can be
|
||||
; predicted without interrupts. These include e.g. a periodic roothub
|
||||
; scanning in UHCI and initializing in USB_CONNECT_DELAY ticks
|
||||
; after connecting a new device.
|
||||
; * The main procedure of USB thread, usb_thread_proc, does all its work
|
||||
; by querying usb_hardware_func.ProcessDeferred for every controller
|
||||
; and usb_hub_process_deferred for every hub.
|
||||
; ProcessDeferred does controller-specific actions and calculates the time
|
||||
; when it should be invoked again, possibly infinite.
|
||||
; usb_thread_proc selects the minimum from all times returned by
|
||||
; ProcessDeferred and sleeps until this moment is reached or the thread
|
||||
; is awakened by IRQ handler.
|
||||
|
||||
iglobal
|
||||
uhci_service_name:
|
||||
db 'UHCI',0
|
||||
ohci_service_name:
|
||||
db 'OHCI',0
|
||||
ehci_service_name:
|
||||
db 'EHCI',0
|
||||
endg
|
||||
|
||||
; Initializes the USB subsystem.
|
||||
proc usb_init
|
||||
; 1. Initialize all locks.
|
||||
mov ecx, usb_controllers_list_mutex
|
||||
call mutex_init
|
||||
; 2. Kick off BIOS from all USB controllers, calling the corresponding function
|
||||
; *hci_kickoff_bios. Also count USB controllers for the next step.
|
||||
; Note: USB1 companion(s) must go before the corresponding EHCI controller,
|
||||
; otherwise BIOS could see a device moving from EHCI to a companion;
|
||||
; first, this always wastes time;
|
||||
; second, some BIOSes are buggy, do not expect that move and try to refer to
|
||||
; previously-assigned controller instead of actual; sometimes that leads to
|
||||
; hangoff.
|
||||
; Thus, process controllers in PCI order.
|
||||
mov esi, pcidev_list
|
||||
push 0
|
||||
.kickoff:
|
||||
mov esi, [esi+PCIDEV.fd]
|
||||
cmp esi, pcidev_list
|
||||
jz .done_kickoff
|
||||
cmp word [esi+PCIDEV.class+1], 0x0C03
|
||||
jnz .kickoff
|
||||
mov ebx, uhci_service_name
|
||||
cmp byte [esi+PCIDEV.class], 0x00
|
||||
jz .do_kickoff
|
||||
mov ebx, ohci_service_name
|
||||
cmp byte [esi+PCIDEV.class], 0x10
|
||||
jz .do_kickoff
|
||||
mov ebx, ehci_service_name
|
||||
cmp byte [esi+PCIDEV.class], 0x20
|
||||
jnz .kickoff
|
||||
.do_kickoff:
|
||||
inc dword [esp]
|
||||
push ebx esi
|
||||
stdcall get_service, ebx
|
||||
pop esi ebx
|
||||
test eax, eax
|
||||
jz .driver_fail
|
||||
mov edx, [eax+USBSRV.usb_func]
|
||||
cmp [edx+usb_hardware_func.Version], USBHC_VERSION
|
||||
jnz .driver_invalid
|
||||
mov [esi+PCIDEV.owner], eax
|
||||
call [edx+usb_hardware_func.BeforeInit]
|
||||
jmp .kickoff
|
||||
.driver_fail:
|
||||
DEBUGF 1,'K : failed to load driver %s\n',ebx
|
||||
jmp .kickoff
|
||||
.driver_invalid:
|
||||
DEBUGF 1,'K : driver %s has wrong version\n',ebx
|
||||
jmp .kickoff
|
||||
.done_kickoff:
|
||||
pop eax
|
||||
; 3. If no controllers were found, exit.
|
||||
; Otherwise, run the USB thread.
|
||||
test eax, eax
|
||||
jz .nothing
|
||||
call create_usb_thread
|
||||
jz .nothing
|
||||
; 4. Initialize all USB controllers, calling usb_init_controller for each.
|
||||
; Note: USB1 companion(s) should go before the corresponding EHCI controller,
|
||||
; although this is not strictly necessary (this way, a companion would not try
|
||||
; to initialize high-speed device only to see a disconnect when EHCI takes
|
||||
; control).
|
||||
; Thus, process all EHCI controllers in the first loop, all USB1 controllers
|
||||
; in the second loop. (One loop in reversed PCI order could also be used,
|
||||
; but seems less natural.)
|
||||
; 4a. Loop over all PCI devices, call usb_init_controller
|
||||
; for all EHCI controllers.
|
||||
mov eax, pcidev_list
|
||||
.scan_ehci:
|
||||
mov eax, [eax+PCIDEV.fd]
|
||||
cmp eax, pcidev_list
|
||||
jz .done_ehci
|
||||
cmp [eax+PCIDEV.class], 0x0C0320
|
||||
jnz .scan_ehci
|
||||
call usb_init_controller
|
||||
jmp .scan_ehci
|
||||
.done_ehci:
|
||||
; 4b. Loop over all PCI devices, call usb_init_controller
|
||||
; for all UHCI and OHCI controllers.
|
||||
mov eax, pcidev_list
|
||||
.scan_usb1:
|
||||
mov eax, [eax+PCIDEV.fd]
|
||||
cmp eax, pcidev_list
|
||||
jz .done_usb1
|
||||
cmp [eax+PCIDEV.class], 0x0C0300
|
||||
jz @f
|
||||
cmp [eax+PCIDEV.class], 0x0C0310
|
||||
jnz .scan_usb1
|
||||
@@:
|
||||
call usb_init_controller
|
||||
jmp .scan_usb1
|
||||
.done_usb1:
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
uglobal
|
||||
align 4
|
||||
usb_event dd ?
|
||||
endg
|
||||
|
||||
; Helper function for usb_init. Creates and initializes the USB thread.
|
||||
proc create_usb_thread
|
||||
; 1. Create the thread.
|
||||
push edi
|
||||
movi ebx, 1
|
||||
mov ecx, usb_thread_proc
|
||||
xor edx, edx
|
||||
call new_sys_threads
|
||||
pop edi
|
||||
; If failed, say something to the debug board and return with ZF set.
|
||||
test eax, eax
|
||||
jns @f
|
||||
DEBUGF 1,'K : cannot create kernel thread for USB, error %d\n',eax
|
||||
.clear:
|
||||
xor eax, eax
|
||||
jmp .nothing
|
||||
@@:
|
||||
; 2. Wait while the USB thread initializes itself.
|
||||
@@:
|
||||
call change_task
|
||||
cmp [usb_event], 0
|
||||
jz @b
|
||||
; 3. If initialization failed, the USB thread sets [usb_event] to -1.
|
||||
; Return with ZF set or cleared corresponding to the result.
|
||||
cmp [usb_event], -1
|
||||
jz .clear
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Helper function for IRQ handlers. Wakes the USB thread if ebx is nonzero.
|
||||
proc usb_wakeup_if_needed
|
||||
test ebx, ebx
|
||||
jz usb_wakeup.nothing
|
||||
usb_wakeup:
|
||||
xor edx, edx
|
||||
mov eax, [usb_event]
|
||||
mov ebx, [eax+EVENT.id]
|
||||
xor esi, esi
|
||||
call raise_event
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Main loop of the USB thread.
|
||||
proc usb_thread_proc
|
||||
; 1. Initialize: create event to allow wakeup by interrupt handlers.
|
||||
xor esi, esi
|
||||
mov ecx, MANUAL_DESTROY
|
||||
call create_event
|
||||
test eax, eax
|
||||
jnz @f
|
||||
; If failed, set [usb_event] to -1 and terminate myself.
|
||||
dbgstr 'cannot create event for USB thread'
|
||||
or [usb_event], -1
|
||||
jmp sys_end
|
||||
@@:
|
||||
mov [usb_event], eax
|
||||
push -1 ; initial timeout: infinite
|
||||
usb_thread_wait:
|
||||
; 2. Main loop: wait for either wakeup event or timeout.
|
||||
pop ecx ; get timeout
|
||||
mov eax, [usb_event]
|
||||
mov ebx, [eax+EVENT.id]
|
||||
call wait_event_timeout
|
||||
push -1 ; default timeout: infinite
|
||||
; 3. Main loop: call worker functions of all controllers;
|
||||
; if some function schedules wakeup in timeout less than the current value,
|
||||
; replace that value with the returned timeout.
|
||||
mov esi, usb_controllers_list
|
||||
@@:
|
||||
mov esi, [esi+usb_controller.Next]
|
||||
cmp esi, usb_controllers_list
|
||||
jz .controllers_done
|
||||
mov eax, [esi+usb_controller.HardwareFunc]
|
||||
call [eax+usb_hardware_func.ProcessDeferred]
|
||||
cmp [esp], eax
|
||||
jb @b
|
||||
mov [esp], eax
|
||||
jmp @b
|
||||
.controllers_done:
|
||||
; 4. Main loop: call hub worker function for all hubs,
|
||||
; similarly calculating minimum of all returned timeouts.
|
||||
; When done, continue to 2.
|
||||
mov esi, usb_hubs_list
|
||||
@@:
|
||||
mov esi, [esi+usb_hub.Next]
|
||||
cmp esi, usb_hubs_list
|
||||
jz usb_thread_wait
|
||||
call usb_hub_process_deferred
|
||||
cmp [esp], eax
|
||||
jb @b
|
||||
mov [esp], eax
|
||||
jmp @b
|
||||
endp
|
||||
|
||||
iglobal
|
||||
align 4
|
||||
usb_controllers_list:
|
||||
dd usb_controllers_list
|
||||
dd usb_controllers_list
|
||||
usb_hubs_list:
|
||||
dd usb_hubs_list
|
||||
dd usb_hubs_list
|
||||
endg
|
||||
uglobal
|
||||
align 4
|
||||
usb_controllers_list_mutex MUTEX
|
||||
endg
|
||||
|
||||
include "memory.inc"
|
||||
include "common.inc"
|
||||
include "hccommon.inc"
|
||||
include "pipe.inc"
|
||||
include "protocol.inc"
|
||||
include "hub.inc"
|
||||
43
kernel/branches/kolibri-lldw/bus/usb/memory.inc
Normal file
43
kernel/branches/kolibri-lldw/bus/usb/memory.inc
Normal file
@@ -0,0 +1,43 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
; Memory management for USB structures.
|
||||
; Protocol layer uses the common kernel heap malloc/free.
|
||||
; Hardware layer has special requirements:
|
||||
; * memory blocks should be properly aligned
|
||||
; * memory blocks should not cross page boundary
|
||||
; Hardware layer allocates fixed-size blocks.
|
||||
; Thus, hardware layer uses the system slab allocator.
|
||||
|
||||
; Helper procedure: translate physical address in ecx
|
||||
; of some transfer descriptor to linear address.
|
||||
; in: eax = address of first page
|
||||
proc usb_td_to_virt
|
||||
; Traverse all pages used for transfer descriptors, looking for the one
|
||||
; with physical address as in ecx.
|
||||
@@:
|
||||
test eax, eax
|
||||
jz .zero
|
||||
push eax
|
||||
call get_pg_addr
|
||||
sub eax, ecx
|
||||
jz .found
|
||||
cmp eax, -0x1000
|
||||
ja .found
|
||||
pop eax
|
||||
mov eax, [eax+0x1000-4]
|
||||
jmp @b
|
||||
.found:
|
||||
; When found, combine page address from eax with page offset from ecx.
|
||||
pop eax
|
||||
and ecx, 0xFFF
|
||||
add eax, ecx
|
||||
.zero:
|
||||
ret
|
||||
endp
|
||||
860
kernel/branches/kolibri-lldw/bus/usb/pipe.inc
Normal file
860
kernel/branches/kolibri-lldw/bus/usb/pipe.inc
Normal file
@@ -0,0 +1,860 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
; Functions for USB pipe manipulation: opening/closing, sending data etc.
|
||||
;
|
||||
USB_STDCALL_VERIFY = 1
|
||||
macro stdcall_verify [arg]
|
||||
{
|
||||
common
|
||||
if USB_STDCALL_VERIFY
|
||||
pushad
|
||||
stdcall arg
|
||||
call verify_regs
|
||||
popad
|
||||
else
|
||||
stdcall arg
|
||||
end if
|
||||
}
|
||||
if USB_STDCALL_VERIFY
|
||||
STDCALL_VERIFY_EXTRA = 20h
|
||||
else
|
||||
STDCALL_VERIFY_EXTRA = 0
|
||||
end if
|
||||
|
||||
; Initialization of usb_static_ep structure,
|
||||
; called from controller-specific initialization; edi -> usb_static_ep
|
||||
proc usb_init_static_endpoint
|
||||
mov [edi+usb_static_ep.NextVirt], edi
|
||||
mov [edi+usb_static_ep.PrevVirt], edi
|
||||
ret
|
||||
endp
|
||||
|
||||
; Part of API for drivers, see documentation for USBOpenPipe.
|
||||
proc usb_open_pipe stdcall uses ebx esi edi,\
|
||||
config_pipe:dword, endpoint:dword, maxpacket:dword, type:dword, interval:dword
|
||||
locals
|
||||
tt_vars rd 24 ; should be enough for ehci_select_tt_interrupt_list
|
||||
targetsmask dd ? ; S-Mask for USB2
|
||||
bandwidth dd ?
|
||||
target dd ?
|
||||
endl
|
||||
; 1. Verify type of pipe: it must be one of *_PIPE constants.
|
||||
; Isochronous pipes are not supported yet.
|
||||
mov eax, [type]
|
||||
cmp eax, INTERRUPT_PIPE
|
||||
ja .badtype
|
||||
cmp al, ISOCHRONOUS_PIPE
|
||||
jnz .goodtype
|
||||
.badtype:
|
||||
dbgstr 'unsupported type of USB pipe'
|
||||
jmp .return0
|
||||
.goodtype:
|
||||
; 2. Allocate memory for pipe and transfer queue.
|
||||
; Empty transfer queue consists of one inactive TD.
|
||||
mov ebx, [config_pipe]
|
||||
mov esi, [ebx+usb_pipe.Controller]
|
||||
mov edx, [esi+usb_controller.HardwareFunc]
|
||||
call [edx+usb_hardware_func.AllocPipe]
|
||||
test eax, eax
|
||||
jz .nothing
|
||||
mov edi, eax
|
||||
mov edx, [esi+usb_controller.HardwareFunc]
|
||||
call [edx+usb_hardware_func.AllocTD]
|
||||
test eax, eax
|
||||
jz .free_and_return0
|
||||
; 3. Initialize transfer queue: pointer to transfer descriptor,
|
||||
; pointers in transfer descriptor, queue lock.
|
||||
mov [edi+usb_pipe.LastTD], eax
|
||||
mov [eax+usb_gtd.NextVirt], eax
|
||||
mov [eax+usb_gtd.PrevVirt], eax
|
||||
mov [eax+usb_gtd.Pipe], edi
|
||||
lea ecx, [edi+usb_pipe.Lock]
|
||||
call mutex_init
|
||||
; 4. Initialize software part of pipe structure, except device-related fields.
|
||||
mov al, byte [type]
|
||||
mov [edi+usb_pipe.Type], al
|
||||
xor eax, eax
|
||||
mov [edi+usb_pipe.Flags], al
|
||||
mov [edi+usb_pipe.DeviceData], eax
|
||||
mov [edi+usb_pipe.Controller], esi
|
||||
or [edi+usb_pipe.NextWait], -1
|
||||
; 5. Initialize device-related fields:
|
||||
; for zero endpoint, set .NextSibling = .PrevSibling = this;
|
||||
; for other endpoins, copy device data, take the lock guarding pipe list
|
||||
; for the device and verify that disconnect processing has not yet started
|
||||
; for the device. (Since disconnect processing also takes that lock,
|
||||
; either it has completed or it will not start until we release the lock.)
|
||||
; Note: usb_device_disconnected should not see the new pipe until
|
||||
; initialization is complete, so that lock will be held during next steps
|
||||
; (disconnect processing should either not see it at all, or see fully
|
||||
; initialized pipe).
|
||||
cmp [endpoint], eax
|
||||
jz .zero_endpoint
|
||||
mov ecx, [ebx+usb_pipe.DeviceData]
|
||||
mov [edi+usb_pipe.DeviceData], ecx
|
||||
call mutex_lock
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
|
||||
jz .common
|
||||
.fail:
|
||||
; If disconnect processing has completed, unlock the mutex, free memory
|
||||
; allocated in step 2 and return zero.
|
||||
call mutex_unlock
|
||||
mov edx, [esi+usb_controller.HardwareFunc]
|
||||
stdcall [edx+usb_hardware_func.FreeTD], [edi+usb_pipe.LastTD]
|
||||
.free_and_return0:
|
||||
mov edx, [esi+usb_controller.HardwareFunc]
|
||||
stdcall [edx+usb_hardware_func.FreePipe], edi
|
||||
.return0:
|
||||
xor eax, eax
|
||||
jmp .nothing
|
||||
.zero_endpoint:
|
||||
mov [edi+usb_pipe.NextSibling], edi
|
||||
mov [edi+usb_pipe.PrevSibling], edi
|
||||
.common:
|
||||
; 6. Initialize hardware part of pipe structure.
|
||||
; 6a. Acquire the corresponding mutex.
|
||||
lea ecx, [esi+usb_controller.ControlLock]
|
||||
cmp [type], BULK_PIPE
|
||||
jb @f ; control pipe
|
||||
lea ecx, [esi+usb_controller.BulkLock]
|
||||
jz @f ; bulk pipe
|
||||
lea ecx, [esi+usb_controller.PeriodicLock]
|
||||
@@:
|
||||
call mutex_lock
|
||||
; 6b. Let the controller-specific code do its job.
|
||||
push ecx
|
||||
mov edx, [esi+usb_controller.HardwareFunc]
|
||||
mov eax, [edi+usb_pipe.LastTD]
|
||||
mov ecx, [config_pipe]
|
||||
call [edx+usb_hardware_func.InitPipe]
|
||||
pop ecx
|
||||
; 6c. Release the mutex.
|
||||
push eax
|
||||
call mutex_unlock
|
||||
pop eax
|
||||
; 6d. If controller-specific code indicates failure,
|
||||
; release the lock taken in step 5, free memory allocated in step 2
|
||||
; and return zero.
|
||||
test eax, eax
|
||||
jz .fail
|
||||
; 7. The pipe is initialized. If this is not the first pipe for the device,
|
||||
; insert it to the tail of pipe list for the device,
|
||||
; increment number of pipes,
|
||||
; release the lock taken at step 5.
|
||||
mov ecx, [edi+usb_pipe.DeviceData]
|
||||
test ecx, ecx
|
||||
jz @f
|
||||
mov eax, [ebx+usb_pipe.PrevSibling]
|
||||
mov [edi+usb_pipe.NextSibling], ebx
|
||||
mov [edi+usb_pipe.PrevSibling], eax
|
||||
mov [ebx+usb_pipe.PrevSibling], edi
|
||||
mov [eax+usb_pipe.NextSibling], edi
|
||||
inc [ecx+usb_device_data.NumPipes]
|
||||
call mutex_unlock
|
||||
@@:
|
||||
; 8. Return pointer to usb_pipe.
|
||||
mov eax, edi
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; This procedure is called several times during initial device configuration,
|
||||
; when usb_device_data structure is reallocated.
|
||||
; It (re)initializes all pointers in usb_device_data.
|
||||
; ebx -> usb_pipe
|
||||
proc usb_reinit_pipe_list
|
||||
push eax
|
||||
; 1. (Re)initialize the lock guarding pipe list.
|
||||
mov ecx, [ebx+usb_pipe.DeviceData]
|
||||
call mutex_init
|
||||
; 2. Initialize list of opened pipes: two entries, the head and ebx.
|
||||
add ecx, usb_device_data.OpenedPipeList - usb_pipe.NextSibling
|
||||
mov [ecx+usb_pipe.NextSibling], ebx
|
||||
mov [ecx+usb_pipe.PrevSibling], ebx
|
||||
mov [ebx+usb_pipe.NextSibling], ecx
|
||||
mov [ebx+usb_pipe.PrevSibling], ecx
|
||||
; 3. Initialize list of closed pipes: empty list, only the head is present.
|
||||
add ecx, usb_device_data.ClosedPipeList - usb_device_data.OpenedPipeList
|
||||
mov [ecx+usb_pipe.NextSibling], ecx
|
||||
mov [ecx+usb_pipe.PrevSibling], ecx
|
||||
pop eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; Part of API for drivers, see documentation for USBClosePipe.
|
||||
proc usb_close_pipe
|
||||
push ebx esi ; save used registers to be stdcall
|
||||
virtual at esp
|
||||
rd 2 ; saved registers
|
||||
dd ? ; return address
|
||||
.pipe dd ?
|
||||
end virtual
|
||||
; 1. Lock the pipe list for the device.
|
||||
mov ebx, [.pipe]
|
||||
mov esi, [ebx+usb_pipe.Controller]
|
||||
mov ecx, [ebx+usb_pipe.DeviceData]
|
||||
call mutex_lock
|
||||
; 2. Set the flag "the driver has abandoned this pipe, free it at any time".
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_lock
|
||||
or [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
|
||||
call mutex_unlock
|
||||
; 3. Call the worker function.
|
||||
call usb_close_pipe_nolock
|
||||
; 4. Unlock the pipe list for the device.
|
||||
mov ecx, [ebx+usb_pipe.DeviceData]
|
||||
call mutex_unlock
|
||||
; 5. Wakeup the USB thread so that it can proceed with releasing that pipe.
|
||||
push edi
|
||||
call usb_wakeup
|
||||
pop edi
|
||||
; 6. Return.
|
||||
pop esi ebx ; restore used registers to be stdcall
|
||||
retn 4
|
||||
endp
|
||||
|
||||
; Worker function for pipe closing. Called by usb_close_pipe API and
|
||||
; from disconnect processing.
|
||||
; The lock guarding pipe list for the device should be held by the caller.
|
||||
; ebx -> usb_pipe, esi -> usb_controller
|
||||
proc usb_close_pipe_nolock
|
||||
; 1. Set the flag "pipe is closed, ignore new transfers".
|
||||
; If it was already set, do nothing.
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_lock
|
||||
bts dword [ebx+usb_pipe.Flags], USB_FLAG_CLOSED_BIT
|
||||
jc .closed
|
||||
call mutex_unlock
|
||||
; 2. Remove the pipe from the list of opened pipes.
|
||||
mov eax, [ebx+usb_pipe.NextSibling]
|
||||
mov edx, [ebx+usb_pipe.PrevSibling]
|
||||
mov [eax+usb_pipe.PrevSibling], edx
|
||||
mov [edx+usb_pipe.NextSibling], eax
|
||||
; 3. Unlink the pipe from hardware structures.
|
||||
; 3a. Acquire the corresponding lock.
|
||||
lea edx, [esi+usb_controller.WaitPipeListAsync]
|
||||
lea ecx, [esi+usb_controller.ControlLock]
|
||||
cmp [ebx+usb_pipe.Type], BULK_PIPE
|
||||
jb @f ; control pipe
|
||||
lea ecx, [esi+usb_controller.BulkLock]
|
||||
jz @f ; bulk pipe
|
||||
add edx, usb_controller.WaitPipeListPeriodic - usb_controller.WaitPipeListAsync
|
||||
lea ecx, [esi+usb_controller.PeriodicLock]
|
||||
@@:
|
||||
push edx
|
||||
call mutex_lock
|
||||
push ecx
|
||||
; 3b. Let the controller-specific code do its job.
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
|
||||
jnz @f
|
||||
mov eax, [esi+usb_controller.HardwareFunc]
|
||||
call [eax+usb_hardware_func.DisablePipe]
|
||||
@@:
|
||||
mov eax, [esi+usb_controller.HardwareFunc]
|
||||
call [eax+usb_hardware_func.UnlinkPipe]
|
||||
mov edx, [ebx+usb_pipe.NextVirt]
|
||||
mov eax, [ebx+usb_pipe.PrevVirt]
|
||||
mov [edx+usb_pipe.PrevVirt], eax
|
||||
mov [eax+usb_pipe.NextVirt], edx
|
||||
; 3c. Release the corresponding lock.
|
||||
pop ecx
|
||||
call mutex_unlock
|
||||
; 4. Put the pipe into wait queue.
|
||||
pop edx
|
||||
cmp [ebx+usb_pipe.NextWait], -1
|
||||
jz .insert_new
|
||||
or [ebx+usb_pipe.Flags], USB_FLAG_EXTRA_WAIT
|
||||
jmp .inserted
|
||||
.insert_new:
|
||||
mov eax, [edx]
|
||||
mov [ebx+usb_pipe.NextWait], eax
|
||||
mov [edx], ebx
|
||||
.inserted:
|
||||
; 5. Return.
|
||||
ret
|
||||
.closed:
|
||||
call mutex_unlock
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; This procedure is called when all transfers are aborted
|
||||
; either due to call to usb_abort_pipe or due to pipe closing.
|
||||
; It notifies all callbacks and frees all transfer descriptors.
|
||||
; ebx -> usb_pipe, esi -> usb_controller, edi -> usb_hardware_func
|
||||
; three stack parameters: status code for callback functions
|
||||
; and descriptors where to start and stop.
|
||||
proc usb_pipe_aborted
|
||||
virtual at esp
|
||||
dd ? ; return address
|
||||
.status dd ? ; USB_STATUS_CLOSED or USB_STATUS_CANCELLED
|
||||
.first_td dd ?
|
||||
.last_td dd ?
|
||||
end virtual
|
||||
; Loop over all transfers, calling the driver with the given status
|
||||
; and freeing all descriptors except the last one.
|
||||
.loop:
|
||||
mov edx, [.first_td]
|
||||
cmp edx, [.last_td]
|
||||
jz .done
|
||||
mov ecx, [edx+usb_gtd.Callback]
|
||||
test ecx, ecx
|
||||
jz .no_callback
|
||||
stdcall_verify ecx, ebx, [.status+12+STDCALL_VERIFY_EXTRA], \
|
||||
[edx+usb_gtd.Buffer], 0, [edx+usb_gtd.UserData]
|
||||
mov edx, [.first_td]
|
||||
.no_callback:
|
||||
mov eax, [edx+usb_gtd.NextVirt]
|
||||
mov [.first_td], eax
|
||||
stdcall [edi+usb_hardware_func.FreeTD], edx
|
||||
jmp .loop
|
||||
.done:
|
||||
ret 12
|
||||
endp
|
||||
|
||||
; This procedure is called when a pipe with USB_FLAG_CLOSED is removed from the
|
||||
; corresponding wait list. It means that the hardware has fully forgot about it.
|
||||
; ebx -> usb_pipe, esi -> usb_controller
|
||||
proc usb_pipe_closed
|
||||
push edi
|
||||
mov edi, [esi+usb_controller.HardwareFunc]
|
||||
; 1. Notify all registered callbacks with status USB_STATUS_CLOSED, if any,
|
||||
; and free all transfer descriptors, including the last one.
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_lock
|
||||
mov edx, [ebx+usb_pipe.LastTD]
|
||||
test edx, edx
|
||||
jz .no_transfer
|
||||
mov eax, [edx+usb_gtd.NextVirt]
|
||||
push edx
|
||||
push eax
|
||||
call mutex_unlock
|
||||
push USB_STATUS_CLOSED
|
||||
call usb_pipe_aborted
|
||||
; It is safe to free LastTD here:
|
||||
; usb_*_transfer_async do not enqueue new transfers if USB_FLAG_CLOSED is set.
|
||||
stdcall [edi+usb_hardware_func.FreeTD], [ebx+usb_pipe.LastTD]
|
||||
jmp @f
|
||||
.no_transfer:
|
||||
call mutex_unlock
|
||||
@@:
|
||||
; 2. Decrement number of pipes for the device.
|
||||
; If this pipe is the last pipe, go to 5.
|
||||
mov ecx, [ebx+usb_pipe.DeviceData]
|
||||
call mutex_lock
|
||||
dec [ecx+usb_device_data.NumPipes]
|
||||
jz .last_pipe
|
||||
call mutex_unlock
|
||||
; 3. If the flag "the driver has abandoned this pipe" is set,
|
||||
; free memory and return.
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_CAN_FREE
|
||||
jz .nofree
|
||||
stdcall [edi+usb_hardware_func.FreePipe], ebx
|
||||
pop edi
|
||||
ret
|
||||
; 4. Otherwise, add it to the list of closed pipes and return.
|
||||
.nofree:
|
||||
add ecx, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
|
||||
mov edx, [ecx+usb_pipe.PrevSibling]
|
||||
mov [ebx+usb_pipe.NextSibling], ecx
|
||||
mov [ebx+usb_pipe.PrevSibling], edx
|
||||
mov [ecx+usb_pipe.PrevSibling], ebx
|
||||
mov [edx+usb_pipe.NextSibling], ebx
|
||||
pop edi
|
||||
ret
|
||||
.last_pipe:
|
||||
; That was the last pipe for the device.
|
||||
; 5. Notify device driver(s) about disconnect.
|
||||
call mutex_unlock
|
||||
mov eax, [ecx+usb_device_data.NumInterfaces]
|
||||
test eax, eax
|
||||
jz .notify_done
|
||||
add ecx, [ecx+usb_device_data.Interfaces]
|
||||
.notify_loop:
|
||||
mov edx, [ecx+usb_interface_data.DriverFunc]
|
||||
test edx, edx
|
||||
jz @f
|
||||
mov edx, [edx+USBSRV.usb_func]
|
||||
cmp [edx+USBFUNC.strucsize], USBFUNC.device_disconnect + 4
|
||||
jb @f
|
||||
mov edx, [edx+USBFUNC.device_disconnect]
|
||||
test edx, edx
|
||||
jz @f
|
||||
push eax ecx
|
||||
stdcall_verify edx, [ecx+usb_interface_data.DriverData]
|
||||
pop ecx eax
|
||||
@@:
|
||||
add ecx, sizeof.usb_interface_data
|
||||
dec eax
|
||||
jnz .notify_loop
|
||||
.notify_done:
|
||||
; 6. Kill the timer, if active.
|
||||
; (Usually not; possible if device is disconnected
|
||||
; while processing SET_ADDRESS request).
|
||||
mov eax, [ebx+usb_pipe.DeviceData]
|
||||
cmp [eax+usb_device_data.Timer], 0
|
||||
jz @f
|
||||
stdcall cancel_timer_hs, [eax+usb_device_data.Timer]
|
||||
mov [eax+usb_device_data.Timer], 0
|
||||
@@:
|
||||
; 7. Bus address, if assigned, can now be reused.
|
||||
call [edi+usb_hardware_func.GetDeviceAddress]
|
||||
test eax, eax
|
||||
jz @f
|
||||
bts [esi+usb_controller.ExistingAddresses], eax
|
||||
@@:
|
||||
dbgstr 'USB device disconnected'
|
||||
; 8. All drivers have returned from disconnect callback,
|
||||
; so all drivers should not use any device-related pipes.
|
||||
; Free the remaining pipes.
|
||||
mov eax, [ebx+usb_pipe.DeviceData]
|
||||
add eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
|
||||
push eax
|
||||
mov eax, [eax+usb_pipe.NextSibling]
|
||||
.free_loop:
|
||||
cmp eax, [esp]
|
||||
jz .free_done
|
||||
push [eax+usb_pipe.NextSibling]
|
||||
stdcall [edi+usb_hardware_func.FreePipe], eax
|
||||
pop eax
|
||||
jmp .free_loop
|
||||
.free_done:
|
||||
stdcall [edi+usb_hardware_func.FreePipe], ebx
|
||||
pop eax
|
||||
; 9. Free the usb_device_data structure.
|
||||
sub eax, usb_device_data.ClosedPipeList - usb_pipe.NextSibling
|
||||
call free
|
||||
; 10. Return.
|
||||
.nothing:
|
||||
pop edi
|
||||
ret
|
||||
endp
|
||||
|
||||
; This procedure is called when a pipe with USB_FLAG_DISABLED is removed from the
|
||||
; corresponding wait list. It means that the hardware has fully forgot about it.
|
||||
; ebx -> usb_pipe, esi -> usb_controller
|
||||
proc usb_pipe_disabled
|
||||
push edi
|
||||
mov edi, [esi+usb_controller.HardwareFunc]
|
||||
; 1. Acquire pipe lock.
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_lock
|
||||
; 2. Clear USB_FLAG_DISABLED in pipe state.
|
||||
and [ebx+usb_pipe.Flags], not USB_FLAG_DISABLED
|
||||
; 3. Sanity check: ignore uninitialized pipes.
|
||||
cmp [ebx+usb_pipe.LastTD], 0
|
||||
jz .no_transfer
|
||||
; 4. Acquire the first and last to-be-cancelled transfer descriptor,
|
||||
; save them in stack for the step 6,
|
||||
; ask the controller driver to enable the pipe for hardware,
|
||||
; removing transfers between first and last to-be-cancelled descriptors.
|
||||
lea ecx, [esi+usb_controller.ControlLock]
|
||||
cmp [ebx+usb_pipe.Type], BULK_PIPE
|
||||
jb @f ; control pipe
|
||||
lea ecx, [esi+usb_controller.BulkLock]
|
||||
jz @f ; bulk pipe
|
||||
lea ecx, [esi+usb_controller.PeriodicLock]
|
||||
@@:
|
||||
call mutex_lock
|
||||
mov eax, [ebx+usb_pipe.BaseList]
|
||||
mov edx, [eax+usb_pipe.NextVirt]
|
||||
mov [ebx+usb_pipe.NextVirt], edx
|
||||
mov [ebx+usb_pipe.PrevVirt], eax
|
||||
mov [edx+usb_pipe.PrevVirt], ebx
|
||||
mov [eax+usb_pipe.NextVirt], ebx
|
||||
mov eax, [ebx+usb_pipe.LastTD]
|
||||
mov edx, [eax+usb_gtd.NextVirt]
|
||||
mov [eax+usb_gtd.NextVirt], eax
|
||||
mov [eax+usb_gtd.PrevVirt], eax
|
||||
push eax
|
||||
push edx
|
||||
push ecx
|
||||
call [edi+usb_hardware_func.EnablePipe]
|
||||
pop ecx
|
||||
call mutex_unlock
|
||||
; 5. Release pipe lock acquired at step 1.
|
||||
; Callbacks called at step 6 can insert new transfers,
|
||||
; so we cannot call usb_pipe_aborted while holding pipe lock.
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_unlock
|
||||
; 6. Notify all registered callbacks with status USB_STATUS_CANCELLED, if any.
|
||||
; Two arguments describing transfers range were pushed at step 4.
|
||||
push USB_STATUS_CANCELLED
|
||||
call usb_pipe_aborted
|
||||
pop edi
|
||||
ret
|
||||
.no_transfer:
|
||||
call mutex_unlock
|
||||
pop edi
|
||||
ret
|
||||
endp
|
||||
|
||||
; Part of API for drivers, see documentation for USBNormalTransferAsync.
|
||||
proc usb_normal_transfer_async stdcall uses ebx edi,\
|
||||
pipe:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
|
||||
; 1. Sanity check: callback must be nonzero.
|
||||
; (It is important for other parts of code.)
|
||||
xor eax, eax
|
||||
cmp [callback], eax
|
||||
jz .nothing
|
||||
; 2. Lock the transfer queue.
|
||||
mov ebx, [pipe]
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_lock
|
||||
; 3. If the pipe has already been closed (presumably due to device disconnect),
|
||||
; release the lock taken in step 2 and return zero.
|
||||
xor eax, eax
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
|
||||
jnz .unlock
|
||||
; 4. Allocate and initialize TDs for the transfer.
|
||||
mov edx, [ebx+usb_pipe.Controller]
|
||||
mov edi, [edx+usb_controller.HardwareFunc]
|
||||
stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], [ebx+usb_pipe.LastTD], 0
|
||||
; If failed, release the lock taken in step 2 and return zero.
|
||||
test eax, eax
|
||||
jz .unlock
|
||||
; 5. Store callback and its parameters in the last descriptor for this transfer.
|
||||
mov ecx, [eax+usb_gtd.PrevVirt]
|
||||
mov edx, [callback]
|
||||
mov [ecx+usb_gtd.Callback], edx
|
||||
mov edx, [calldata]
|
||||
mov [ecx+usb_gtd.UserData], edx
|
||||
mov edx, [buffer]
|
||||
mov [ecx+usb_gtd.Buffer], edx
|
||||
; 6. Advance LastTD pointer and activate transfer.
|
||||
push [ebx+usb_pipe.LastTD]
|
||||
mov [ebx+usb_pipe.LastTD], eax
|
||||
call [edi+usb_hardware_func.InsertTransfer]
|
||||
pop eax
|
||||
; 7. Release the lock taken in step 2 and
|
||||
; return pointer to the first descriptor for the new transfer.
|
||||
.unlock:
|
||||
push eax
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_unlock
|
||||
pop eax
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Part of API for drivers, see documentation for USBControlTransferAsync.
|
||||
proc usb_control_async stdcall uses ebx edi,\
|
||||
pipe:dword, config:dword, buffer:dword, size:dword, callback:dword, calldata:dword, flags:dword
|
||||
locals
|
||||
last_td dd ?
|
||||
endl
|
||||
; 1. Sanity check: callback must be nonzero.
|
||||
; (It is important for other parts of code.)
|
||||
cmp [callback], 0
|
||||
jz .return0
|
||||
; 2. Lock the transfer queue.
|
||||
mov ebx, [pipe]
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_lock
|
||||
; 3. If the pipe has already been closed (presumably due to device disconnect),
|
||||
; release the lock taken in step 2 and return zero.
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_CLOSED
|
||||
jnz .unlock_return0
|
||||
; A control transfer contains two or three stages:
|
||||
; Setup stage, optional Data stage, Status stage.
|
||||
; 4. Allocate and initialize TDs for the Setup stage.
|
||||
; Payload is 8 bytes from [config].
|
||||
mov edx, [ebx+usb_pipe.Controller]
|
||||
mov edi, [edx+usb_controller.HardwareFunc]
|
||||
stdcall [edi+usb_hardware_func.AllocTransfer], [config], 8, 0, [ebx+usb_pipe.LastTD], (2 shl 2) + 0
|
||||
; short transfer is an error, direction is DATA0, token is SETUP
|
||||
mov [last_td], eax
|
||||
test eax, eax
|
||||
jz .fail
|
||||
; 5. Allocate and initialize TDs for the Data stage, if [size] is nonzero.
|
||||
; Payload is [size] bytes from [buffer].
|
||||
mov edx, [config]
|
||||
mov ecx, (3 shl 2) + 1 ; DATA1, token is OUT
|
||||
cmp byte [edx], 0
|
||||
jns @f
|
||||
cmp [size], 0
|
||||
jz @f
|
||||
inc ecx ; token is IN
|
||||
@@:
|
||||
cmp [size], 0
|
||||
jz .nodata
|
||||
push ecx
|
||||
stdcall [edi+usb_hardware_func.AllocTransfer], [buffer], [size], [flags], eax, ecx
|
||||
pop ecx
|
||||
test eax, eax
|
||||
jz .fail
|
||||
mov [last_td], eax
|
||||
.nodata:
|
||||
; 6. Allocate and initialize TDs for the Status stage.
|
||||
; No payload.
|
||||
xor ecx, 3 ; IN becomes OUT, OUT becomes IN
|
||||
stdcall [edi+usb_hardware_func.AllocTransfer], 0, 0, 0, eax, ecx
|
||||
test eax, eax
|
||||
jz .fail
|
||||
; 7. Store callback and its parameters in the last descriptor for this transfer.
|
||||
mov ecx, [eax+usb_gtd.PrevVirt]
|
||||
mov edx, [callback]
|
||||
mov [ecx+usb_gtd.Callback], edx
|
||||
mov edx, [calldata]
|
||||
mov [ecx+usb_gtd.UserData], edx
|
||||
mov edx, [buffer]
|
||||
mov [ecx+usb_gtd.Buffer], edx
|
||||
; 8. Advance LastTD pointer and activate transfer.
|
||||
push [ebx+usb_pipe.LastTD]
|
||||
mov [ebx+usb_pipe.LastTD], eax
|
||||
call [edi+usb_hardware_func.InsertTransfer]
|
||||
; 9. Release the lock taken in step 2 and
|
||||
; return pointer to the first descriptor for the new transfer.
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_unlock
|
||||
pop eax
|
||||
ret
|
||||
.fail:
|
||||
mov eax, [last_td]
|
||||
test eax, eax
|
||||
jz .unlock_return0
|
||||
stdcall usb_undo_tds, [ebx+usb_pipe.LastTD]
|
||||
.unlock_return0:
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_unlock
|
||||
.return0:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
; Part of API for drivers, see documentation for USBAbortPipe.
|
||||
proc usb_abort_pipe
|
||||
push ebx esi ; save used registers to be stdcall
|
||||
virtual at esp
|
||||
rd 2 ; saved registers
|
||||
dd ? ; return address
|
||||
.pipe dd ?
|
||||
end virtual
|
||||
mov ebx, [.pipe]
|
||||
; 1. Acquire pipe lock.
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_lock
|
||||
; 2. If the pipe is already closed or abort is in progress,
|
||||
; just release pipe lock and return.
|
||||
test [ebx+usb_pipe.Flags], USB_FLAG_CLOSED + USB_FLAG_DISABLED
|
||||
jnz .nothing
|
||||
; 3. Mark the pipe as aborting.
|
||||
or [ebx+usb_pipe.Flags], USB_FLAG_DISABLED
|
||||
; 4. We cannot do anything except adding new transfers concurrently with hardware.
|
||||
; Ask the controller driver to (temporarily) remove the pipe from hardware queue.
|
||||
mov esi, [ebx+usb_pipe.Controller]
|
||||
; 4a. Acquire queue lock.
|
||||
lea ecx, [esi+usb_controller.ControlLock]
|
||||
cmp [ebx+usb_pipe.Type], BULK_PIPE
|
||||
jb @f ; control pipe
|
||||
lea ecx, [esi+usb_controller.BulkLock]
|
||||
jz @f ; bulk pipe
|
||||
lea ecx, [esi+usb_controller.PeriodicLock]
|
||||
@@:
|
||||
call mutex_lock
|
||||
push ecx
|
||||
; 4b. Call the driver.
|
||||
mov eax, [esi+usb_controller.HardwareFunc]
|
||||
call [eax+usb_hardware_func.DisablePipe]
|
||||
; 4c. Remove the pipe from software list.
|
||||
mov eax, [ebx+usb_pipe.NextVirt]
|
||||
mov edx, [ebx+usb_pipe.PrevVirt]
|
||||
mov [eax+usb_pipe.PrevVirt], edx
|
||||
mov [edx+usb_pipe.NextVirt], eax
|
||||
; 4c. Register the pipe in corresponding wait list.
|
||||
test [ebx+usb_pipe.Type], 1
|
||||
jz .control_bulk
|
||||
call usb_subscribe_periodic
|
||||
jmp @f
|
||||
.control_bulk:
|
||||
call usb_subscribe_control
|
||||
@@:
|
||||
; 4d. Release queue lock.
|
||||
pop ecx
|
||||
call mutex_unlock
|
||||
; 4e. Notify the USB thread about new work.
|
||||
push ebx esi edi
|
||||
call usb_wakeup
|
||||
pop edi esi ebx
|
||||
; That's all for now. To be continued in usb_pipe_disabled.
|
||||
; 5. Release pipe lock acquired at step 1 and return.
|
||||
.nothing:
|
||||
lea ecx, [ebx+usb_pipe.Lock]
|
||||
call mutex_unlock
|
||||
pop esi ebx
|
||||
ret 4
|
||||
endp
|
||||
|
||||
; Part of API for drivers, see documentation for USBGetParam.
|
||||
proc usb_get_param
|
||||
virtual at esp
|
||||
dd ? ; return address
|
||||
.pipe dd ?
|
||||
.param dd ?
|
||||
end virtual
|
||||
mov edx, [.param]
|
||||
mov ecx, [.pipe]
|
||||
mov eax, [ecx+usb_pipe.DeviceData]
|
||||
test edx, edx
|
||||
jz .get_device_descriptor
|
||||
dec edx
|
||||
jz .get_config_descriptor
|
||||
dec edx
|
||||
jz .get_speed
|
||||
or eax, -1
|
||||
ret 8
|
||||
.get_device_descriptor:
|
||||
add eax, usb_device_data.DeviceDescriptor
|
||||
ret 8
|
||||
.get_config_descriptor:
|
||||
movzx ecx, [eax+usb_device_data.DeviceDescrSize]
|
||||
lea eax, [eax+ecx+usb_device_data.DeviceDescriptor]
|
||||
ret 8
|
||||
.get_speed:
|
||||
movzx eax, [eax+usb_device_data.Speed]
|
||||
ret 8
|
||||
endp
|
||||
|
||||
; Initialize software part of usb_gtd. Called from controller-specific code
|
||||
; somewhere in AllocTransfer with eax -> next (inactive) usb_gtd,
|
||||
; ebx -> usb_pipe, ebp frame from call to AllocTransfer with [.td] ->
|
||||
; current (initializing) usb_gtd.
|
||||
; Returns ecx = [.td].
|
||||
proc usb_init_transfer
|
||||
virtual at ebp-4
|
||||
.Size dd ?
|
||||
rd 2
|
||||
.Buffer dd ?
|
||||
dd ?
|
||||
.Flags dd ?
|
||||
.td dd ?
|
||||
end virtual
|
||||
mov [eax+usb_gtd.Pipe], ebx
|
||||
mov ecx, [.td]
|
||||
mov [eax+usb_gtd.PrevVirt], ecx
|
||||
mov edx, [ecx+usb_gtd.NextVirt]
|
||||
mov [ecx+usb_gtd.NextVirt], eax
|
||||
mov [eax+usb_gtd.NextVirt], edx
|
||||
mov [edx+usb_gtd.PrevVirt], eax
|
||||
mov edx, [.Size]
|
||||
mov [ecx+usb_gtd.Length], edx
|
||||
xor edx, edx
|
||||
mov [ecx+usb_gtd.Callback], edx
|
||||
mov [ecx+usb_gtd.UserData], edx
|
||||
ret
|
||||
endp
|
||||
|
||||
; Free all TDs for the current transfer if something has failed
|
||||
; during initialization (e.g. no memory for the next TD).
|
||||
; Stdcall with one stack argument = first TD for the transfer
|
||||
; and eax = last initialized TD for the transfer.
|
||||
proc usb_undo_tds
|
||||
push [eax+usb_gtd.NextVirt]
|
||||
@@:
|
||||
cmp eax, [esp+8]
|
||||
jz @f
|
||||
push [eax+usb_gtd.PrevVirt]
|
||||
stdcall [edi+usb_hardware_func.FreeTD], eax
|
||||
pop eax
|
||||
jmp @b
|
||||
@@:
|
||||
pop ecx
|
||||
mov [eax+usb_gtd.NextVirt], ecx
|
||||
mov [ecx+usb_gtd.PrevVirt], eax
|
||||
ret 4
|
||||
endp
|
||||
|
||||
; Helper procedure for handling short packets in controller-specific code.
|
||||
; Returns with CF cleared if this is the final packet in some stage:
|
||||
; for control transfers that means one of Data and Status stages,
|
||||
; for other transfers - the final packet in the only stage.
|
||||
proc usb_is_final_packet
|
||||
cmp [ebx+usb_gtd.Callback], 0
|
||||
jnz .nothing
|
||||
mov eax, [ebx+usb_gtd.NextVirt]
|
||||
cmp [eax+usb_gtd.Callback], 0
|
||||
jz .stc
|
||||
mov eax, [ebx+usb_gtd.Pipe]
|
||||
cmp [eax+usb_pipe.Type], CONTROL_PIPE
|
||||
jz .nothing
|
||||
.stc:
|
||||
stc
|
||||
.nothing:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Helper procedure for controller-specific code:
|
||||
; removes one TD from the transfer queue, ebx -> usb_gtd to remove.
|
||||
proc usb_unlink_td
|
||||
mov ecx, [ebx+usb_gtd.Pipe]
|
||||
add ecx, usb_pipe.Lock
|
||||
call mutex_lock
|
||||
mov eax, [ebx+usb_gtd.PrevVirt]
|
||||
mov edx, [ebx+usb_gtd.NextVirt]
|
||||
mov [edx+usb_gtd.PrevVirt], eax
|
||||
mov [eax+usb_gtd.NextVirt], edx
|
||||
call mutex_unlock
|
||||
ret
|
||||
endp
|
||||
|
||||
; One part of transfer is completed, run the associated callback
|
||||
; or update total length in the next part of transfer.
|
||||
; in: ebx -> usb_gtd, ecx = status, edx = length
|
||||
proc usb_process_gtd
|
||||
; 1. Test whether it is the last descriptor in the transfer
|
||||
; <=> it has an associated callback.
|
||||
mov eax, [ebx+usb_gtd.Callback]
|
||||
test eax, eax
|
||||
jz .nocallback
|
||||
; 2. It has an associated callback; call it with corresponding parameters.
|
||||
stdcall_verify eax, [ebx+usb_gtd.Pipe], ecx, \
|
||||
[ebx+usb_gtd.Buffer], edx, [ebx+usb_gtd.UserData]
|
||||
ret
|
||||
.nocallback:
|
||||
; 3. It is an intermediate descriptor. Add its length to the length
|
||||
; in the following descriptor.
|
||||
mov eax, [ebx+usb_gtd.NextVirt]
|
||||
add [eax+usb_gtd.Length], edx
|
||||
ret
|
||||
endp
|
||||
|
||||
if USB_STDCALL_VERIFY
|
||||
proc verify_regs
|
||||
virtual at esp
|
||||
dd ? ; return address
|
||||
.edi dd ?
|
||||
.esi dd ?
|
||||
.ebp dd ?
|
||||
.esp dd ?
|
||||
.ebx dd ?
|
||||
.edx dd ?
|
||||
.ecx dd ?
|
||||
.eax dd ?
|
||||
end virtual
|
||||
cmp ebx, [.ebx]
|
||||
jz @f
|
||||
dbgstr 'ERROR!!! ebx changed'
|
||||
@@:
|
||||
cmp esi, [.esi]
|
||||
jz @f
|
||||
dbgstr 'ERROR!!! esi changed'
|
||||
@@:
|
||||
cmp edi, [.edi]
|
||||
jz @f
|
||||
dbgstr 'ERROR!!! edi changed'
|
||||
@@:
|
||||
cmp ebp, [.ebp]
|
||||
jz @f
|
||||
dbgstr 'ERROR!!! ebp changed'
|
||||
@@:
|
||||
ret
|
||||
endp
|
||||
end if
|
||||
1019
kernel/branches/kolibri-lldw/bus/usb/protocol.inc
Normal file
1019
kernel/branches/kolibri-lldw/bus/usb/protocol.inc
Normal file
File diff suppressed because it is too large
Load Diff
989
kernel/branches/kolibri-lldw/const.inc
Normal file
989
kernel/branches/kolibri-lldw/const.inc
Normal file
@@ -0,0 +1,989 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
dpl0 = 10010000b ; data read dpl0
|
||||
drw0 = 10010010b ; data read/write dpl0
|
||||
drw3 = 11110010b ; data read/write dpl3
|
||||
cpl0 = 10011010b ; code read dpl0
|
||||
cpl3 = 11111010b ; code read dpl3
|
||||
|
||||
D32 = 01000000b ; 32bit segment
|
||||
G32 = 10000000b ; page gran
|
||||
|
||||
;;;;;;;;;;; task manager errors ;;;;;;;;;;
|
||||
|
||||
TASKMAN_ERROR_OUT_OF_MEMORY = 30 ; 0x1E
|
||||
TASKMAN_ERROR_NOT_A_EXECUTABLE = 31 ; 0x1F
|
||||
TASKMAN_ERROR_TOO_MANY_PROCESSES = 32 ; 0x20
|
||||
|
||||
;;;;;;;;;;;;cpu_caps flags;;;;;;;;;;;;;;;;
|
||||
|
||||
CPU_386 = 3
|
||||
CPU_486 = 4
|
||||
CPU_PENTIUM = 5
|
||||
CPU_P6 = 6
|
||||
CPU_PENTIUM4 = 0x0F
|
||||
|
||||
CAPS_FPU = 00 ;on-chip x87 floating point unit
|
||||
CAPS_VME = 01 ;virtual-mode enhancements
|
||||
CAPS_DE = 02 ;debugging extensions
|
||||
CAPS_PSE = 03 ;page-size extensions
|
||||
CAPS_TSC = 04 ;time stamp counter
|
||||
CAPS_MSR = 05 ;model-specific registers
|
||||
CAPS_PAE = 06 ;physical-address extensions
|
||||
CAPS_MCE = 07 ;machine check exception
|
||||
CAPS_CX8 = 08 ;CMPXCHG8B instruction
|
||||
CAPS_APIC = 09 ;on-chip advanced programmable
|
||||
;interrupt controller
|
||||
; 10 ;unused
|
||||
CAPS_SEP = 11 ;SYSENTER and SYSEXIT instructions
|
||||
CAPS_MTRR = 12 ;memory-type range registers
|
||||
CAPS_PGE = 13 ;page global extension
|
||||
CAPS_MCA = 14 ;machine check architecture
|
||||
CAPS_CMOV = 15 ;conditional move instructions
|
||||
CAPS_PAT = 16 ;page attribute table
|
||||
|
||||
CAPS_PSE36 = 17 ;page-size extensions
|
||||
CAPS_PSN = 18 ;processor serial number
|
||||
CAPS_CLFLUSH = 19 ;CLFUSH instruction
|
||||
|
||||
CAPS_DS = 21 ;debug store
|
||||
CAPS_ACPI = 22 ;thermal monitor and software
|
||||
;controlled clock supported
|
||||
CAPS_MMX = 23 ;MMX instructions
|
||||
CAPS_FXSR = 24 ;FXSAVE and FXRSTOR instructions
|
||||
CAPS_SSE = 25 ;SSE instructions
|
||||
CAPS_SSE2 = 26 ;SSE2 instructions
|
||||
CAPS_SS = 27 ;self-snoop
|
||||
CAPS_HTT = 28 ;hyper-threading technology
|
||||
CAPS_TM = 29 ;thermal monitor supported
|
||||
CAPS_IA64 = 30 ;IA64 capabilities
|
||||
CAPS_PBE = 31 ;pending break enable
|
||||
|
||||
;ecx
|
||||
CAPS_SSE3 = 32 ;SSE3 instructions
|
||||
; 33
|
||||
; 34
|
||||
CAPS_MONITOR = 35 ;MONITOR/MWAIT instructions
|
||||
CAPS_DS_CPL = 36 ;
|
||||
CAPS_VMX = 37 ;virtual mode extensions
|
||||
; 38 ;
|
||||
CAPS_EST = 39 ;enhansed speed step
|
||||
CAPS_TM2 = 40 ;thermal monitor2 supported
|
||||
; 41
|
||||
CAPS_CID = 42 ;
|
||||
; 43
|
||||
; 44
|
||||
CAPS_CX16 = 45 ;CMPXCHG16B instruction
|
||||
CAPS_xTPR = 46 ;
|
||||
CAPS_XSAVE = 32 + 26 ; XSAVE and XRSTOR instructions
|
||||
CAPS_OSXSAVE = 32 + 27
|
||||
; A value of 1 indicates that the OS has set CR4.OSXSAVE[bit 18] to enable
|
||||
; XSETBV/XGETBV instructions to access XCR0 and to support processor extended
|
||||
; state management using XSAVE/XRSTOR.
|
||||
CAPS_AVX = 32 + 28 ; not AVX2
|
||||
;
|
||||
;reserved
|
||||
;
|
||||
;ext edx /ecx
|
||||
CAPS_SYSCAL = 64 ;
|
||||
CAPS_XD = 65 ;execution disable
|
||||
CAPS_FFXSR = 66 ;
|
||||
CAPS_RDTSCP = 67 ;
|
||||
CAPS_X64 = 68 ;
|
||||
CAPS_3DNOW = 69 ;
|
||||
CAPS_3DNOWEXT = 70 ;
|
||||
CAPS_LAHF = 71 ;
|
||||
CAPS_CMP_LEG = 72 ;
|
||||
CAPS_SVM = 73 ;secure virual machine
|
||||
CAPS_ALTMOVCR8 = 74 ;
|
||||
|
||||
; CPU MSR names
|
||||
MSR_SYSENTER_CS = 0x174
|
||||
MSR_SYSENTER_ESP = 0x175
|
||||
MSR_SYSENTER_EIP = 0x176
|
||||
MSR_CR_PAT = 0x277
|
||||
MSR_MTRR_DEF_TYPE = 0x2FF
|
||||
|
||||
MSR_AMD_EFER = 0xC0000080 ; Extended Feature Enable Register
|
||||
MSR_AMD_STAR = 0xC0000081 ; SYSCALL/SYSRET Target Address Register
|
||||
|
||||
CR0_PE = 0x00000001 ;protected mode
|
||||
CR0_MP = 0x00000002 ;monitor fpu
|
||||
CR0_EM = 0x00000004 ;fpu emulation
|
||||
CR0_TS = 0x00000008 ;task switch
|
||||
CR0_ET = 0x00000010 ;extension type hardcoded to 1
|
||||
CR0_NE = 0x00000020 ;numeric error
|
||||
CR0_WP = 0x00010000 ;write protect
|
||||
CR0_AM = 0x00040000 ;alignment check
|
||||
CR0_NW = 0x20000000 ;not write-through
|
||||
CR0_CD = 0x40000000 ;cache disable
|
||||
CR0_PG = 0x80000000 ;paging
|
||||
|
||||
|
||||
CR4_VME = 0x000001
|
||||
CR4_PVI = 0x000002
|
||||
CR4_TSD = 0x000004
|
||||
CR4_DE = 0x000008
|
||||
CR4_PSE = 0x000010
|
||||
CR4_PAE = 0x000020
|
||||
CR4_MCE = 0x000040
|
||||
CR4_PGE = 0x000080
|
||||
CR4_PCE = 0x000100
|
||||
CR4_OSFXSR = 0x000200
|
||||
CR4_OSXMMEXPT = 0x000400
|
||||
CR4_OSXSAVE = 0x040000
|
||||
|
||||
XCR0_FPU_MMX = 0x0001
|
||||
XCR0_SSE = 0x0002
|
||||
XCR0_AVX = 0x0004
|
||||
XCR0_MPX = 0x0018
|
||||
XCR0_AVX512 = 0x00e0
|
||||
|
||||
MXCSR_IE = 0x0001
|
||||
MXCSR_DE = 0x0002
|
||||
MXCSR_ZE = 0x0004
|
||||
MXCSR_OE = 0x0008
|
||||
MXCSR_UE = 0x0010
|
||||
MXCSR_PE = 0x0020
|
||||
MXCSR_DAZ = 0x0040
|
||||
MXCSR_IM = 0x0080
|
||||
MXCSR_DM = 0x0100
|
||||
MXCSR_ZM = 0x0200
|
||||
MXCSR_OM = 0x0400
|
||||
MXCSR_UM = 0x0800
|
||||
MXCSR_PM = 0x1000
|
||||
MXCSR_FZ = 0x8000
|
||||
|
||||
MXCSR_INIT = MXCSR_IM + MXCSR_DM + MXCSR_ZM + MXCSR_OM + MXCSR_UM + MXCSR_PM
|
||||
|
||||
EFLAGS_CF = 0x000001 ; carry flag
|
||||
EFLAGS_PF = 0x000004 ; parity flag
|
||||
EFLAGS_AF = 0x000010 ; auxiliary flag
|
||||
EFLAGS_ZF = 0x000040 ; zero flag
|
||||
EFLAGS_SF = 0x000080 ; sign flag
|
||||
EFLAGS_TF = 0x000100 ; trap flag
|
||||
EFLAGS_IF = 0x000200 ; interrupt flag
|
||||
EFLAGS_DF = 0x000400 ; direction flag
|
||||
EFLAGS_OF = 0x000800 ; overflow flag
|
||||
EFLAGS_IOPL = 0x003000 ; i/o priviledge level
|
||||
EFLAGS_NT = 0x004000 ; nested task flag
|
||||
EFLAGS_RF = 0x010000 ; resume flag
|
||||
EFLAGS_VM = 0x020000 ; virtual 8086 mode flag
|
||||
EFLAGS_AC = 0x040000 ; alignment check flag
|
||||
EFLAGS_VIF = 0x080000 ; virtual interrupt flag
|
||||
EFLAGS_VIP = 0x100000 ; virtual interrupt pending
|
||||
EFLAGS_ID = 0x200000 ; id flag
|
||||
|
||||
IRQ_PIC = 0
|
||||
IRQ_APIC = 1
|
||||
|
||||
struct TSS
|
||||
_back rw 2
|
||||
_esp0 rd 1
|
||||
_ss0 rw 2
|
||||
_esp1 rd 1
|
||||
_ss1 rw 2
|
||||
_esp2 rd 1
|
||||
_ss2 rw 2
|
||||
_cr3 rd 1
|
||||
_eip rd 1
|
||||
_eflags rd 1
|
||||
_eax rd 1
|
||||
_ecx rd 1
|
||||
_edx rd 1
|
||||
_ebx rd 1
|
||||
_esp rd 1
|
||||
_ebp rd 1
|
||||
_esi rd 1
|
||||
_edi rd 1
|
||||
_es rw 2
|
||||
_cs rw 2
|
||||
_ss rw 2
|
||||
_ds rw 2
|
||||
_fs rw 2
|
||||
_gs rw 2
|
||||
_ldt rw 2
|
||||
_trap rw 1
|
||||
_io rw 1
|
||||
rb 24
|
||||
_io_map_0 rb 4096
|
||||
_io_map_1 rb 4096
|
||||
ends
|
||||
|
||||
DRIVE_DATA_SIZE = 16
|
||||
|
||||
OS_BASE = 0x80000000
|
||||
|
||||
window_data = OS_BASE + 0x0001000
|
||||
|
||||
TASK_TABLE = OS_BASE + 0x0003000
|
||||
;CURRENT_TASK = OS_BASE + 0x0003000
|
||||
;TASK_COUNT = OS_BASE + 0x0003004
|
||||
TASK_BASE = OS_BASE + 0x0003010
|
||||
TASK_DATA = OS_BASE + 0x0003020
|
||||
;TASK_EVENT = OS_BASE + 0x0003020
|
||||
|
||||
CDDataBuf = OS_BASE + 0x0005000
|
||||
|
||||
;unused 0x6000 - 0x8fff
|
||||
|
||||
BOOT_VARS = 0x9000
|
||||
|
||||
idts = OS_BASE + 0x000B100
|
||||
WIN_STACK = OS_BASE + 0x000C000
|
||||
WIN_POS = OS_BASE + 0x000C400
|
||||
FDD_BUFF = OS_BASE + 0x000D000 ;512
|
||||
|
||||
WIN_TEMP_XY = OS_BASE + 0x000F300
|
||||
KEY_COUNT = OS_BASE + 0x000F400
|
||||
KEY_BUFF = OS_BASE + 0x000F401 ; 120*2 + 2*2 = 244 bytes, actually 255 bytes
|
||||
|
||||
BTN_COUNT = OS_BASE + 0x000F500
|
||||
BTN_BUFF = OS_BASE + 0x000F501
|
||||
|
||||
|
||||
BTN_ADDR = OS_BASE + 0x000FE88
|
||||
MEM_AMOUNT = OS_BASE + 0x000FE8C
|
||||
|
||||
SYS_SHUTDOWN = OS_BASE + 0x000FF00
|
||||
|
||||
|
||||
TMP_STACK_TOP = 0x007CC00
|
||||
|
||||
sys_proc = OS_BASE + 0x007E000
|
||||
|
||||
SLOT_BASE = OS_BASE + 0x0080000
|
||||
|
||||
VGABasePtr = OS_BASE + 0x00A0000
|
||||
|
||||
virtual at OS_BASE + 0x05FFF80
|
||||
tss TSS
|
||||
end virtual
|
||||
|
||||
HEAP_BASE = OS_BASE + 0x0800000
|
||||
HEAP_MIN_SIZE = 0x01000000
|
||||
|
||||
page_tabs = 0xFDC00000
|
||||
app_page_tabs = 0xFDC00000
|
||||
kernel_tabs = page_tabs + (OS_BASE shr 10) ;0xFDE00000
|
||||
master_tab = page_tabs + (page_tabs shr 10) ;0xFDFF70000
|
||||
|
||||
LFB_BASE = 0xFE000000
|
||||
|
||||
|
||||
new_app_base = 0;
|
||||
|
||||
twdw = TASK_TABLE - window_data
|
||||
|
||||
std_application_base_address = new_app_base
|
||||
RING0_STACK_SIZE = 0x2000
|
||||
|
||||
REG_SS = RING0_STACK_SIZE - 4
|
||||
REG_APP_ESP = RING0_STACK_SIZE - 8
|
||||
REG_EFLAGS = RING0_STACK_SIZE - 12
|
||||
REG_CS = RING0_STACK_SIZE - 16
|
||||
REG_EIP = RING0_STACK_SIZE - 20
|
||||
REG_EAX = RING0_STACK_SIZE - 24
|
||||
REG_ECX = RING0_STACK_SIZE - 28
|
||||
REG_EDX = RING0_STACK_SIZE - 32
|
||||
REG_EBX = RING0_STACK_SIZE - 36
|
||||
REG_ESP = RING0_STACK_SIZE - 40 ;RING0_STACK_SIZE-20
|
||||
REG_EBP = RING0_STACK_SIZE - 44
|
||||
REG_ESI = RING0_STACK_SIZE - 48
|
||||
REG_EDI = RING0_STACK_SIZE - 52
|
||||
REG_RET = RING0_STACK_SIZE - 56 ;irq0.return
|
||||
|
||||
|
||||
PAGE_SIZE = 4096
|
||||
|
||||
PG_UNMAP = 0x000
|
||||
PG_READ = 0x001
|
||||
PG_WRITE = 0x002
|
||||
PG_USER = 0x004
|
||||
PG_PCD = 0x008
|
||||
PG_PWT = 0x010
|
||||
PG_ACCESSED = 0x020
|
||||
PG_DIRTY = 0x040
|
||||
PG_PAT = 0x080
|
||||
PG_GLOBAL = 0x100
|
||||
PG_SHARED = 0x200
|
||||
|
||||
PG_SWR = 0x003 ; PG_WRITE + PG_READ
|
||||
PG_UR = 0x005 ; PG_USER + PG_READ
|
||||
PG_UWR = 0x007 ; PG_USER + PG_WRITE + PG_READ
|
||||
PG_NOCACHE = 0x018 ; PG_PCD + PG_PWT
|
||||
|
||||
PDE_LARGE = 0x080
|
||||
|
||||
MEM_WB = 6 ; write-back memory
|
||||
MEM_WC = 1 ; write combined memory
|
||||
MEM_UC = 0 ; uncached memory
|
||||
|
||||
PAT_WB = 0x000
|
||||
PAT_WC = 0x008
|
||||
PAT_UCM = 0x010
|
||||
PAT_UC = 0x018
|
||||
|
||||
PAT_TYPE_UC = 0
|
||||
PAT_TYPE_WC = 1
|
||||
PAT_TYPE_WB = 6
|
||||
PAT_TYPE_UCM = 7
|
||||
|
||||
PAT_VALUE = 0x00070106; (UC<<24)|(UCM<<16)|(WC<<8)|WB
|
||||
|
||||
MAX_MEMMAP_BLOCKS = 32
|
||||
|
||||
EVENT_REDRAW = 0x00000001
|
||||
EVENT_KEY = 0x00000002
|
||||
EVENT_BUTTON = 0x00000004
|
||||
EVENT_BACKGROUND = 0x00000010
|
||||
EVENT_MOUSE = 0x00000020
|
||||
EVENT_IPC = 0x00000040
|
||||
EVENT_NETWORK = 0x00000080
|
||||
EVENT_DEBUG = 0x00000100
|
||||
EVENT_NETWORK2 = 0x00000200
|
||||
EVENT_EXTENDED = 0x00000400
|
||||
|
||||
EV_INTR = 1
|
||||
|
||||
STDIN_FILENO = 0
|
||||
STDOUT_FILENO = 1
|
||||
STDERR_FILENO = 2
|
||||
|
||||
SYSTEM_SHUTDOWN = 2
|
||||
SYSTEM_REBOOT = 3
|
||||
SYSTEM_RESTART = 4
|
||||
|
||||
BLIT_CLIENT_RELATIVE = 0x20000000
|
||||
|
||||
struct SYSCALL_STACK
|
||||
_eip dd ?
|
||||
_edi dd ? ; +4
|
||||
_esi dd ? ; +8
|
||||
_ebp dd ? ; +12
|
||||
_esp dd ? ; +16
|
||||
_ebx dd ? ; +20
|
||||
_edx dd ? ; +24
|
||||
_ecx dd ? ; +28
|
||||
_eax dd ? ; +32
|
||||
ends
|
||||
|
||||
struct LHEAD
|
||||
next dd ? ;next object in list
|
||||
prev dd ? ;prev object in list
|
||||
ends
|
||||
|
||||
struct MUTEX_WAITER
|
||||
list LHEAD
|
||||
task dd ?
|
||||
type dd ?
|
||||
ends
|
||||
|
||||
struct MUTEX
|
||||
wait_list LHEAD
|
||||
count dd ?
|
||||
ends
|
||||
|
||||
struct RWSEM
|
||||
wait_list LHEAD
|
||||
count dd ?
|
||||
ends
|
||||
|
||||
struct FUTEX
|
||||
list LHEAD
|
||||
magic dd ?
|
||||
handle dd ?
|
||||
destroy dd ?
|
||||
|
||||
wait_list LHEAD
|
||||
pointer dd ?
|
||||
flags dd ?
|
||||
ends
|
||||
|
||||
FUTEX_INIT = 0
|
||||
FUTEX_DESTROY = 1
|
||||
FUTEX_WAIT = 2
|
||||
FUTEX_WAKE = 3
|
||||
|
||||
struct FILED
|
||||
list LHEAD
|
||||
magic rd 1
|
||||
handle rd 1
|
||||
destroy rd 1
|
||||
mode rd 1
|
||||
file rd 1
|
||||
ends
|
||||
|
||||
struct PIPE
|
||||
pipe_ops rd 1
|
||||
buffer rd 1
|
||||
readers rd 1
|
||||
writers rd 1
|
||||
|
||||
pipe_lock MUTEX
|
||||
count rd 1
|
||||
|
||||
read_end rd 1
|
||||
write_end rd 1
|
||||
rlist LHEAD
|
||||
wlist LHEAD
|
||||
ends
|
||||
|
||||
struct PROC
|
||||
list LHEAD
|
||||
thr_list LHEAD
|
||||
heap_lock MUTEX
|
||||
heap_base rd 1
|
||||
heap_top rd 1
|
||||
mem_used rd 1
|
||||
dlls_list_ptr rd 1
|
||||
pdt_0_phys rd 1
|
||||
pdt_1_phys rd 1
|
||||
io_map_0 rd 1
|
||||
io_map_1 rd 1
|
||||
|
||||
ht_lock rd 1
|
||||
ht_free rd 1 ;htab[0] stdin
|
||||
ht_next rd 1 ;htab[1] stdout
|
||||
htab rd 1024-PROC.htab/4 ;htab[2] stderr
|
||||
pdt_0 rd 1024
|
||||
ends
|
||||
|
||||
struct DBG_REGS
|
||||
dr0 dd ?
|
||||
dr1 dd ?
|
||||
dr2 dd ?
|
||||
dr3 dd ?
|
||||
dr7 dd ?
|
||||
ends
|
||||
|
||||
struct POINT
|
||||
x dd ?
|
||||
y dd ?
|
||||
ends
|
||||
|
||||
struct RECT
|
||||
left dd ?
|
||||
top dd ?
|
||||
right dd ?
|
||||
bottom dd ?
|
||||
ends
|
||||
|
||||
struct BOX
|
||||
left dd ?
|
||||
top dd ?
|
||||
width dd ?
|
||||
height dd ?
|
||||
ends
|
||||
|
||||
; Fields, marked as R now not used, but will be used soon,
|
||||
; when legacy TASKDATA structure will be deleted
|
||||
struct APPDATA
|
||||
app_name rb 11
|
||||
rb 5
|
||||
|
||||
list LHEAD ;+16
|
||||
process dd ? ;+24
|
||||
fpu_state dd ? ;+28
|
||||
exc_handler dd ? ;+32
|
||||
except_mask dd ? ;+36
|
||||
pl0_stack dd ? ;+40
|
||||
cursor dd ? ;+44
|
||||
fd_ev dd ? ;+48
|
||||
bk_ev dd ? ;+52
|
||||
fd_obj dd ? ;+56
|
||||
bk_obj dd ? ;+60
|
||||
saved_esp dd ? ;+64
|
||||
io_map rd 2 ;+68
|
||||
dbg_state dd ? ;+76
|
||||
cur_dir dd ? ;+80
|
||||
wait_timeout dd ? ;+84
|
||||
saved_esp0 dd ? ;+88
|
||||
wait_begin dd ? ;+92 +++
|
||||
wait_test dd ? ;+96 +++
|
||||
wait_param dd ? ;+100 +++
|
||||
tls_base dd ? ;+104
|
||||
event_mask dd ? ;+108 ; R stores event types allowed for task
|
||||
tid dd ? ;+112 ; R thread id
|
||||
draw_bgr_x dd ? ;+116
|
||||
draw_bgr_y dd ? ;+120
|
||||
state db ? ;+124 ; R thread state
|
||||
db ? ;+125
|
||||
dw ? ;+126
|
||||
wnd_shape dd ? ;+128
|
||||
wnd_shape_scale dd ? ;+132
|
||||
mem_start dd ? ;+136 ; R
|
||||
counter_sum dd ? ;+140 ; R
|
||||
saved_box BOX ;+144
|
||||
ipc_start dd ? ;+160
|
||||
ipc_size dd ? ;+164
|
||||
occurred_events dd ? ;+168 ; mask which accumulates occurred events
|
||||
debugger_slot dd ? ;+172
|
||||
terminate_protection dd ? ;+176
|
||||
keyboard_mode db ? ;+180
|
||||
captionEncoding db ?
|
||||
rb 2
|
||||
exec_params dd ? ;+184
|
||||
dbg_event_mem dd ? ;+188
|
||||
dbg_regs DBG_REGS ;+192
|
||||
wnd_caption dd ? ;+212
|
||||
wnd_clientbox BOX ;+216
|
||||
priority dd ? ;+232
|
||||
in_schedule LHEAD ;+236
|
||||
counter_add dd ? ;+244 ; R
|
||||
cpu_usage dd ? ;+248 ; R
|
||||
dd ? ;+252
|
||||
ends
|
||||
|
||||
assert sizeof.APPDATA = 256
|
||||
|
||||
APP_OBJ_OFFSET = 48
|
||||
APP_EV_OFFSET = 40
|
||||
|
||||
; Note: in future TASKDATA will be merged into APPDATA
|
||||
struct TASKDATA
|
||||
event_mask dd ? ;+0 mask which stores event types allowed for task
|
||||
pid dd ? ;+4
|
||||
dw ? ;+8
|
||||
state db ? ;+10
|
||||
db ? ;+11
|
||||
dw ? ;+12
|
||||
wnd_number db ? ;+14
|
||||
db ? ;+15
|
||||
mem_start dd ? ;+16
|
||||
counter_sum dd ? ;+20
|
||||
counter_add dd ? ;+24
|
||||
cpu_usage dd ? ;+28
|
||||
ends
|
||||
|
||||
; Thread states:
|
||||
TSTATE_RUNNING = 0
|
||||
TSTATE_RUN_SUSPENDED = 1
|
||||
TSTATE_WAIT_SUSPENDED = 2
|
||||
TSTATE_ZOMBIE = 3
|
||||
TSTATE_TERMINATING = 4
|
||||
TSTATE_WAITING = 5
|
||||
TSTATE_FREE = 9
|
||||
|
||||
; Window constants:
|
||||
WSTATE_NORMAL = 00000000b
|
||||
WSTATE_MAXIMIZED = 00000001b
|
||||
WSTATE_MINIMIZED = 00000010b
|
||||
WSTATE_ROLLEDUP = 00000100b
|
||||
|
||||
WSTATE_REDRAW = 00000001b
|
||||
WSTATE_WNDDRAWN = 00000010b
|
||||
|
||||
WSTYLE_HASCAPTION = 00010000b
|
||||
WSTYLE_CLIENTRELATIVE = 00100000b
|
||||
|
||||
ZPOS_DESKTOP = -2
|
||||
ZPOS_ALWAYS_BACK = -1
|
||||
ZPOS_NORMAL = 0
|
||||
ZPOS_ALWAYS_TOP = 1 ;ZPOS_ALWAYS_TOP is always last and has max number!
|
||||
|
||||
; Window structure:
|
||||
struct WDATA
|
||||
box BOX
|
||||
cl_workarea dd ?
|
||||
cl_titlebar dd ?
|
||||
cl_frames dd ?
|
||||
z_modif db ?
|
||||
fl_wstate db ?
|
||||
fl_wdrawn db ?
|
||||
fl_redraw db ?
|
||||
ends
|
||||
|
||||
label WDATA.fl_wstyle byte at WDATA.cl_workarea + 3
|
||||
|
||||
assert sizeof.WDATA = 32
|
||||
|
||||
struct SYS_VARS
|
||||
bpp dd ?
|
||||
scanline dd ?
|
||||
vesa_mode dd ?
|
||||
x_res dd ?
|
||||
y_res dd ?
|
||||
ends
|
||||
|
||||
struct APPOBJ ; common object header
|
||||
magic dd ? ;
|
||||
destroy dd ? ; internal destructor
|
||||
fd dd ? ; next object in list
|
||||
bk dd ? ; prev object in list
|
||||
pid dd ? ; owner id
|
||||
ends
|
||||
|
||||
struct CURSOR APPOBJ
|
||||
base dd ? ;allocated memory
|
||||
hot_x dd ? ;hotspot coords
|
||||
hot_y dd ?
|
||||
|
||||
list_next dd ? ;next cursor in cursor list
|
||||
list_prev dd ? ;prev cursor in cursor list
|
||||
dev_obj dd ? ;device depended data
|
||||
ends
|
||||
|
||||
|
||||
struct EVENT APPOBJ
|
||||
id dd ? ;event uid
|
||||
state dd ? ;internal flags
|
||||
code dd ?
|
||||
rd 5
|
||||
ends
|
||||
|
||||
|
||||
struct SMEM
|
||||
bk dd ?
|
||||
fd dd ? ;+4
|
||||
base dd ? ;+8
|
||||
size dd ? ;+12
|
||||
access dd ? ;+16
|
||||
refcount dd ? ;+20
|
||||
name rb 32 ;+24
|
||||
ends
|
||||
|
||||
struct SMAP APPOBJ
|
||||
base dd ? ;mapped base
|
||||
parent dd ? ;SMEM
|
||||
ends
|
||||
|
||||
struct DLLDESCR
|
||||
bk dd ?
|
||||
fd dd ? ;+4
|
||||
data dd ? ;+8
|
||||
size dd ? ;+12
|
||||
timestamp dq ?
|
||||
refcount dd ?
|
||||
defaultbase dd ?
|
||||
coff_hdr dd ?
|
||||
symbols_ptr dd ?
|
||||
symbols_num dd ?
|
||||
symbols_lim dd ?
|
||||
exports dd ? ;export table
|
||||
name rb 260
|
||||
ends
|
||||
|
||||
struct HDLL
|
||||
fd dd ? ;next object in list
|
||||
bk dd ? ;prev object in list
|
||||
pid dd ? ;owner id
|
||||
|
||||
base dd ? ;mapped base
|
||||
size dd ? ;mapped size
|
||||
refcount dd ? ;reference counter for this process and this lib
|
||||
parent dd ? ;DLLDESCR
|
||||
ends
|
||||
|
||||
struct DQ
|
||||
lo dd ?
|
||||
hi dd ?
|
||||
ends
|
||||
|
||||
struct e820entry
|
||||
addr DQ ?
|
||||
size DQ ?
|
||||
type dd ?
|
||||
ends
|
||||
|
||||
RD_LOAD_FROM_FLOPPY = 1
|
||||
RD_LOAD_FROM_HD = 2
|
||||
RD_LOAD_FROM_MEMORY = 3
|
||||
RD_LOAD_FROM_FORMAT = 4
|
||||
RD_LOAD_FROM_NONE = 5
|
||||
|
||||
struct boot_data
|
||||
bpp db ? ; bits per pixel
|
||||
pitch dw ? ; scanline length
|
||||
db ?
|
||||
dd ?
|
||||
vesa_mode dw ?
|
||||
x_res dw ?
|
||||
y_res dw ?
|
||||
dw ?
|
||||
dd ?
|
||||
bank_switch dd ? ; Vesa 1.2 pm bank switch
|
||||
lfb dd ? ; Vesa 2.0 LFB address
|
||||
mtrr db ? ; 0 or 1: enable MTRR graphics acceleration
|
||||
launcher_start db ? ; 0 or 1: start the first app (right now it's
|
||||
; LAUNCHER) after kernel is loaded
|
||||
debug_print db ? ; if nonzero, duplicates debug output to the screen
|
||||
dma db ? ; DMA write: 1=yes, 2=no
|
||||
pci_data rb 8
|
||||
rb 8
|
||||
shutdown_type db ? ; see sysfn 18.9
|
||||
rb 15
|
||||
apm_entry dd ? ; entry point of APM BIOS
|
||||
apm_version dw ? ; BCD
|
||||
apm_flags dw ?
|
||||
rb 8
|
||||
apm_code_32 dw ?
|
||||
apm_code_16 dw ?
|
||||
apm_data_16 dw ?
|
||||
rd_load_from db ? ; Device to load ramdisk from, RD_LOAD_FROM_*
|
||||
db ?
|
||||
kernel_restart dw ?
|
||||
sys_disk dw ? ; Device to mount on /sys/, see loader_doc.txt for details
|
||||
acpi_rsdp dd ?
|
||||
syspath rb 0x17
|
||||
devicesdat_data dd ?
|
||||
devicesdat_size dd ?
|
||||
bios_hd_cnt db ? ; number of BIOS hard disks
|
||||
bios_hd rb 0x80 ; BIOS hard disks
|
||||
memmap_block_cnt dd ? ; available physical memory map: number of blocks
|
||||
memmap_blocks e820entry
|
||||
rb sizeof.e820entry * (MAX_MEMMAP_BLOCKS - 1)
|
||||
ends
|
||||
|
||||
virtual at BOOT_VARS
|
||||
BOOT_LO boot_data
|
||||
end virtual
|
||||
virtual at OS_BASE + BOOT_VARS
|
||||
BOOT boot_data
|
||||
end virtual
|
||||
|
||||
MAX_SCREEN_WIDTH = 3840
|
||||
MAX_SCREEN_HEIGHT = 2160
|
||||
|
||||
struct display_t
|
||||
x dd ?
|
||||
y dd ?
|
||||
width dd ?
|
||||
height dd ?
|
||||
bits_per_pixel dd ?
|
||||
vrefresh dd ?
|
||||
current_lfb dd ?
|
||||
lfb_pitch dd ?
|
||||
|
||||
win_map_lock RWSEM
|
||||
win_map dd ?
|
||||
win_map_pitch dd ?
|
||||
win_map_size dd ?
|
||||
|
||||
modes dd ?
|
||||
ddev dd ?
|
||||
connector dd ?
|
||||
crtc dd ?
|
||||
|
||||
cr_list.next dd ?
|
||||
cr_list.prev dd ?
|
||||
|
||||
cursor dd ?
|
||||
|
||||
init_cursor dd ?
|
||||
select_cursor dd ?
|
||||
show_cursor dd ?
|
||||
move_cursor dd ?
|
||||
restore_cursor dd ?
|
||||
disable_mouse dd ?
|
||||
mask_seqno dd ?
|
||||
check_mouse dd ?
|
||||
check_m_pixel dd ?
|
||||
|
||||
bytes_per_pixel dd ?
|
||||
ends
|
||||
|
||||
struct DISPMODE
|
||||
width dw ?
|
||||
height dw ?
|
||||
bpp dw ?
|
||||
freq dw ?
|
||||
ends
|
||||
|
||||
|
||||
struct PCIDEV
|
||||
bk dd ?
|
||||
fd dd ?
|
||||
vendor_device_id dd ?
|
||||
class dd ?
|
||||
devfn db ?
|
||||
bus db ?
|
||||
rb 2
|
||||
owner dd ? ; pointer to SRV or 0
|
||||
ends
|
||||
|
||||
struct IDE_DATA
|
||||
ProgrammingInterface dd ?
|
||||
Interrupt dw ?
|
||||
RegsBaseAddres dw ?
|
||||
BAR0_val dw ?
|
||||
BAR1_val dw ?
|
||||
BAR2_val dw ?
|
||||
BAR3_val dw ?
|
||||
dma_hdd_channel_1 db ?
|
||||
dma_hdd_channel_2 db ?
|
||||
pcidev dd ? ; pointer to corresponding PCIDEV structure
|
||||
ends
|
||||
|
||||
struct IDE_CACHE
|
||||
pointer dd ?
|
||||
size dd ? ; not use
|
||||
data_pointer dd ?
|
||||
system_data_size dd ? ; not use
|
||||
appl_data_size dd ? ; not use
|
||||
system_data dd ?
|
||||
appl_data dd ?
|
||||
system_sad_size dd ?
|
||||
appl_sad_size dd ?
|
||||
search_start dd ?
|
||||
appl_search_start dd ?
|
||||
ends
|
||||
|
||||
struct IDE_DEVICE
|
||||
UDMA_possible_modes db ?
|
||||
UDMA_set_mode db ?
|
||||
ends
|
||||
|
||||
; The following macro assume that we are on uniprocessor machine.
|
||||
; Serious work is needed for multiprocessor machines.
|
||||
macro spin_lock_irqsave spinlock
|
||||
{
|
||||
pushf
|
||||
cli
|
||||
}
|
||||
macro spin_unlock_irqrestore spinlock
|
||||
{
|
||||
popf
|
||||
}
|
||||
macro spin_lock_irq spinlock
|
||||
{
|
||||
cli
|
||||
}
|
||||
macro spin_unlock_irq spinlock
|
||||
{
|
||||
sti
|
||||
}
|
||||
|
||||
struct MEM_STATE
|
||||
mutex MUTEX
|
||||
smallmap dd ?
|
||||
treemap dd ?
|
||||
topsize dd ?
|
||||
top dd ?
|
||||
smallbins rd 4*32
|
||||
treebins rd 32
|
||||
ends
|
||||
|
||||
struct PG_DATA
|
||||
mem_amount dd ?
|
||||
vesa_mem dd ?
|
||||
pages_count dd ?
|
||||
pages_free dd ?
|
||||
pages_faults dd ?
|
||||
pagemap_size dd ?
|
||||
kernel_pages dd ?
|
||||
kernel_tables dd ?
|
||||
sys_page_dir dd ?
|
||||
mutex MUTEX
|
||||
ends
|
||||
|
||||
struct SRV
|
||||
srv_name rb 16 ;ASCIIZ string
|
||||
magic dd ? ;+0x10 ;'SRV '
|
||||
size dd ? ;+0x14 ;size of structure SRV
|
||||
fd dd ? ;+0x18 ;next SRV descriptor
|
||||
bk dd ? ;+0x1C ;prev SRV descriptor
|
||||
base dd ? ;+0x20 ;service base address
|
||||
entry dd ? ;+0x24 ;service START function
|
||||
srv_proc dd ? ;+0x28 ;user mode service handler
|
||||
srv_proc_ex dd ? ;+0x2C ;kernel mode service handler
|
||||
ends
|
||||
|
||||
struct USBSRV
|
||||
srv SRV
|
||||
usb_func dd ?
|
||||
ends
|
||||
|
||||
struct USBFUNC
|
||||
strucsize dd ?
|
||||
add_device dd ?
|
||||
device_disconnect dd ?
|
||||
ends
|
||||
|
||||
DRV_ENTRY = 1
|
||||
DRV_EXIT = -1
|
||||
|
||||
struct COFF_HEADER
|
||||
machine dw ?
|
||||
nSections dw ?
|
||||
DataTime dd ?
|
||||
pSymTable dd ?
|
||||
nSymbols dd ?
|
||||
optHeader dw ?
|
||||
flags dw ?
|
||||
ends
|
||||
|
||||
struct COFF_SECTION
|
||||
Name rb 8
|
||||
VirtualSize dd ?
|
||||
VirtualAddress dd ?
|
||||
SizeOfRawData dd ?
|
||||
PtrRawData dd ?
|
||||
PtrReloc dd ?
|
||||
PtrLinenumbers dd ?
|
||||
NumReloc dw ?
|
||||
NumLinenum dw ?
|
||||
Characteristics dd ?
|
||||
ends
|
||||
|
||||
struct COFF_RELOC
|
||||
VirtualAddress dd ?
|
||||
SymIndex dd ?
|
||||
Type dw ?
|
||||
ends
|
||||
|
||||
struct COFF_SYM
|
||||
Name rb 8
|
||||
Value dd ?
|
||||
SectionNumber dw ?
|
||||
Type dw ?
|
||||
StorageClass db ?
|
||||
NumAuxSymbols db ?
|
||||
ends
|
||||
|
||||
struct STRIPPED_PE_HEADER
|
||||
Signature dw ?
|
||||
Characteristics dw ?
|
||||
AddressOfEntryPoint dd ?
|
||||
ImageBase dd ?
|
||||
SectionAlignmentLog db ?
|
||||
FileAlignmentLog db ?
|
||||
MajorOSVersion db ?
|
||||
MinorOSVersion db ?
|
||||
SizeOfImage dd ?
|
||||
SizeOfStackReserve dd ?
|
||||
SizeOfHeapReserve dd ?
|
||||
SizeOfHeaders dd ?
|
||||
Subsystem db ?
|
||||
NumberOfRvaAndSizes db ?
|
||||
NumberOfSections dw ?
|
||||
ends
|
||||
STRIPPED_PE_SIGNATURE = 0x4503 ; 'PE' xor 'S'
|
||||
SPE_DIRECTORY_IMPORT = 0
|
||||
SPE_DIRECTORY_EXPORT = 1
|
||||
SPE_DIRECTORY_BASERELOC = 2
|
||||
|
||||
struct IOCTL
|
||||
handle dd ?
|
||||
io_code dd ?
|
||||
input dd ?
|
||||
inp_size dd ?
|
||||
output dd ?
|
||||
out_size dd ?
|
||||
ends
|
||||
|
||||
struct IRQH
|
||||
list LHEAD
|
||||
handler dd ? ;handler roututine
|
||||
data dd ? ;user-specific data
|
||||
num_ints dd ? ;how many times handled
|
||||
ends
|
||||
|
||||
3
kernel/branches/kolibri-lldw/core/Tupfile.lua
Normal file
3
kernel/branches/kolibri-lldw/core/Tupfile.lua
Normal file
@@ -0,0 +1,3 @@
|
||||
if tup.getconfig("NO_FASM") ~= "" then return end
|
||||
tup.rule("mtrrtest.asm", "fasm %f %o", "mtrrtest.exe")
|
||||
tup.rule("test_malloc.asm", "fasm %f %o", "test_malloc")
|
||||
567
kernel/branches/kolibri-lldw/core/apic.inc
Normal file
567
kernel/branches/kolibri-lldw/core/apic.inc
Normal file
@@ -0,0 +1,567 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
MAX_IOAPICS = 2
|
||||
|
||||
uglobal
|
||||
IRQ_COUNT rd MAX_IOAPICS
|
||||
irq_mode rd 1 ; PIC/(IO)APIC
|
||||
IOAPIC_base rd MAX_IOAPICS
|
||||
ioapic_gsi_base rd MAX_IOAPICS ; zero-based, i.e. not vector
|
||||
ioapic_cnt dd ? ; from MADT aka APIC table
|
||||
ioapic_cur dd ?
|
||||
LAPIC_BASE rd 1
|
||||
endg
|
||||
|
||||
APIC_ID = 0x20
|
||||
APIC_TPR = 0x80
|
||||
APIC_EOI = 0xb0
|
||||
APIC_LDR = 0xd0
|
||||
APIC_DFR = 0xe0
|
||||
APIC_SVR = 0xf0
|
||||
APIC_ISR = 0x100
|
||||
APIC_ESR = 0x280
|
||||
APIC_ICRL = 0x300
|
||||
APIC_ICRH = 0x310
|
||||
APIC_LVT_LINT0 = 0x350
|
||||
APIC_LVT_LINT1 = 0x360
|
||||
APIC_LVT_err = 0x370
|
||||
|
||||
; APIC timer
|
||||
APIC_LVT_timer = 0x320
|
||||
APIC_timer_div = 0x3e0
|
||||
APIC_timer_init = 0x380
|
||||
APIC_timer_cur = 0x390
|
||||
; IOAPIC
|
||||
IOAPIC_ID = 0x0
|
||||
IOAPIC_VER = 0x1
|
||||
IOAPIC_ARB = 0x2
|
||||
IOAPIC_REDTBL = 0x10
|
||||
|
||||
align 4
|
||||
APIC_init:
|
||||
push ebx
|
||||
mov [irq_mode], IRQ_PIC
|
||||
|
||||
cmp [acpi_ioapic_base], 0
|
||||
jz .no_apic
|
||||
|
||||
cmp [acpi_lapic_base], 0
|
||||
jz .no_apic
|
||||
|
||||
; non-UEFI loaders don't load DEVICES.DAT and don't initialize [acpi_dev_size]
|
||||
if defined UEFI
|
||||
cmp [acpi_dev_size], 0
|
||||
jz @f
|
||||
stdcall map_io_mem, [acpi_dev_data], [acpi_dev_size], PG_SWR
|
||||
mov [acpi_dev_data], eax
|
||||
jmp .loaded
|
||||
@@:
|
||||
end if
|
||||
|
||||
stdcall load_file, dev_data_path
|
||||
test eax, eax
|
||||
jz .no_apic
|
||||
|
||||
mov [acpi_dev_data], eax
|
||||
mov [acpi_dev_size], ebx
|
||||
.loaded:
|
||||
|
||||
; IOAPIC init
|
||||
xor ebx, ebx
|
||||
@@:
|
||||
stdcall map_io_mem, [acpi_ioapic_base+ebx*4], 0x20, PG_GLOBAL+PG_NOCACHE+PG_SWR
|
||||
mov [IOAPIC_base+ebx*4], eax
|
||||
inc ebx
|
||||
cmp ebx, [ioapic_cnt]
|
||||
jnz @b
|
||||
|
||||
call IRQ_mask_all
|
||||
mov [ioapic_cur], 0
|
||||
.next_ioapic:
|
||||
mov edx, [ioapic_cur]
|
||||
mov eax, IOAPIC_VER
|
||||
call IOAPIC_read
|
||||
shr eax, 16
|
||||
inc al
|
||||
movzx eax, al
|
||||
mov ecx, [ioapic_gsi_base+edx*4]
|
||||
cmp ecx, IRQ_RESERVED
|
||||
jae .lapic_init
|
||||
add ecx, eax
|
||||
sub ecx, IRQ_RESERVED
|
||||
jbe @f
|
||||
sub eax, ecx
|
||||
@@:
|
||||
mov [IRQ_COUNT+edx*4], eax
|
||||
|
||||
; Reroute IOAPIC & mask all interrupts
|
||||
xor ecx, ecx
|
||||
mov eax, IOAPIC_REDTBL
|
||||
.next_irq:
|
||||
mov ebx, eax
|
||||
call IOAPIC_read
|
||||
mov ah, 0x08; Delivery Mode: Fixed, Destination Mode: Logical
|
||||
mov al, cl
|
||||
add al, 0x20; vector
|
||||
add eax, [ioapic_gsi_base+edx*4]
|
||||
or eax, 0x1a000; Mask Interrupt, level-triggered active-low
|
||||
cmp [ioapic_cur], 0
|
||||
jnz @f
|
||||
cmp ecx, 16
|
||||
jae @f
|
||||
and eax, NOT 0xa000 ; edge-triggered active-high for IRQ0-15
|
||||
@@:
|
||||
xchg eax, ebx
|
||||
call IOAPIC_write
|
||||
inc eax
|
||||
mov ebx, eax
|
||||
call IOAPIC_read
|
||||
or eax, 0xff000000; Destination Field
|
||||
xchg eax, ebx
|
||||
call IOAPIC_write
|
||||
inc eax
|
||||
inc ecx
|
||||
cmp ecx, [IRQ_COUNT+edx*4]
|
||||
jb .next_irq
|
||||
|
||||
inc [ioapic_cur]
|
||||
inc edx
|
||||
cmp edx, [ioapic_cnt]
|
||||
jnz .next_ioapic
|
||||
|
||||
.lapic_init:
|
||||
call LAPIC_init
|
||||
|
||||
mov [irq_mode], IRQ_APIC
|
||||
|
||||
mov al, 0x70
|
||||
out 0x22, al
|
||||
mov al, 1
|
||||
out 0x23, al
|
||||
|
||||
call pci_irq_fixup
|
||||
.no_apic:
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
;===========================================================
|
||||
align 4
|
||||
LAPIC_init:
|
||||
|
||||
mov eax, [LAPIC_BASE]
|
||||
test eax, eax
|
||||
jnz @f
|
||||
stdcall map_io_mem, [acpi_lapic_base], 0x1000, PG_GLOBAL+PG_NOCACHE+PG_SWR
|
||||
mov [LAPIC_BASE], eax
|
||||
@@:
|
||||
mov esi, eax
|
||||
|
||||
; Program Destination Format Register for Flat mode.
|
||||
mov eax, [esi + APIC_DFR]
|
||||
or eax, 0xf0000000
|
||||
mov [esi + APIC_DFR], eax
|
||||
|
||||
; Program Logical Destination Register.
|
||||
mov eax, [esi + APIC_LDR]
|
||||
;and eax, 0xff000000
|
||||
and eax, 0x00ffffff
|
||||
or eax, 0x01000000;!!!!!!!!!!!!
|
||||
mov [esi + APIC_LDR], eax
|
||||
|
||||
; Task Priority Register initialization.
|
||||
mov eax, [esi + APIC_TPR]
|
||||
and eax, 0xffffff00
|
||||
mov [esi + APIC_TPR], eax
|
||||
|
||||
; Flush the queue
|
||||
mov edx, 0
|
||||
.nxt2:
|
||||
mov ecx, 32
|
||||
mov eax, [esi + APIC_ISR + edx]
|
||||
.nxt:
|
||||
shr eax, 1
|
||||
jnc @f
|
||||
mov dword [esi + APIC_EOI], 0; EOI
|
||||
@@:
|
||||
loop .nxt
|
||||
|
||||
add edx, 0x10
|
||||
cmp edx, 0x170
|
||||
jbe .nxt2
|
||||
|
||||
; Spurious-Interrupt Vector Register initialization.
|
||||
mov eax, [esi + APIC_SVR]
|
||||
or eax, 0x1ff
|
||||
and eax, 0xfffffdff
|
||||
mov [esi + APIC_SVR], eax
|
||||
|
||||
; Initialize LVT LINT0 register. (INTR)
|
||||
mov eax, 0x00700
|
||||
; mov eax, 0x10700
|
||||
mov [esi + APIC_LVT_LINT0], eax
|
||||
|
||||
; Initialize LVT LINT1 register. (NMI)
|
||||
mov eax, 0x00400
|
||||
mov [esi + APIC_LVT_LINT1], eax
|
||||
|
||||
; Initialize LVT Error register.
|
||||
mov eax, [esi + APIC_LVT_err]
|
||||
or eax, 0x10000; bit 16
|
||||
mov [esi + APIC_LVT_err], eax
|
||||
|
||||
; LAPIC timer
|
||||
; pre init
|
||||
mov dword[esi + APIC_timer_div], 1011b; 1
|
||||
mov dword[esi + APIC_timer_init], 0xffffffff; max val
|
||||
push esi
|
||||
mov esi, 640 ; wait 0.64 sec
|
||||
call delay_ms
|
||||
pop esi
|
||||
mov eax, [esi + APIC_timer_cur]; read current tick couner
|
||||
xor eax, 0xffffffff ; eax = 0xffffffff - eax
|
||||
shr eax, 6 ; eax /= 64; APIC ticks per 0.01 sec
|
||||
|
||||
; Start (every 0.01 sec)
|
||||
mov dword[esi + APIC_LVT_timer], 0x30020; periodic int 0x20
|
||||
mov dword[esi + APIC_timer_init], eax
|
||||
|
||||
.done:
|
||||
ret
|
||||
|
||||
;===========================================================
|
||||
; IOAPIC implementation
|
||||
align 4
|
||||
IOAPIC_read:
|
||||
; in : EAX - IOAPIC register
|
||||
; out: EAX - readed value
|
||||
push esi
|
||||
mov esi, [ioapic_cur]
|
||||
mov esi, [IOAPIC_base+esi*4]
|
||||
mov [esi], eax
|
||||
mov eax, [esi + 0x10]
|
||||
pop esi
|
||||
ret
|
||||
|
||||
align 4
|
||||
IOAPIC_write:
|
||||
; in : EAX - IOAPIC register
|
||||
; EBX - value
|
||||
; out: none
|
||||
push esi
|
||||
mov esi, [ioapic_cur]
|
||||
mov esi, [IOAPIC_base+esi*4]
|
||||
mov [esi], eax
|
||||
mov [esi + 0x10], ebx
|
||||
pop esi
|
||||
ret
|
||||
;===========================================================
|
||||
; Remap all IRQ to 0x20+ Vectors
|
||||
; IRQ0 to vector 0x20, IRQ1 to vector 0x21....
|
||||
align 4
|
||||
PIC_init:
|
||||
mov [IRQ_COUNT], 16
|
||||
cli
|
||||
mov al, 0x11 ; icw4, edge triggered
|
||||
out 0x20, al
|
||||
out 0xA0, al
|
||||
|
||||
mov al, 0x20 ; generate 0x20 +
|
||||
out 0x21, al
|
||||
mov al, 0x28 ; generate 0x28 +
|
||||
out 0xA1, al
|
||||
|
||||
mov al, 0x04 ; slave at irq2
|
||||
out 0x21, al
|
||||
mov al, 0x02 ; at irq9
|
||||
out 0xA1, al
|
||||
|
||||
mov al, 0x01 ; 8086 mode
|
||||
out 0x21, al
|
||||
out 0xA1, al
|
||||
|
||||
call IRQ_mask_all
|
||||
ret
|
||||
|
||||
; -----------------------------------------
|
||||
; TIMER SET TO 1/100 S
|
||||
align 4
|
||||
PIT_init:
|
||||
mov al, 0x34 ; set to 100Hz
|
||||
out 0x43, al
|
||||
mov al, 0x9b ; lsb 1193180 / 1193
|
||||
out 0x40, al
|
||||
mov al, 0x2e ; msb
|
||||
out 0x40, al
|
||||
ret
|
||||
|
||||
; -----------------------------------------
|
||||
align 4
|
||||
unmask_timer:
|
||||
cmp [irq_mode], IRQ_APIC
|
||||
je @f
|
||||
|
||||
stdcall enable_irq, 0
|
||||
ret
|
||||
@@:
|
||||
; use PIT
|
||||
; in some systems PIT no connected to IOAPIC
|
||||
; mov eax, 0x14
|
||||
; call IOAPIC_read
|
||||
; mov ah, 0x09 ; Delivery Mode: Lowest Priority, Destination Mode: Logical
|
||||
; mov al, 0x20
|
||||
; or eax, 0x10000 ; Mask Interrupt
|
||||
; mov ebx, eax
|
||||
; mov eax, 0x14
|
||||
; call IOAPIC_write
|
||||
; stdcall enable_irq, 2
|
||||
; ret
|
||||
|
||||
; use LAPIC timer
|
||||
mov esi, [LAPIC_BASE]
|
||||
mov eax, [esi + APIC_LVT_timer]
|
||||
and eax, 0xfffeffff
|
||||
mov [esi + APIC_LVT_timer], eax
|
||||
ret
|
||||
|
||||
; -----------------------------------------
|
||||
; Disable all IRQ
|
||||
align 4
|
||||
IRQ_mask_all:
|
||||
cmp [irq_mode], IRQ_APIC
|
||||
je .APIC
|
||||
|
||||
mov al, 0xFF
|
||||
out 0x21, al
|
||||
out 0xA1, al
|
||||
mov ecx, 0x1000
|
||||
ret
|
||||
.APIC:
|
||||
cmp [IOAPIC_base], 0
|
||||
jz .done
|
||||
mov [ioapic_cur], 0
|
||||
.next_ioapic:
|
||||
mov edx, [ioapic_cur]
|
||||
mov ecx, [IRQ_COUNT+edx*4]
|
||||
mov eax, 0x10
|
||||
@@:
|
||||
mov ebx, eax
|
||||
call IOAPIC_read
|
||||
or eax, 0x10000; bit 16
|
||||
xchg eax, ebx
|
||||
call IOAPIC_write
|
||||
inc eax
|
||||
inc eax
|
||||
loop @b
|
||||
|
||||
inc [ioapic_cur]
|
||||
inc edx
|
||||
cmp edx, [ioapic_cnt]
|
||||
jnz .next_ioapic
|
||||
.done:
|
||||
ret
|
||||
|
||||
; -----------------------------------------
|
||||
; End Of Interrupt
|
||||
; cl - IRQ number
|
||||
align 4
|
||||
irq_eoi: ; __fastcall
|
||||
cmp [irq_mode], IRQ_APIC
|
||||
je .APIC
|
||||
|
||||
cmp cl, 8
|
||||
mov al, 0x20
|
||||
jb @f
|
||||
out 0xa0, al
|
||||
@@:
|
||||
out 0x20, al
|
||||
ret
|
||||
|
||||
.APIC:
|
||||
mov eax, [LAPIC_BASE]
|
||||
mov dword [eax + APIC_EOI], 0; EOI
|
||||
ret
|
||||
|
||||
; -----------------------------------------
|
||||
; from dll.inc
|
||||
align 4
|
||||
proc enable_irq stdcall, irq_line:dword
|
||||
mov ebx, [irq_line]
|
||||
cmp [irq_mode], IRQ_APIC
|
||||
je .APIC
|
||||
|
||||
mov edx, 0x21
|
||||
cmp ebx, 8
|
||||
jb @F
|
||||
|
||||
mov edx, 0xA1
|
||||
sub ebx, 8
|
||||
@@:
|
||||
in al, dx
|
||||
btr eax, ebx
|
||||
out dx, al
|
||||
ret
|
||||
.APIC:
|
||||
push [ioapic_cur]
|
||||
xor eax, eax
|
||||
.next_ioapic:
|
||||
mov ecx, [ioapic_gsi_base+eax*4]
|
||||
add ecx, [IRQ_COUNT+eax*4]
|
||||
cmp ebx, ecx
|
||||
jb .found
|
||||
inc eax
|
||||
cmp eax, [ioapic_cnt]
|
||||
jnz .next_ioapic
|
||||
jmp .done
|
||||
.found:
|
||||
mov [ioapic_cur], eax
|
||||
sub ebx, [ioapic_gsi_base+eax*4]
|
||||
shl ebx, 1
|
||||
add ebx, 0x10
|
||||
mov eax, ebx
|
||||
call IOAPIC_read
|
||||
and eax, 0xfffeffff; bit 16
|
||||
xchg eax, ebx
|
||||
call IOAPIC_write
|
||||
.done:
|
||||
pop [ioapic_cur]
|
||||
ret
|
||||
endp
|
||||
|
||||
proc disable_irq stdcall, irq_line:dword
|
||||
mov ebx, [irq_line]
|
||||
cmp [irq_mode], IRQ_APIC
|
||||
je .APIC
|
||||
|
||||
mov edx, 0x21
|
||||
cmp ebx, 8
|
||||
jb @F
|
||||
|
||||
mov edx, 0xA1
|
||||
sub ebx, 8
|
||||
@@:
|
||||
in al, dx
|
||||
bts eax, ebx
|
||||
out dx, al
|
||||
ret
|
||||
.APIC:
|
||||
push [ioapic_cur]
|
||||
xor eax, eax
|
||||
.next_ioapic:
|
||||
mov ecx, [ioapic_gsi_base+eax*4]
|
||||
add ecx, [IRQ_COUNT+eax*4]
|
||||
cmp ebx, ecx
|
||||
jae .found
|
||||
inc eax
|
||||
cmp eax, [ioapic_cnt]
|
||||
jnz .next_ioapic
|
||||
jmp .done
|
||||
.found:
|
||||
mov [ioapic_cur], eax
|
||||
sub ebx, [ioapic_gsi_base+eax*4]
|
||||
shl ebx, 1
|
||||
add ebx, 0x10
|
||||
mov eax, ebx
|
||||
call IOAPIC_read
|
||||
or eax, 0x10000; bit 16
|
||||
xchg eax, ebx
|
||||
call IOAPIC_write
|
||||
.done:
|
||||
pop [ioapic_cur]
|
||||
ret
|
||||
endp
|
||||
|
||||
align 4
|
||||
pci_irq_fixup:
|
||||
|
||||
push ebp
|
||||
|
||||
mov esi, [acpi_dev_data]
|
||||
mov ebx, [acpi_dev_size]
|
||||
|
||||
lea edi, [esi+ebx]
|
||||
|
||||
.iterate:
|
||||
|
||||
cmp esi, edi
|
||||
jae .done
|
||||
|
||||
mov eax, [esi]
|
||||
|
||||
cmp eax, -1
|
||||
je .done
|
||||
|
||||
movzx ebx, al
|
||||
movzx ebp, ah
|
||||
|
||||
stdcall pci_read32, ebp, ebx, 0
|
||||
|
||||
cmp eax, [esi+4]
|
||||
jne .skip
|
||||
|
||||
mov eax, [esi+8]
|
||||
stdcall pci_write8, ebp, ebx, 0x3C, eax
|
||||
.skip:
|
||||
add esi, 16
|
||||
jmp .iterate
|
||||
|
||||
.done:
|
||||
.fail:
|
||||
pop ebp
|
||||
ret
|
||||
|
||||
align 4
|
||||
get_clock_ns:
|
||||
|
||||
mov eax, [hpet_base]
|
||||
test eax, eax
|
||||
jz .old_tics
|
||||
|
||||
push ebx
|
||||
push esi
|
||||
pushfd
|
||||
cli
|
||||
|
||||
mov ebx, eax
|
||||
@@:
|
||||
mov edx, [ebx+0xF4]
|
||||
mov eax, [ebx+0xF0]
|
||||
mov ecx, [ebx+0xF4]
|
||||
cmp ecx, edx
|
||||
jne @B
|
||||
popfd
|
||||
|
||||
;96-bit arithmetic
|
||||
;ebx - low dword
|
||||
;esi - medium dword
|
||||
;edx - high dword
|
||||
|
||||
mul [hpet_period]
|
||||
mov ebx, eax
|
||||
mov esi, edx
|
||||
|
||||
mov eax, ecx
|
||||
mul [hpet_period]
|
||||
add esi, eax
|
||||
adc edx, 0
|
||||
mov eax, ebx
|
||||
mov ebx, esi
|
||||
shrd eax, ebx, 10
|
||||
shrd esi, edx, 10
|
||||
mov edx, esi
|
||||
|
||||
pop esi
|
||||
pop ebx
|
||||
ret
|
||||
|
||||
.old_tics:
|
||||
mov eax, [timer_ticks]
|
||||
mov edx, 10000000
|
||||
mul edx
|
||||
ret
|
||||
167
kernel/branches/kolibri-lldw/core/clipboard.inc
Normal file
167
kernel/branches/kolibri-lldw/core/clipboard.inc
Normal file
@@ -0,0 +1,167 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
;------------------------------------------------------------------------------
|
||||
align 4
|
||||
sys_clipboard:
|
||||
xor eax, eax
|
||||
dec eax
|
||||
; check availability of main list
|
||||
cmp [clipboard_main_list], eax
|
||||
je .exit_1 ; main list area not found
|
||||
|
||||
test ebx, ebx ; 0 - Get the number of slots in the clipboard
|
||||
jnz .1
|
||||
; get the number of slots
|
||||
mov eax, [clipboard_slots]
|
||||
jmp .exit_1
|
||||
;------------------------------------------------------------------------------
|
||||
align 4
|
||||
.1:
|
||||
dec ebx ; 1 - Read the data from the clipboard
|
||||
jnz .2
|
||||
; verify the existence of slot
|
||||
cmp ecx, [clipboard_slots]
|
||||
jae .exit_2
|
||||
; get a pointer to the data of slot
|
||||
shl ecx, 2
|
||||
add ecx, [clipboard_main_list]
|
||||
mov esi, [ecx]
|
||||
mov ecx, [esi]
|
||||
; allocate memory for application for copy the data of slots
|
||||
push ecx
|
||||
stdcall user_alloc, ecx
|
||||
pop ecx
|
||||
; copying data of slots
|
||||
mov edi, eax
|
||||
cld
|
||||
rep movsb
|
||||
jmp .exit_1
|
||||
;------------------------------------------------------------------------------
|
||||
align 4
|
||||
.2:
|
||||
dec ebx ; 2 - Write the data to the clipboard
|
||||
jnz .3
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
stdcall is_region_userspace, edx, ecx
|
||||
jz @f
|
||||
mov eax, -1
|
||||
jmp .exit_1
|
||||
@@:
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; check the lock
|
||||
mov ebx, clipboard_write_lock
|
||||
xor eax, eax
|
||||
cmp [ebx], eax
|
||||
jne .exit_2
|
||||
; lock last slot
|
||||
inc eax
|
||||
mov [ebx], eax
|
||||
; check the overflow pointer of slots
|
||||
cmp [clipboard_slots], 1024
|
||||
jae .exit_3
|
||||
; get memory for new slot
|
||||
push ebx ecx edx
|
||||
stdcall kernel_alloc, ecx
|
||||
pop edx ecx ebx
|
||||
test eax, eax
|
||||
jz .exit_3
|
||||
; create a new slot
|
||||
mov edi, eax
|
||||
mov eax, [clipboard_slots]
|
||||
shl eax, 2
|
||||
add eax, [clipboard_main_list]
|
||||
mov [eax], edi
|
||||
; copy the data into the slot
|
||||
mov esi, edx
|
||||
mov eax, ecx
|
||||
cld
|
||||
stosd ; store size of slot
|
||||
sub ecx, 4
|
||||
add esi, 4
|
||||
rep movsb ; store slot data
|
||||
; increase the counter of slots
|
||||
inc [clipboard_slots]
|
||||
; unlock last slot
|
||||
xor eax, eax
|
||||
mov [ebx], eax
|
||||
jmp .exit_1
|
||||
;------------------------------------------------------------------------------
|
||||
align 4
|
||||
.3:
|
||||
dec ebx ; 3 - Delete the last slot in the clipboard
|
||||
jnz .4
|
||||
; check the availability of slots
|
||||
mov eax, [clipboard_slots]
|
||||
test eax, eax
|
||||
jz .exit_2
|
||||
; check the lock
|
||||
mov ebx, clipboard_write_lock
|
||||
xor eax, eax
|
||||
cmp [ebx], eax
|
||||
jne .exit_2
|
||||
; lock last slot
|
||||
inc eax
|
||||
mov [ebx], eax
|
||||
; decrease the counter of slots
|
||||
mov eax, clipboard_slots
|
||||
dec dword [eax]
|
||||
; free of kernel memory allocated for the slot
|
||||
mov eax, [eax]
|
||||
shl eax, 2
|
||||
add eax, [clipboard_main_list]
|
||||
mov eax, [eax]
|
||||
push ebx
|
||||
stdcall kernel_free, eax
|
||||
pop ebx
|
||||
; unlock last slot
|
||||
xor eax, eax
|
||||
mov [ebx], eax
|
||||
jmp .exit_1
|
||||
;------------------------------------------------------------------------------
|
||||
align 4
|
||||
.4:
|
||||
dec ebx ; 4 - Emergency discharge of clipboard
|
||||
jnz .exit
|
||||
; check the lock
|
||||
mov ebx, clipboard_write_lock
|
||||
xor eax, eax
|
||||
cmp [ebx], eax
|
||||
je .exit_2
|
||||
|
||||
; there should be a procedure for checking the integrity of the slots
|
||||
; and I will do so in the future
|
||||
|
||||
; unlock last slot
|
||||
mov [ebx], eax
|
||||
jmp .exit
|
||||
;------------------------------------------------------------------------------
|
||||
align 4
|
||||
.exit_3:
|
||||
; unlock last slot
|
||||
xor eax, eax
|
||||
mov [ebx], eax
|
||||
.exit_2:
|
||||
xor eax, eax
|
||||
inc eax ; error
|
||||
.exit_1:
|
||||
mov [esp + 32], eax
|
||||
.exit:
|
||||
ret
|
||||
;------------------------------------------------------------------------------
|
||||
uglobal
|
||||
align 4
|
||||
clipboard_slots dd ?
|
||||
clipboard_main_list dd ?
|
||||
clipboard_write_lock dd ?
|
||||
endg
|
||||
;------------------------------------------------------------------------------
|
||||
21
kernel/branches/kolibri-lldw/core/conf_lib-sp.inc
Normal file
21
kernel/branches/kolibri-lldw/core/conf_lib-sp.inc
Normal file
@@ -0,0 +1,21 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
; Éste archivo debe ser editado con codificación CP866
|
||||
|
||||
ugui_mouse_speed cp850 'velocidad del ratón',0
|
||||
ugui_mouse_delay cp850 'demora del ratón',0
|
||||
|
||||
udev cp850 'disp',0
|
||||
unet cp850 'red',0
|
||||
unet_active cp850 'activa',0
|
||||
unet_addr cp850 'direc',0
|
||||
unet_mask cp850 'másc',0
|
||||
unet_gate cp850 'puer',0
|
||||
254
kernel/branches/kolibri-lldw/core/conf_lib.inc
Normal file
254
kernel/branches/kolibri-lldw/core/conf_lib.inc
Normal file
@@ -0,0 +1,254 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;-------------------------------------------------------------------------
|
||||
;Loading configuration from ini file
|
||||
; {SPraid.simba}
|
||||
;-------------------------------------------------------------------------
|
||||
|
||||
$Revision$
|
||||
|
||||
iglobal
|
||||
conf_path_sect:
|
||||
db 'path',0
|
||||
|
||||
conf_fname db '/sys/sys.conf',0
|
||||
endg
|
||||
; set soke kernel configuration
|
||||
proc set_kernel_conf
|
||||
locals
|
||||
par db 30 dup(?)
|
||||
endl
|
||||
|
||||
pushad
|
||||
;[gui]
|
||||
;mouse_speed
|
||||
|
||||
lea eax, [par]
|
||||
push eax
|
||||
invoke ini.get_str, conf_fname, ugui, ugui_mouse_speed, \
|
||||
eax,30, ugui_mouse_speed_def
|
||||
pop eax
|
||||
stdcall strtoint, eax
|
||||
mov [mouse_speed_factor], ax
|
||||
|
||||
;mouse_delay
|
||||
lea eax, [par]
|
||||
push eax
|
||||
invoke ini.get_str, conf_fname, ugui, ugui_mouse_delay, \
|
||||
eax,30, ugui_mouse_delay_def
|
||||
pop eax
|
||||
stdcall strtoint, eax
|
||||
mov [mouse_delay], eax
|
||||
|
||||
|
||||
;midibase
|
||||
lea eax, [par]
|
||||
push eax
|
||||
invoke ini.get_str, conf_fname, udev, udev_midibase, eax, 30, udev_midibase_def
|
||||
pop eax
|
||||
stdcall strtoint, eax
|
||||
|
||||
cmp eax, 0x100
|
||||
jb @f
|
||||
cmp eax, 0x10000
|
||||
jae @f
|
||||
mov [midi_base], ax
|
||||
mov [mididp], eax
|
||||
inc eax
|
||||
mov [midisp], eax
|
||||
@@:
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
iglobal
|
||||
ugui db 'gui',0
|
||||
ugui_mouse_speed_def db '2',0
|
||||
ugui_mouse_delay_def db '0x00A',0
|
||||
udev_midibase db 'midibase',0
|
||||
udev_midibase_def db '0x320',0
|
||||
endg
|
||||
|
||||
iglobal
|
||||
if lang eq sp
|
||||
include 'core/conf_lib-sp.inc'
|
||||
else
|
||||
ugui_mouse_speed db 'mouse_speed',0
|
||||
ugui_mouse_delay db 'mouse_delay',0
|
||||
udev db 'dev',0
|
||||
unet db 'net',0
|
||||
unet_active db 'active',0
|
||||
unet_addr db 'addr',0
|
||||
unet_mask db 'mask',0
|
||||
unet_gate db 'gate',0
|
||||
end if
|
||||
unet_def db 0
|
||||
endg
|
||||
; convert string to DWord
|
||||
proc strtoint stdcall,strs
|
||||
pushad
|
||||
|
||||
mov eax, [strs]
|
||||
inc eax
|
||||
mov bl, [eax]
|
||||
cmp bl, 'x'
|
||||
je .hex
|
||||
cmp bl, 'X'
|
||||
je .hex
|
||||
jmp .dec
|
||||
.hex:
|
||||
inc eax
|
||||
stdcall strtoint_hex, eax
|
||||
jmp .exit
|
||||
.dec:
|
||||
dec eax
|
||||
stdcall strtoint_dec, eax
|
||||
.exit:
|
||||
mov [esp+28], eax
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
; convert string to DWord for decimal value
|
||||
proc strtoint_dec stdcall,strs
|
||||
pushad
|
||||
xor edx, edx
|
||||
; поиск конца
|
||||
mov esi, [strs]
|
||||
@@:
|
||||
lodsb
|
||||
or al, al
|
||||
jnz @b
|
||||
mov ebx, esi
|
||||
mov esi, [strs]
|
||||
dec ebx
|
||||
sub ebx, esi
|
||||
mov ecx, 1
|
||||
|
||||
@@:
|
||||
dec ebx
|
||||
or ebx, ebx
|
||||
jz @f
|
||||
imul ecx, ecx, 10; порядок
|
||||
jmp @b
|
||||
@@:
|
||||
|
||||
xchg ebx, ecx
|
||||
|
||||
|
||||
xor ecx, ecx
|
||||
|
||||
|
||||
@@:
|
||||
xor eax, eax
|
||||
lodsb
|
||||
cmp al, 0
|
||||
je .eend
|
||||
|
||||
sub al, 30h
|
||||
imul ebx
|
||||
add ecx, eax
|
||||
push ecx
|
||||
xchg eax, ebx
|
||||
mov ecx, 10
|
||||
div ecx
|
||||
xchg eax, ebx
|
||||
pop ecx
|
||||
jmp @b
|
||||
|
||||
.eend:
|
||||
mov [esp+28], ecx
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
;convert string to DWord for hex value
|
||||
proc strtoint_hex stdcall,strs
|
||||
pushad
|
||||
xor edx, edx
|
||||
|
||||
mov esi, [strs]
|
||||
mov ebx, 1
|
||||
add esi, 1
|
||||
|
||||
@@:
|
||||
lodsb
|
||||
or al, al
|
||||
jz @f
|
||||
shl ebx, 4
|
||||
jmp @b
|
||||
@@:
|
||||
xor ecx, ecx
|
||||
mov esi, [strs]
|
||||
|
||||
@@:
|
||||
xor eax, eax
|
||||
lodsb
|
||||
cmp al, 0
|
||||
je .eend
|
||||
|
||||
cmp al, 'a'
|
||||
jae .bm
|
||||
cmp al, 'A'
|
||||
jae .bb
|
||||
jmp .cc
|
||||
.bm: ; 57h
|
||||
sub al, 57h
|
||||
jmp .do
|
||||
|
||||
.bb: ; 37h
|
||||
sub al, 37h
|
||||
jmp .do
|
||||
|
||||
.cc: ; 30h
|
||||
sub al, 30h
|
||||
|
||||
.do:
|
||||
imul ebx
|
||||
add ecx, eax
|
||||
shr ebx, 4
|
||||
|
||||
jmp @b
|
||||
|
||||
.eend:
|
||||
mov [esp+28], ecx
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
; convert string to DWord for IP addres
|
||||
proc do_inet_adr stdcall,strs
|
||||
pushad
|
||||
|
||||
mov esi, [strs]
|
||||
mov ebx, 0
|
||||
.next:
|
||||
push esi
|
||||
@@:
|
||||
lodsb
|
||||
or al, al
|
||||
jz @f
|
||||
cmp al, '.'
|
||||
jz @f
|
||||
jmp @b
|
||||
@@:
|
||||
mov cl, al
|
||||
mov [esi-1], byte 0
|
||||
;pop eax
|
||||
call strtoint_dec
|
||||
rol eax, 24
|
||||
ror ebx, 8
|
||||
add ebx, eax
|
||||
or cl, cl
|
||||
jz @f
|
||||
jmp .next
|
||||
@@:
|
||||
mov [esp+28], ebx
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
455
kernel/branches/kolibri-lldw/core/debug.inc
Normal file
455
kernel/branches/kolibri-lldw/core/debug.inc
Normal file
@@ -0,0 +1,455 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
; diamond, 2006
|
||||
sys_debug_services:
|
||||
cmp ebx, 9
|
||||
ja @f
|
||||
jmp dword [sys_debug_services_table+ebx*4]
|
||||
@@:
|
||||
ret
|
||||
iglobal
|
||||
align 4
|
||||
sys_debug_services_table:
|
||||
dd debug_set_event_data
|
||||
dd debug_getcontext
|
||||
dd debug_setcontext
|
||||
dd debug_detach
|
||||
dd debug_suspend
|
||||
dd debug_resume
|
||||
dd debug_read_process_memory
|
||||
dd debug_write_process_memory
|
||||
dd debug_terminate
|
||||
dd debug_set_drx
|
||||
endg
|
||||
debug_set_event_data:
|
||||
; in: ecx = pointer
|
||||
; destroys eax
|
||||
mov eax, [current_slot]
|
||||
mov [eax+APPDATA.dbg_event_mem], ecx
|
||||
ret
|
||||
|
||||
get_debuggee_slot:
|
||||
; in: ecx=PID
|
||||
; out: CF=1 if error
|
||||
; CF=0 and eax=slot*0x20 if ok
|
||||
; out: interrupts disabled
|
||||
cli
|
||||
mov eax, ecx
|
||||
call pid_to_slot
|
||||
test eax, eax
|
||||
jz .ret_bad
|
||||
shl eax, 5
|
||||
push ebx
|
||||
mov ebx, [current_slot_idx]
|
||||
cmp [SLOT_BASE+eax*8+APPDATA.debugger_slot], ebx
|
||||
pop ebx
|
||||
jnz .ret_bad
|
||||
; clc ; automatically
|
||||
ret
|
||||
.ret_bad:
|
||||
stc
|
||||
ret
|
||||
|
||||
debug_detach:
|
||||
; in: ecx=pid
|
||||
; destroys eax,ebx
|
||||
call get_debuggee_slot
|
||||
jc .ret
|
||||
and dword [eax*8+SLOT_BASE+APPDATA.debugger_slot], 0
|
||||
call do_resume
|
||||
.ret:
|
||||
sti
|
||||
ret
|
||||
|
||||
debug_terminate:
|
||||
; in: ecx=pid
|
||||
call get_debuggee_slot
|
||||
jc debug_detach.ret
|
||||
mov ecx, eax
|
||||
shr ecx, 5
|
||||
; push 2
|
||||
; pop ebx
|
||||
mov edx, esi
|
||||
jmp sysfn_terminate
|
||||
|
||||
debug_suspend:
|
||||
; in: ecx=pid
|
||||
; destroys eax,ecx
|
||||
; { Patch by Coldy (rev. 7125), reason: http://board.kolibrios.org/viewtopic.php?f=1&t=1712&p=75957#p75957
|
||||
; cli
|
||||
; mov eax, ecx
|
||||
; call pid_to_slot
|
||||
; shl eax, 5
|
||||
; jz .ret
|
||||
call get_debuggee_slot
|
||||
jc .ret
|
||||
; } End patch
|
||||
mov cl, [TASK_TABLE+eax+TASKDATA.state] ; process state
|
||||
test cl, cl
|
||||
jz .1
|
||||
cmp cl, 5
|
||||
jnz .ret
|
||||
mov cl, 2
|
||||
.2:
|
||||
mov [TASK_TABLE+eax+TASKDATA.state], cl
|
||||
.ret:
|
||||
sti
|
||||
ret
|
||||
.1:
|
||||
inc ecx
|
||||
jmp .2
|
||||
|
||||
do_resume:
|
||||
mov cl, [TASK_TABLE+eax+TASKDATA.state]
|
||||
cmp cl, 1
|
||||
jz .1
|
||||
cmp cl, 2
|
||||
jnz .ret
|
||||
mov cl, 5
|
||||
.2:
|
||||
mov [TASK_TABLE+eax+TASKDATA.state], cl
|
||||
.ret:
|
||||
ret
|
||||
.1:
|
||||
dec ecx
|
||||
jmp .2
|
||||
|
||||
debug_resume:
|
||||
; in: ecx=pid
|
||||
; destroys eax,ebx
|
||||
cli
|
||||
mov eax, ecx
|
||||
call pid_to_slot
|
||||
shl eax, 5
|
||||
jz .ret
|
||||
call do_resume
|
||||
.ret:
|
||||
sti
|
||||
ret
|
||||
|
||||
debug_getcontext:
|
||||
; in:
|
||||
; ecx=pid
|
||||
; edx=sizeof(CONTEXT)
|
||||
; esi->CONTEXT
|
||||
; destroys eax,ebx,ecx,edx,esi,edi
|
||||
|
||||
xor ebx, ebx ; 0 - get only gp regs
|
||||
cmp edx, 40
|
||||
je .std_ctx
|
||||
|
||||
cmp edx, 48+288
|
||||
jne .ret
|
||||
|
||||
inc ebx ; 1 - get sse context
|
||||
; TODO legacy 32-bit FPU/MMX context
|
||||
.std_ctx:
|
||||
call get_debuggee_slot
|
||||
jc .ret
|
||||
|
||||
shr eax, 5
|
||||
cmp eax, [fpu_owner]
|
||||
jne @f
|
||||
inc bh ; set swap context flag
|
||||
@@:
|
||||
shl eax, 8
|
||||
mov edi, esi
|
||||
mov eax, [eax+SLOT_BASE+APPDATA.pl0_stack]
|
||||
lea esi, [eax+RING0_STACK_SIZE]
|
||||
|
||||
.ring0:
|
||||
; note that following code assumes that all interrupt/exception handlers
|
||||
; save ring-3 context by pushad in this order
|
||||
; top of ring0 stack: ring3 stack ptr (ss+esp), iret data (cs+eip+eflags), pushad
|
||||
sub esi, 8+12+20h
|
||||
lodsd ;edi
|
||||
mov [edi+24h], eax
|
||||
lodsd ;esi
|
||||
mov [edi+20h], eax
|
||||
lodsd ; ebp
|
||||
mov [edi+1Ch], eax
|
||||
lodsd ;esp
|
||||
lodsd ;ebx
|
||||
mov [edi+14h], eax
|
||||
lodsd ;edx
|
||||
mov [edi+10h], eax
|
||||
lodsd ;ecx
|
||||
mov [edi+0Ch], eax
|
||||
lodsd ;eax
|
||||
mov [edi+8], eax
|
||||
lodsd ;eip
|
||||
mov [edi], eax
|
||||
lodsd ;cs
|
||||
lodsd ;eflags
|
||||
mov [edi+4], eax
|
||||
lodsd ;esp
|
||||
mov [edi+18h], eax
|
||||
|
||||
dec bl
|
||||
js .ret
|
||||
dec bl
|
||||
jns .ret
|
||||
|
||||
test bh, bh ; check swap flag
|
||||
jz @F
|
||||
|
||||
ffree st0 ; swap context
|
||||
@@:
|
||||
|
||||
add esi, 4 ;top of ring0 stack
|
||||
;fpu/sse context saved here
|
||||
add edi, 40
|
||||
mov eax, 1 ;sse context
|
||||
stosd
|
||||
xor eax, eax ;reserved dword
|
||||
stosd
|
||||
|
||||
mov ecx, 288/4
|
||||
rep movsd ;copy sse context
|
||||
|
||||
.ret:
|
||||
sti
|
||||
ret
|
||||
|
||||
debug_setcontext:
|
||||
; in:
|
||||
; ecx=pid
|
||||
; edx=sizeof(CONTEXT)
|
||||
; esi->CONTEXT
|
||||
; destroys eax,ecx,edx,esi,edi
|
||||
cmp edx, 28h
|
||||
jnz .ret
|
||||
|
||||
call get_debuggee_slot
|
||||
jc .stiret
|
||||
; mov esi, edx
|
||||
mov eax, [eax*8+SLOT_BASE+APPDATA.pl0_stack]
|
||||
lea edi, [eax+RING0_STACK_SIZE]
|
||||
|
||||
.ring0:
|
||||
sub edi, 8+12+20h
|
||||
mov eax, [esi+24h] ;edi
|
||||
stosd
|
||||
mov eax, [esi+20h] ;esi
|
||||
stosd
|
||||
mov eax, [esi+1Ch] ;ebp
|
||||
stosd
|
||||
scasd
|
||||
mov eax, [esi+14h] ;ebx
|
||||
stosd
|
||||
mov eax, [esi+10h] ;edx
|
||||
stosd
|
||||
mov eax, [esi+0Ch] ;ecx
|
||||
stosd
|
||||
mov eax, [esi+8] ;eax
|
||||
stosd
|
||||
mov eax, [esi] ;eip
|
||||
stosd
|
||||
scasd
|
||||
mov eax, [esi+4] ;eflags
|
||||
stosd
|
||||
mov eax, [esi+18h] ;esp
|
||||
stosd
|
||||
.stiret:
|
||||
sti
|
||||
.ret:
|
||||
ret
|
||||
|
||||
debug_set_drx:
|
||||
call get_debuggee_slot
|
||||
jc .errret
|
||||
mov ebp, eax
|
||||
lea eax, [eax*8+SLOT_BASE+APPDATA.dbg_regs]
|
||||
; [eax]=dr0, [eax+4]=dr1, [eax+8]=dr2, [eax+C]=dr3
|
||||
; [eax+10]=dr7
|
||||
cmp esi, OS_BASE
|
||||
jae .errret
|
||||
cmp dl, 3
|
||||
ja .errret
|
||||
mov ecx, dr7
|
||||
;fix me
|
||||
xchg ecx, edx
|
||||
shr edx, cl
|
||||
shr edx, cl
|
||||
xchg ecx, edx
|
||||
|
||||
test ecx, 2 ; bit 1+2*index = G0..G3, global break enable
|
||||
jnz .errret2
|
||||
test dh, dh
|
||||
jns .new
|
||||
; clear breakpoint
|
||||
movzx edx, dl
|
||||
add edx, edx
|
||||
and dword [eax+edx*2], 0 ; clear DR<i>
|
||||
btr dword [eax+10h], edx ; clear L<i> bit
|
||||
test byte [eax+10h], 55h
|
||||
jnz .okret
|
||||
; imul eax, ebp, tss_step/32
|
||||
; and byte [eax + tss_data + TSS._trap], not 1
|
||||
and [ebp*8 + SLOT_BASE+APPDATA.dbg_state], not 1
|
||||
.okret:
|
||||
and dword [esp+32], 0
|
||||
sti
|
||||
ret
|
||||
.errret:
|
||||
sti
|
||||
mov dword [esp+32], 1
|
||||
ret
|
||||
.errret2:
|
||||
sti
|
||||
mov dword [esp+32], 2
|
||||
ret
|
||||
.new:
|
||||
; add new breakpoint
|
||||
; dl=index; dh=flags; esi=address
|
||||
test dh, 0xF0
|
||||
jnz .errret
|
||||
mov cl, dh
|
||||
and cl, 3
|
||||
cmp cl, 2
|
||||
jz .errret
|
||||
mov cl, dh
|
||||
shr cl, 2
|
||||
cmp cl, 2
|
||||
jz .errret
|
||||
|
||||
mov ebx, esi
|
||||
test bl, dl
|
||||
|
||||
jnz .errret
|
||||
or byte [eax+10h+1], 3 ; set GE and LE flags
|
||||
|
||||
movzx edx, dh
|
||||
movzx ecx, dl
|
||||
add ecx, ecx
|
||||
bts dword [eax+10h], ecx ; set L<i> flag
|
||||
add ecx, ecx
|
||||
mov [eax+ecx], ebx;esi ; set DR<i>
|
||||
shl edx, cl
|
||||
mov ebx, 0xF
|
||||
shl ebx, cl
|
||||
not ebx
|
||||
and [eax+10h+2], bx
|
||||
or [eax+10h+2], dx ; set R/W and LEN fields
|
||||
; imul eax, ebp, tss_step/32
|
||||
; or byte [eax + tss_data + TSS._trap], 1
|
||||
or [ebp*8 + SLOT_BASE+APPDATA.dbg_state], 1
|
||||
jmp .okret
|
||||
|
||||
debug_read_process_memory:
|
||||
; in:
|
||||
; ecx=pid
|
||||
; edx=length
|
||||
; edi->buffer in debugger
|
||||
; esi=address in debuggee
|
||||
; out: [esp+36]=sizeof(read)
|
||||
; destroys all
|
||||
call get_debuggee_slot
|
||||
jc .err
|
||||
shr eax, 5
|
||||
mov ecx, edi
|
||||
call read_process_memory
|
||||
sti
|
||||
mov dword [esp+32], eax
|
||||
ret
|
||||
.err:
|
||||
or dword [esp+32], -1
|
||||
ret
|
||||
|
||||
debug_write_process_memory:
|
||||
; in:
|
||||
; ecx=pid
|
||||
; edx=length
|
||||
; edi->buffer in debugger
|
||||
; esi=address in debuggee
|
||||
; out: [esp+36]=sizeof(write)
|
||||
; destroys all
|
||||
call get_debuggee_slot
|
||||
jc debug_read_process_memory.err
|
||||
shr eax, 5
|
||||
mov ecx, edi
|
||||
call write_process_memory
|
||||
sti
|
||||
mov [esp+32], eax
|
||||
ret
|
||||
|
||||
debugger_notify:
|
||||
; in: eax=debugger slot
|
||||
; ecx=size of debug message
|
||||
; [esp+4]..[esp+4+ecx]=message
|
||||
; interrupts must be disabled!
|
||||
; destroys all general registers
|
||||
; interrupts remain disabled
|
||||
xchg ebp, eax
|
||||
mov edi, [timer_ticks]
|
||||
add edi, 500 ; 5 sec timeout
|
||||
.1:
|
||||
mov eax, ebp
|
||||
shl eax, 8
|
||||
mov esi, [SLOT_BASE+eax+APPDATA.dbg_event_mem]
|
||||
test esi, esi
|
||||
jz .ret
|
||||
; read buffer header
|
||||
push ecx
|
||||
push eax
|
||||
push eax
|
||||
mov eax, ebp
|
||||
mov ecx, esp
|
||||
mov edx, 8
|
||||
call read_process_memory
|
||||
cmp eax, edx
|
||||
jz @f
|
||||
add esp, 12
|
||||
jmp .ret
|
||||
@@:
|
||||
cmp dword [ecx], 0
|
||||
jg @f
|
||||
.2:
|
||||
pop ecx
|
||||
pop ecx
|
||||
pop ecx
|
||||
cmp dword [current_slot_idx], 1
|
||||
jnz .notos
|
||||
cmp [timer_ticks], edi
|
||||
jae .ret
|
||||
.notos:
|
||||
sti
|
||||
call change_task
|
||||
cli
|
||||
jmp .1
|
||||
@@:
|
||||
mov edx, [ecx+8]
|
||||
add edx, [ecx+4]
|
||||
cmp edx, [ecx]
|
||||
ja .2
|
||||
; advance buffer position
|
||||
push edx
|
||||
mov edx, 4
|
||||
sub ecx, edx
|
||||
mov eax, ebp
|
||||
add esi, edx
|
||||
call write_process_memory
|
||||
pop eax
|
||||
; write message
|
||||
mov eax, ebp
|
||||
add esi, edx
|
||||
add esi, [ecx+8]
|
||||
add ecx, 20
|
||||
pop edx
|
||||
pop edx
|
||||
pop edx
|
||||
call write_process_memory
|
||||
; new debug event
|
||||
mov eax, ebp
|
||||
shl eax, BSF sizeof.APPDATA
|
||||
or [SLOT_BASE+eax+APPDATA.occurred_events], EVENT_DEBUG
|
||||
.ret:
|
||||
ret
|
||||
1518
kernel/branches/kolibri-lldw/core/dll.inc
Normal file
1518
kernel/branches/kolibri-lldw/core/dll.inc
Normal file
File diff suppressed because it is too large
Load Diff
40
kernel/branches/kolibri-lldw/core/export.inc
Normal file
40
kernel/branches/kolibri-lldw/core/export.inc
Normal file
@@ -0,0 +1,40 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
; Macroinstruction for making export section
|
||||
|
||||
|
||||
macro export dllname,[label,string]
|
||||
{ common
|
||||
local module,addresses,names,ordinal,count
|
||||
count = 0
|
||||
forward
|
||||
count = count+1
|
||||
common
|
||||
dd 0,0,0, (module-OS_BASE) , 1
|
||||
dd count,count,(addresses-OS_BASE),(names-OS_BASE),(ordinal-OS_BASE)
|
||||
addresses:
|
||||
forward
|
||||
dd (label-OS_BASE)
|
||||
common
|
||||
names:
|
||||
forward
|
||||
local name
|
||||
dd (name-OS_BASE)
|
||||
common
|
||||
ordinal:
|
||||
count = 0
|
||||
forward
|
||||
dw count
|
||||
count = count+1
|
||||
common
|
||||
module db dllname,0
|
||||
forward
|
||||
name db string,0
|
||||
}
|
||||
146
kernel/branches/kolibri-lldw/core/exports.inc
Normal file
146
kernel/branches/kolibri-lldw/core/exports.inc
Normal file
@@ -0,0 +1,146 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
align 4
|
||||
__exports:
|
||||
export 'KERNEL', \
|
||||
alloc_kernel_space, 'AllocKernelSpace', \ ; stdcall
|
||||
alloc_page, 'AllocPage', \ ; gcc ABI
|
||||
alloc_pages, 'AllocPages', \ ; stdcall
|
||||
commit_pages, 'CommitPages', \ ; eax, ebx, ecx
|
||||
\
|
||||
disk_add, 'DiskAdd', \ ;stdcall
|
||||
disk_del, 'DiskDel', \
|
||||
disk_media_changed, 'DiskMediaChanged', \ ;stdcall
|
||||
\
|
||||
create_event, 'CreateEvent', \ ; ecx, esi
|
||||
destroy_event, 'DestroyEvent', \ ;
|
||||
raise_event, 'RaiseEvent', \ ; eax, ebx, edx, esi
|
||||
wait_event, 'WaitEvent', \ ; eax, ebx
|
||||
wait_event_timeout, 'WaitEventTimeout', \ ; eax, ebx, ecx
|
||||
get_event_ex, 'GetEvent', \ ; edi
|
||||
clear_event, 'ClearEvent', \ ;see EVENT.inc for specification
|
||||
send_event, 'SendEvent', \ ;see EVENT.inc for specification
|
||||
\
|
||||
create_kernel_object, 'CreateObject', \
|
||||
create_ring_buffer, 'CreateRingBuffer', \ ; stdcall
|
||||
destroy_kernel_object, 'DestroyObject', \
|
||||
free_kernel_space, 'FreeKernelSpace', \ ; stdcall
|
||||
free_page, 'FreePage', \ ; eax
|
||||
kernel_alloc, 'KernelAlloc', \ ; stdcall
|
||||
kernel_free, 'KernelFree', \ ; stdcall
|
||||
malloc, 'Kmalloc', \
|
||||
free, 'Kfree', \
|
||||
map_io_mem, 'MapIoMem', \ ; stdcall
|
||||
map_page, 'MapPage', \ ; stdcall
|
||||
get_pg_addr, 'GetPgAddr', \ ; eax
|
||||
get_phys_addr, 'GetPhysAddr', \ ; eax
|
||||
map_space, 'MapSpace', \
|
||||
release_pages, 'ReleasePages', \
|
||||
alloc_dma24, 'AllocDMA24', \ ; stdcall
|
||||
\
|
||||
init_rwsem, 'InitRwsem', \ ; gcc fastcall
|
||||
down_read, 'DownRead', \ ; gcc fastcall
|
||||
down_write, 'DownWrite', \ ; gcc fastcall
|
||||
up_read, 'UpRead', \ ; gcc fastcall
|
||||
up_write, 'UpWrite', \ ; gcc fastacll
|
||||
mutex_init, 'MutexInit', \ ; gcc fastcall
|
||||
mutex_lock, 'MutexLock', \ ; gcc fastcall
|
||||
mutex_unlock, 'MutexUnlock', \ ; gcc fastcall
|
||||
\
|
||||
get_display, 'GetDisplay', \
|
||||
set_screen, 'SetScreen', \
|
||||
set_framebuffer, 'SetFramebuffer', \ ; gcc fastcall
|
||||
window._.get_rect, 'GetWindowRect', \ ; gcc fastcall
|
||||
pci_api_drv, 'PciApi', \
|
||||
pci_read8, 'PciRead8', \ ; stdcall
|
||||
pci_read16, 'PciRead16', \ ; stdcall
|
||||
pci_read32, 'PciRead32', \ ; stdcall
|
||||
pci_write8, 'PciWrite8', \ ; stdcall
|
||||
pci_write16, 'PciWrite16', \ ; stdcall
|
||||
pci_write32, 'PciWrite32', \ ; stdcall
|
||||
\
|
||||
get_pid, 'GetPid', \
|
||||
get_service, 'GetService', \ ;
|
||||
reg_service, 'RegService', \ ; stdcall
|
||||
attach_int_handler, 'AttachIntHandler', \ ; stdcall
|
||||
user_alloc, 'UserAlloc', \ ; stdcall
|
||||
user_alloc_at, 'UserAllocAt', \ ; stdcall
|
||||
user_free, 'UserFree', \ ; stdcall
|
||||
unmap_pages, 'UnmapPages', \ ; eax, ecx
|
||||
sys_msg_board_str, 'SysMsgBoardStr', \
|
||||
sys_msg_board, 'SysMsgBoard', \
|
||||
get_clock_ns, 'GetClockNs', \ ;retval edx:eax 64-bit value
|
||||
get_timer_ticks, 'GetTimerTicks', \
|
||||
get_stack_base, 'GetStackBase', \
|
||||
delay_hs, 'Delay', \ ; ebx
|
||||
set_mouse_data, 'SetMouseData', \ ;
|
||||
set_keyboard_data, 'SetKeyboardData', \ ; gcc fastcall
|
||||
register_keyboard, 'RegKeyboard', \
|
||||
delete_keyboard, 'DelKeyboard', \
|
||||
get_cpu_freq, 'GetCpuFreq', \
|
||||
\
|
||||
new_sys_threads, 'CreateThread', \ ; ebx, ecx, edx
|
||||
\
|
||||
srv_handler, 'ServiceHandler', \
|
||||
fpu_save, 'FpuSave', \
|
||||
fpu_restore, 'FpuRestore', \
|
||||
avx_save_size, 'AvxSaveSize', \
|
||||
avx_save, 'AvxSave', \
|
||||
avx_restore, 'AvxRestore', \
|
||||
r_f_port_area, 'ReservePortArea', \
|
||||
boot_log, 'Boot_Log', \
|
||||
\
|
||||
load_cursor, 'LoadCursor', \ ;stdcall
|
||||
\
|
||||
get_curr_task, 'GetCurrentTask', \
|
||||
change_task, 'ChangeTask', \
|
||||
load_file, 'LoadFile', \ ;retval eax, ebx
|
||||
delay_ms, 'Sleep', \
|
||||
\
|
||||
strncat, 'strncat', \
|
||||
strncpy, 'strncpy', \
|
||||
strncmp, 'strncmp', \
|
||||
strnlen, 'strnlen', \
|
||||
strchr, 'strchr', \
|
||||
strrchr, 'strrchr', \
|
||||
\
|
||||
timer_hs, 'TimerHS', \
|
||||
timer_hs, 'TimerHs', \ ; shit happens
|
||||
cancel_timer_hs, 'CancelTimerHS', \
|
||||
\
|
||||
reg_usb_driver, 'RegUSBDriver', \
|
||||
usb_open_pipe, 'USBOpenPipe', \
|
||||
usb_close_pipe, 'USBClosePipe', \
|
||||
usb_normal_transfer_async, 'USBNormalTransferAsync', \
|
||||
usb_control_async, 'USBControlTransferAsync', \
|
||||
usb_get_param, 'USBGetParam', \
|
||||
usb_hc_func, 'USBHCFunc', \
|
||||
\
|
||||
\ ; The intrakernel function of working with the file system.
|
||||
\ ; Duplicates system call 70.
|
||||
file_system_lfn_protected_registers, 'FS_Service', \
|
||||
\
|
||||
net_add_device, 'NetRegDev', \
|
||||
net_remove_device, 'NetUnRegDev', \
|
||||
net_ptr_to_num, 'NetPtrToNum', \
|
||||
net_link_changed, 'NetLinkChanged', \
|
||||
eth_input, 'EthInput', \
|
||||
net_buff_alloc, 'NetAlloc', \
|
||||
net_buff_free, 'NetFree', \
|
||||
\
|
||||
get_pcidev_list, 'GetPCIList', \
|
||||
\
|
||||
acpi_get_root_ptr, 'AcpiGetRootPtr', \
|
||||
\
|
||||
0, 'LFBAddress' ; must be the last one
|
||||
|
||||
load kernel_exports_count dword from __exports + 24
|
||||
load kernel_exports_addresses dword from __exports + 28
|
||||
exp_lfb = OS_BASE + kernel_exports_addresses + (kernel_exports_count - 1) * 4 - 4
|
||||
476
kernel/branches/kolibri-lldw/core/ext_lib.inc
Normal file
476
kernel/branches/kolibri-lldw/core/ext_lib.inc
Normal file
@@ -0,0 +1,476 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
; External kernel dependencies (libraries) loading.
|
||||
; The code currently does not work, requires correcting dll.inc.
|
||||
|
||||
$Revision$
|
||||
|
||||
if 0
|
||||
iglobal
|
||||
tmp_file_name_size dd 1
|
||||
endg
|
||||
|
||||
uglobal
|
||||
tmp_file_name_table dd ?
|
||||
s_libname rb 64
|
||||
def_val_1 db ?
|
||||
endg
|
||||
|
||||
macro library [name,fname]
|
||||
{
|
||||
forward
|
||||
dd __#name#_library_table__,__#name#_library_name__
|
||||
common
|
||||
dd 0
|
||||
forward
|
||||
__#name#_library_name__ db fname,0
|
||||
}
|
||||
|
||||
macro import lname,[name,sname]
|
||||
{
|
||||
common
|
||||
align 4
|
||||
__#lname#_library_table__:
|
||||
forward
|
||||
name dd __#name#_import_name__
|
||||
common
|
||||
dd 0
|
||||
forward
|
||||
__#name#_import_name__ db sname,0
|
||||
}
|
||||
|
||||
macro export [name,sname]
|
||||
{
|
||||
align 4
|
||||
forward
|
||||
dd __#name#_export_name__,name
|
||||
common
|
||||
dd 0
|
||||
forward
|
||||
__#name#_export_name__ db sname,0
|
||||
}
|
||||
|
||||
|
||||
|
||||
align 4 ; loading library (use kernel functions)
|
||||
proc load_k_library stdcall, file_name:dword
|
||||
locals
|
||||
coff dd ?
|
||||
sym dd ?
|
||||
strings dd ?
|
||||
img_size dd ?
|
||||
img_base dd ?
|
||||
exports dd ?
|
||||
endl
|
||||
|
||||
cli
|
||||
|
||||
stdcall load_file, [file_name]
|
||||
test eax, eax
|
||||
jz .fail
|
||||
|
||||
mov [coff], eax
|
||||
movzx ecx, [eax+CFH.nSections]
|
||||
xor ebx, ebx
|
||||
|
||||
lea edx, [eax+20]
|
||||
@@:
|
||||
add ebx, [edx+CFS.SizeOfRawData]
|
||||
add ebx, 15
|
||||
and ebx, not 15
|
||||
add edx, COFF_SECTION_SIZE
|
||||
dec ecx
|
||||
jnz @B
|
||||
mov [img_size], ebx
|
||||
|
||||
stdcall kernel_alloc, [img_size]
|
||||
|
||||
test eax, eax
|
||||
jz .fail
|
||||
mov [img_base], eax
|
||||
|
||||
mov edx, [coff]
|
||||
movzx ebx, [edx+CFH.nSections]
|
||||
mov edi, [img_base]
|
||||
lea eax, [edx+20]
|
||||
@@:
|
||||
mov [eax+CFS.VirtualAddress], edi
|
||||
mov esi, [eax+CFS.PtrRawData]
|
||||
test esi, esi
|
||||
jnz .copy
|
||||
add edi, [eax+CFS.SizeOfRawData]
|
||||
jmp .next
|
||||
.copy:
|
||||
add esi, edx
|
||||
mov ecx, [eax+CFS.SizeOfRawData]
|
||||
cld
|
||||
rep movsb
|
||||
.next:
|
||||
add edi, 15
|
||||
and edi, not 15
|
||||
add eax, COFF_SECTION_SIZE
|
||||
dec ebx
|
||||
jnz @B
|
||||
|
||||
mov ebx, [edx+CFH.pSymTable]
|
||||
add ebx, edx
|
||||
mov [sym], ebx
|
||||
mov ecx, [edx+CFH.nSymbols]
|
||||
add ecx, ecx
|
||||
lea ecx, [ecx+ecx*8];ecx*=18 = nSymbols*CSYM_SIZE
|
||||
add ecx, [sym]
|
||||
mov [strings], ecx
|
||||
|
||||
lea eax, [edx+20]
|
||||
|
||||
stdcall fix_coff_symbols, eax, [sym], [edx+CFH.nSymbols], \
|
||||
[strings], dword 0
|
||||
test eax, eax
|
||||
jnz @F
|
||||
|
||||
@@:
|
||||
mov edx, [coff]
|
||||
movzx ebx, [edx+CFH.nSections]
|
||||
mov edi, 0
|
||||
lea eax, [edx+20]
|
||||
@@:
|
||||
add [eax+CFS.VirtualAddress], edi ;patch user space offset
|
||||
add eax, COFF_SECTION_SIZE
|
||||
dec ebx
|
||||
jnz @B
|
||||
|
||||
add edx, 20
|
||||
stdcall fix_coff_relocs, [coff], edx, [sym]
|
||||
|
||||
mov ebx, [coff]
|
||||
stdcall get_coff_sym, [sym], [ebx+CFH.nSymbols], szEXPORTS
|
||||
mov [exports], eax
|
||||
|
||||
stdcall kernel_free, [coff]
|
||||
|
||||
mov eax, [exports]
|
||||
ret
|
||||
.fail:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
proc dll.Load, import_table:dword
|
||||
mov esi, [import_table]
|
||||
.next_lib:
|
||||
mov edx, [esi]
|
||||
or edx, edx
|
||||
jz .exit
|
||||
push esi
|
||||
|
||||
mov edi, s_libname
|
||||
|
||||
mov al, '/'
|
||||
stosb
|
||||
mov esi, sysdir_path
|
||||
@@:
|
||||
lodsb
|
||||
stosb
|
||||
or al, al
|
||||
jnz @b
|
||||
dec edi
|
||||
mov [edi], dword '/lib'
|
||||
mov [edi+4], byte '/'
|
||||
add edi, 5
|
||||
pop esi
|
||||
push esi
|
||||
mov esi, [esi+4]
|
||||
@@:
|
||||
lodsb
|
||||
stosb
|
||||
or al, al
|
||||
jnz @b
|
||||
|
||||
pushad
|
||||
stdcall load_k_library, s_libname
|
||||
mov [esp+28], eax
|
||||
popad
|
||||
or eax, eax
|
||||
jz .fail
|
||||
stdcall dll.Link, eax, edx
|
||||
stdcall dll.Init, [eax+4]
|
||||
pop esi
|
||||
add esi, 8
|
||||
jmp .next_lib
|
||||
.exit:
|
||||
xor eax, eax
|
||||
ret
|
||||
.fail:
|
||||
add esp, 4
|
||||
xor eax, eax
|
||||
inc eax
|
||||
ret
|
||||
endp
|
||||
|
||||
proc dll.Link, exp:dword,imp:dword
|
||||
push eax
|
||||
mov esi, [imp]
|
||||
test esi, esi
|
||||
jz .done
|
||||
.next:
|
||||
lodsd
|
||||
test eax, eax
|
||||
jz .done
|
||||
stdcall dll.GetProcAddress, [exp], eax
|
||||
or eax, eax
|
||||
jz @f
|
||||
mov [esi-4], eax
|
||||
jmp .next
|
||||
@@:
|
||||
mov dword[esp], 0
|
||||
.done:
|
||||
pop eax
|
||||
ret
|
||||
endp
|
||||
|
||||
proc dll.Init, dllentry:dword
|
||||
pushad
|
||||
mov eax, mem.Alloc
|
||||
mov ebx, mem.Free
|
||||
mov ecx, mem.ReAlloc
|
||||
mov edx, dll.Load
|
||||
stdcall [dllentry]
|
||||
popad
|
||||
ret
|
||||
endp
|
||||
|
||||
proc dll.GetProcAddress, exp:dword,sz_name:dword
|
||||
mov edx, [exp]
|
||||
.next:
|
||||
test edx, edx
|
||||
jz .end
|
||||
stdcall strncmp, [edx], [sz_name], dword -1
|
||||
test eax, eax
|
||||
jz .ok
|
||||
add edx, 8
|
||||
jmp .next
|
||||
.ok:
|
||||
mov eax, [edx+4]
|
||||
.end:
|
||||
ret
|
||||
endp
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
proc mem.Alloc size ;/////////////////////////////////////////////////////////
|
||||
;-----------------------------------------------------------------------------
|
||||
push ebx ecx
|
||||
; mov eax,[size]
|
||||
; lea ecx,[eax+4+4095]
|
||||
; and ecx,not 4095
|
||||
; stdcall kernel_alloc, ecx
|
||||
; add ecx,-4
|
||||
; mov [eax],ecx
|
||||
; add eax,4
|
||||
|
||||
stdcall kernel_alloc, [size]
|
||||
|
||||
pop ecx ebx
|
||||
ret
|
||||
endp
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
proc mem.ReAlloc mptr,size;///////////////////////////////////////////////////
|
||||
;-----------------------------------------------------------------------------
|
||||
push ebx ecx esi edi eax
|
||||
mov eax, [mptr]
|
||||
mov ebx, [size]
|
||||
or eax, eax
|
||||
jz @f
|
||||
lea ecx, [ebx+4+4095]
|
||||
and ecx, not 4095
|
||||
add ecx, -4
|
||||
cmp ecx, [eax-4]
|
||||
je .exit
|
||||
@@:
|
||||
mov eax, ebx
|
||||
call mem.Alloc
|
||||
xchg eax, [esp]
|
||||
or eax, eax
|
||||
jz .exit
|
||||
mov esi, eax
|
||||
xchg eax, [esp]
|
||||
mov edi, eax
|
||||
mov ecx, [esi-4]
|
||||
cmp ecx, [edi-4]
|
||||
jbe @f
|
||||
mov ecx, [edi-4]
|
||||
@@:
|
||||
add ecx, 3
|
||||
shr ecx, 2
|
||||
cld
|
||||
rep movsd
|
||||
xchg eax, [esp]
|
||||
call mem.Free
|
||||
.exit:
|
||||
pop eax edi esi ecx ebx
|
||||
ret
|
||||
endp
|
||||
|
||||
;-----------------------------------------------------------------------------
|
||||
proc mem.Free mptr ;//////////////////////////////////////////////////////////
|
||||
;-----------------------------------------------------------------------------
|
||||
; mov eax,[mptr]
|
||||
; or eax,eax
|
||||
; jz @f
|
||||
; push ebx ecx
|
||||
; lea ecx,[eax-4]
|
||||
; stdcall kernel_free, ecx
|
||||
; pop ecx ebx
|
||||
; @@: ret
|
||||
stdcall kernel_free, [mptr]
|
||||
ret
|
||||
endp
|
||||
|
||||
proc load_file_parse_table
|
||||
stdcall kernel_alloc, 0x1000
|
||||
mov [tmp_file_name_table], eax
|
||||
mov edi, eax
|
||||
mov esi, sysdir_name
|
||||
mov ecx, 128/4
|
||||
rep movsd
|
||||
invoke ini.enum_keys, conf_fname, conf_path_sect, get_every_key
|
||||
mov eax, [tmp_file_name_table]
|
||||
mov [full_file_name_table], eax
|
||||
mov eax, [tmp_file_name_size]
|
||||
mov [full_file_name_table.size], eax
|
||||
ret
|
||||
endp
|
||||
|
||||
proc get_every_key stdcall, f_name, sec_name, key_name
|
||||
mov esi, [key_name]
|
||||
mov ecx, esi
|
||||
cmp byte [esi], '/'
|
||||
jnz @f
|
||||
inc esi
|
||||
@@:
|
||||
mov edi, [tmp_file_name_size]
|
||||
shl edi, 7
|
||||
cmp edi, 0x1000
|
||||
jae .stop_parse
|
||||
add edi, [tmp_file_name_table]
|
||||
lea ebx, [edi+64]
|
||||
@@:
|
||||
cmp edi, ebx
|
||||
jae .skip_this_key
|
||||
lodsb
|
||||
test al, al
|
||||
jz @f
|
||||
or al, 20h
|
||||
stosb
|
||||
jmp @b
|
||||
|
||||
.stop_parse:
|
||||
xor eax, eax
|
||||
ret
|
||||
|
||||
@@:
|
||||
stosb
|
||||
invoke ini.get_str, [f_name], [sec_name], ecx, ebx, 64, def_val_1
|
||||
cmp byte [ebx], '/'
|
||||
jnz @f
|
||||
lea esi, [ebx+1]
|
||||
mov edi, ebx
|
||||
mov ecx, 63
|
||||
rep movsb
|
||||
@@:
|
||||
push ebp
|
||||
mov ebp, [tmp_file_name_table]
|
||||
mov ecx, [tmp_file_name_size]
|
||||
jecxz .noreplace
|
||||
mov eax, ecx
|
||||
dec eax
|
||||
shl eax, 7
|
||||
add ebp, eax
|
||||
.replace_loop:
|
||||
mov edi, ebx
|
||||
mov esi, ebp
|
||||
@@:
|
||||
lodsb
|
||||
test al, al
|
||||
jz .doreplace
|
||||
mov dl, [edi]
|
||||
inc edi
|
||||
test dl, dl
|
||||
jz .replace_loop_cont
|
||||
or dl, 20h
|
||||
cmp al, dl
|
||||
jz @b
|
||||
jmp .replace_loop_cont
|
||||
|
||||
.doreplace:
|
||||
cmp byte [edi], 0
|
||||
jz @f
|
||||
cmp byte [edi], '/'
|
||||
jnz .replace_loop_cont
|
||||
@@:
|
||||
lea esi, [ebp+64]
|
||||
call .replace
|
||||
jc .skip_this_key2
|
||||
.replace_loop_cont:
|
||||
sub ebp, 128
|
||||
loop .replace_loop
|
||||
.noreplace:
|
||||
pop ebp
|
||||
inc [tmp_file_name_size]
|
||||
.skip_this_key:
|
||||
xor eax, eax
|
||||
inc eax
|
||||
ret
|
||||
|
||||
.skip_this_key2:
|
||||
pop ebp
|
||||
jmp .skip_this_key
|
||||
endp
|
||||
|
||||
proc get_every_key.replace
|
||||
; in: ebx->destination, esi->first part of name, edi->second part of name
|
||||
; maximum length is 64 bytes
|
||||
; out: CF=1 <=> overflow
|
||||
sub esp, 64 ; allocate temporary buffer in stack
|
||||
push esi
|
||||
lea esi, [esp+4] ; esi->tmp buffer
|
||||
xchg esi, edi ; edi->tmp buffer, esi->source
|
||||
@@: ; save second part of name to temporary buffer
|
||||
lodsb
|
||||
stosb
|
||||
test al, al
|
||||
jnz @b
|
||||
pop esi
|
||||
mov edi, ebx
|
||||
@@: ; copy first part of name to destination
|
||||
lodsb
|
||||
test al, al
|
||||
jz @f
|
||||
stosb
|
||||
jmp @b
|
||||
|
||||
@@: ; restore second part of name from temporary buffer to destination
|
||||
lea edx, [ebx+64] ; limit of destination
|
||||
mov esi, esp
|
||||
@@:
|
||||
cmp edi, edx
|
||||
jae .overflow
|
||||
lodsb
|
||||
stosb
|
||||
test al, al
|
||||
jnz @b
|
||||
add esp, 64 ; CF is cleared
|
||||
ret
|
||||
|
||||
.overflow: ; name is too long
|
||||
add esp, 64
|
||||
stc
|
||||
ret
|
||||
endp
|
||||
end if
|
||||
419
kernel/branches/kolibri-lldw/core/fpu.inc
Normal file
419
kernel/branches/kolibri-lldw/core/fpu.inc
Normal file
@@ -0,0 +1,419 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
init_fpu:
|
||||
clts
|
||||
fninit
|
||||
|
||||
bt [cpu_caps+(CAPS_XSAVE/32)*4], CAPS_XSAVE mod 32
|
||||
jnc .no_xsave
|
||||
|
||||
mov ecx, cr4
|
||||
or ecx, CR4_OSXSAVE
|
||||
mov cr4, ecx
|
||||
; don't call cpuid again
|
||||
bts [cpu_caps+(CAPS_OSXSAVE/32)*4], CAPS_OSXSAVE mod 32
|
||||
|
||||
; zero xsave header
|
||||
mov ecx, 64/4
|
||||
xor eax, eax
|
||||
mov edi, fpu_data + 512 ; skip legacy region
|
||||
rep stosd
|
||||
|
||||
mov eax, 0x0d ; extended state enumeration main leaf
|
||||
xor ecx, ecx
|
||||
cpuid
|
||||
and eax, XCR0_FPU_MMX + XCR0_SSE + XCR0_AVX + XCR0_AVX512
|
||||
xor edx, edx
|
||||
mov [xsave_eax], eax
|
||||
mov [xsave_edx], edx
|
||||
xor ecx, ecx
|
||||
xsetbv
|
||||
|
||||
mov eax, 0x0d
|
||||
xor ecx, ecx
|
||||
cpuid
|
||||
add ebx, 63
|
||||
and ebx, NOT 63
|
||||
mov [xsave_area_size], ebx
|
||||
cmp ebx, fpu_data_size
|
||||
ja $
|
||||
|
||||
test eax, XCR0_AVX512
|
||||
jz @f
|
||||
call init_avx512
|
||||
mov eax, [xsave_eax]
|
||||
mov edx, [xsave_edx]
|
||||
xsave [fpu_data]
|
||||
ret
|
||||
@@:
|
||||
test eax, XCR0_AVX
|
||||
jz @f
|
||||
call init_avx
|
||||
mov eax, [xsave_eax]
|
||||
mov edx, [xsave_edx]
|
||||
xsave [fpu_data]
|
||||
ret
|
||||
@@:
|
||||
test eax, XCR0_SSE
|
||||
jz $
|
||||
call init_sse
|
||||
mov eax, [xsave_eax]
|
||||
mov edx, [xsave_edx]
|
||||
xsave [fpu_data]
|
||||
ret
|
||||
.no_xsave:
|
||||
mov [xsave_area_size], 512 ; enough for FPU/MMX and SSE
|
||||
bt [cpu_caps], CAPS_SSE
|
||||
jnc .fpu_mmx
|
||||
.sse:
|
||||
call init_sse
|
||||
fxsave [fpu_data]
|
||||
ret
|
||||
.fpu_mmx:
|
||||
call init_fpu_mmx
|
||||
fnsave [fpu_data]
|
||||
ret
|
||||
|
||||
init_fpu_mmx:
|
||||
mov ecx, cr0
|
||||
and ecx, not CR0_EM
|
||||
or ecx, CR0_MP + CR0_NE
|
||||
mov cr0, ecx
|
||||
ret
|
||||
|
||||
init_sse:
|
||||
mov ebx, cr4
|
||||
mov ecx, cr0
|
||||
or ebx, CR4_OSFXSR + CR4_OSXMMEXPT
|
||||
mov cr4, ebx
|
||||
|
||||
and ecx, not (CR0_EM + CR0_MP)
|
||||
or ecx, CR0_NE
|
||||
mov cr0, ecx
|
||||
|
||||
mov dword [esp-4], MXCSR_INIT
|
||||
ldmxcsr [esp-4]
|
||||
|
||||
xorps xmm0, xmm0
|
||||
xorps xmm1, xmm1
|
||||
xorps xmm2, xmm2
|
||||
xorps xmm3, xmm3
|
||||
xorps xmm4, xmm4
|
||||
xorps xmm5, xmm5
|
||||
xorps xmm6, xmm6
|
||||
xorps xmm7, xmm7
|
||||
ret
|
||||
|
||||
init_avx:
|
||||
mov ebx, cr4
|
||||
or ebx, CR4_OSFXSR + CR4_OSXMMEXPT
|
||||
mov cr4, ebx
|
||||
|
||||
mov ecx, cr0
|
||||
and ecx, not (CR0_EM + CR0_MP)
|
||||
or ecx, CR0_NE
|
||||
mov cr0, ecx
|
||||
|
||||
mov dword [esp-4], MXCSR_INIT
|
||||
vldmxcsr [esp-4]
|
||||
|
||||
vzeroall
|
||||
ret
|
||||
|
||||
init_avx512:
|
||||
mov ebx, cr4
|
||||
or ebx, CR4_OSFXSR + CR4_OSXMMEXPT
|
||||
mov cr4, ebx
|
||||
|
||||
mov ecx, cr0
|
||||
and ecx, not (CR0_EM + CR0_MP)
|
||||
or ecx, CR0_NE
|
||||
mov cr0, ecx
|
||||
|
||||
mov dword [esp-4], MXCSR_INIT
|
||||
vldmxcsr [esp-4]
|
||||
|
||||
vpxorq zmm0, zmm0, zmm0
|
||||
vpxorq zmm1, zmm1, zmm1
|
||||
vpxorq zmm2, zmm2, zmm2
|
||||
vpxorq zmm3, zmm3, zmm3
|
||||
vpxorq zmm4, zmm4, zmm4
|
||||
vpxorq zmm5, zmm5, zmm5
|
||||
vpxorq zmm6, zmm6, zmm6
|
||||
vpxorq zmm7, zmm7, zmm7
|
||||
|
||||
ret
|
||||
|
||||
; param
|
||||
; eax= 512 bytes memory area aligned on a 16-byte boundary
|
||||
|
||||
align 4
|
||||
fpu_save:
|
||||
push ecx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
pushfd
|
||||
cli
|
||||
|
||||
clts
|
||||
mov edi, eax
|
||||
|
||||
mov ecx, [fpu_owner]
|
||||
mov esi, [current_slot_idx]
|
||||
cmp ecx, esi
|
||||
jne .save
|
||||
|
||||
call save_fpu_context
|
||||
jmp .exit
|
||||
.save:
|
||||
mov [fpu_owner], esi
|
||||
|
||||
shl ecx, 8
|
||||
mov eax, [ecx+SLOT_BASE+APPDATA.fpu_state]
|
||||
|
||||
call save_context
|
||||
|
||||
; first 512 bytes of XSAVE area have the same format as FXSAVE
|
||||
shl esi, 8
|
||||
mov esi, [esi+SLOT_BASE+APPDATA.fpu_state]
|
||||
mov ecx, 512/4
|
||||
cld
|
||||
rep movsd
|
||||
fninit
|
||||
.exit:
|
||||
popfd
|
||||
pop edi
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
avx_save_size:
|
||||
mov eax, [xsave_area_size]
|
||||
ret
|
||||
|
||||
; param
|
||||
; eax= avx_save_size() bytes memory area aligned on a 64-byte boundary
|
||||
|
||||
align 4
|
||||
avx_save:
|
||||
push ecx
|
||||
push esi
|
||||
push edi
|
||||
|
||||
pushfd
|
||||
cli
|
||||
|
||||
clts
|
||||
mov edi, eax
|
||||
|
||||
mov ecx, [fpu_owner]
|
||||
mov esi, [current_slot_idx]
|
||||
cmp ecx, esi
|
||||
jne .save
|
||||
|
||||
call save_context
|
||||
jmp .exit
|
||||
.save:
|
||||
mov [fpu_owner], esi
|
||||
|
||||
shl ecx, 8
|
||||
mov eax, [ecx+SLOT_BASE+APPDATA.fpu_state]
|
||||
|
||||
call save_context
|
||||
|
||||
shl esi, 8
|
||||
mov esi, [esi+SLOT_BASE+APPDATA.fpu_state]
|
||||
mov ecx, [xsave_area_size]
|
||||
add ecx, 3
|
||||
shr ecx, 2
|
||||
rep movsd
|
||||
fninit
|
||||
.exit:
|
||||
popfd
|
||||
pop edi
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
align 4
|
||||
save_context:
|
||||
bt [cpu_caps+(CAPS_OSXSAVE/32)*4], CAPS_OSXSAVE mod 32
|
||||
jnc save_fpu_context
|
||||
push eax edx
|
||||
mov ecx, eax
|
||||
mov eax, [xsave_eax]
|
||||
mov edx, [xsave_edx]
|
||||
xsave [ecx]
|
||||
pop edx eax
|
||||
ret
|
||||
save_fpu_context:
|
||||
bt [cpu_caps], CAPS_SSE
|
||||
jnc .no_SSE
|
||||
fxsave [eax]
|
||||
ret
|
||||
.no_SSE:
|
||||
fnsave [eax]
|
||||
ret
|
||||
|
||||
|
||||
align 4
|
||||
fpu_restore:
|
||||
push ecx
|
||||
push esi
|
||||
|
||||
mov esi, eax
|
||||
|
||||
pushfd
|
||||
cli
|
||||
|
||||
mov ecx, [fpu_owner]
|
||||
mov eax, [current_slot_idx]
|
||||
cmp ecx, eax
|
||||
jne .copy
|
||||
|
||||
clts
|
||||
bt [cpu_caps], CAPS_SSE
|
||||
jnc .no_SSE
|
||||
|
||||
fxrstor [esi]
|
||||
popfd
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
.no_SSE:
|
||||
fnclex ;fix possible problems
|
||||
frstor [esi]
|
||||
popfd
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
.copy:
|
||||
shl eax, 8
|
||||
mov edi, [eax+SLOT_BASE+APPDATA.fpu_state]
|
||||
mov ecx, 512/4
|
||||
cld
|
||||
rep movsd
|
||||
popfd
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
align 4
|
||||
avx_restore:
|
||||
push ecx
|
||||
push esi
|
||||
|
||||
mov esi, eax
|
||||
|
||||
pushfd
|
||||
cli
|
||||
|
||||
mov ecx, [fpu_owner]
|
||||
mov eax, [current_slot_idx]
|
||||
cmp ecx, eax
|
||||
jne .copy
|
||||
|
||||
clts
|
||||
bt [cpu_caps+(CAPS_OSXSAVE/32)*4], CAPS_OSXSAVE mod 32
|
||||
jnc .no_xsave
|
||||
push edx
|
||||
mov eax, [xsave_eax]
|
||||
mov edx, [xsave_edx]
|
||||
xrstor [esi]
|
||||
pop edx
|
||||
popfd
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
.no_xsave:
|
||||
bt [cpu_caps], CAPS_SSE
|
||||
jnc .no_SSE
|
||||
|
||||
fxrstor [esi]
|
||||
popfd
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
.no_SSE:
|
||||
fnclex ;fix possible problems
|
||||
frstor [esi]
|
||||
popfd
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
.copy:
|
||||
shl eax, 8
|
||||
mov edi, [eax+SLOT_BASE+APPDATA.fpu_state]
|
||||
mov ecx, [xsave_area_size]
|
||||
add ecx, 3
|
||||
shr ecx, 2
|
||||
cld
|
||||
rep movsd
|
||||
popfd
|
||||
pop esi
|
||||
pop ecx
|
||||
ret
|
||||
|
||||
align 4
|
||||
except_7: ;#NM exception handler
|
||||
save_ring3_context
|
||||
clts
|
||||
mov ax, app_data;
|
||||
mov ds, ax
|
||||
mov es, ax
|
||||
|
||||
mov ebx, [fpu_owner]
|
||||
cmp ebx, [current_slot_idx]
|
||||
je .exit
|
||||
|
||||
shl ebx, 8
|
||||
mov eax, [ebx+SLOT_BASE+APPDATA.fpu_state]
|
||||
bt [cpu_caps+(CAPS_OSXSAVE/32)*4], CAPS_OSXSAVE mod 32
|
||||
jnc .no_xsave
|
||||
mov ecx, eax
|
||||
mov eax, [xsave_eax]
|
||||
mov edx, [xsave_edx]
|
||||
xsave [ecx]
|
||||
mov ebx, [current_slot_idx]
|
||||
mov [fpu_owner], ebx
|
||||
shl ebx, 8
|
||||
mov ecx, [ebx+SLOT_BASE+APPDATA.fpu_state]
|
||||
xrstor [ecx]
|
||||
.exit:
|
||||
restore_ring3_context
|
||||
iret
|
||||
.no_xsave:
|
||||
bt [cpu_caps], CAPS_SSE
|
||||
jnc .no_SSE
|
||||
|
||||
fxsave [eax]
|
||||
mov ebx, [current_slot_idx]
|
||||
mov [fpu_owner], ebx
|
||||
shl ebx, 8
|
||||
mov eax, [ebx+SLOT_BASE+APPDATA.fpu_state]
|
||||
fxrstor [eax]
|
||||
restore_ring3_context
|
||||
iret
|
||||
|
||||
.no_SSE:
|
||||
fnsave [eax]
|
||||
mov ebx, [current_slot_idx]
|
||||
mov [fpu_owner], ebx
|
||||
shl ebx, 8
|
||||
mov eax, [ebx+SLOT_BASE+APPDATA.fpu_state]
|
||||
frstor [eax]
|
||||
restore_ring3_context
|
||||
iret
|
||||
|
||||
iglobal
|
||||
fpu_owner dd 2
|
||||
endg
|
||||
1589
kernel/branches/kolibri-lldw/core/heap.inc
Normal file
1589
kernel/branches/kolibri-lldw/core/heap.inc
Normal file
File diff suppressed because it is too large
Load Diff
74
kernel/branches/kolibri-lldw/core/hpet.inc
Normal file
74
kernel/branches/kolibri-lldw/core/hpet.inc
Normal file
@@ -0,0 +1,74 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
HPET_ID = 0x0000
|
||||
HPET_PERIOD = 0x0004
|
||||
HPET_CFG_ENABLE = 0x0001
|
||||
HPET_CFG = 0x0010
|
||||
HPET_COUNTER = 0x00f0
|
||||
HPET_T0_CFG = 0x0100
|
||||
|
||||
HPET_TN_LEVEL = 0x0002
|
||||
HPET_TN_ENABLE = 0x0004
|
||||
HPET_TN_FSB = 0x4000
|
||||
|
||||
uglobal
|
||||
hpet_base rd 1
|
||||
hpet_period rd 1
|
||||
hpet_timers rd 1
|
||||
hpet_tsc_start rd 2
|
||||
endg
|
||||
|
||||
align 4
|
||||
init_hpet:
|
||||
mov ebx, [hpet_base]
|
||||
test ebx, ebx
|
||||
jz .done
|
||||
|
||||
mov eax, [ebx]
|
||||
and ah, 0x1F
|
||||
inc ah
|
||||
movzx eax, ah
|
||||
mov [hpet_timers], eax
|
||||
mov ecx, eax
|
||||
|
||||
mov eax, [ebx+HPET_PERIOD]
|
||||
xor edx, edx
|
||||
shld edx, eax, 10
|
||||
shl eax, 10
|
||||
mov esi, 1000000
|
||||
div esi
|
||||
mov [hpet_period], eax
|
||||
|
||||
mov esi, [ebx+HPET_CFG]
|
||||
and esi, not HPET_CFG_ENABLE
|
||||
mov [ebx+HPET_CFG], esi ;stop main counter
|
||||
|
||||
lea edx, [ebx+HPET_T0_CFG]
|
||||
@@:
|
||||
jcxz @F
|
||||
mov eax, [edx]
|
||||
and eax, not (HPET_TN_ENABLE+HPET_TN_LEVEL+HPET_TN_FSB)
|
||||
mov [edx], eax
|
||||
add edx, 0x20
|
||||
dec ecx
|
||||
jmp @B
|
||||
@@:
|
||||
mov [ebx+HPET_COUNTER], ecx ;reset main counter
|
||||
mov [ebx+HPET_COUNTER+4], ecx
|
||||
|
||||
or esi, HPET_CFG_ENABLE
|
||||
mov [ebx+HPET_CFG], esi ;and start again
|
||||
|
||||
.done:
|
||||
rdtsc
|
||||
mov [hpet_tsc_start], eax
|
||||
mov [hpet_tsc_start+4], edx
|
||||
|
||||
ret
|
||||
294
kernel/branches/kolibri-lldw/core/irq.inc
Normal file
294
kernel/branches/kolibri-lldw/core/irq.inc
Normal file
@@ -0,0 +1,294 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
|
||||
IRQ_RESERVED = 56
|
||||
|
||||
IRQ_POOL_SIZE = 48
|
||||
|
||||
uglobal
|
||||
|
||||
align 16
|
||||
irqh_tab rd sizeof.LHEAD * IRQ_RESERVED / 4
|
||||
|
||||
irqh_pool rd sizeof.IRQH * IRQ_POOL_SIZE /4
|
||||
next_irqh rd 1
|
||||
|
||||
irq_active_set rd (IRQ_RESERVED+31)/32
|
||||
irq_failed rd IRQ_RESERVED
|
||||
|
||||
endg
|
||||
|
||||
set_irq_active:
|
||||
mov eax, ebp
|
||||
mov ecx, ebp
|
||||
shr ecx, 5
|
||||
and eax, 31
|
||||
bts [irq_active_set+ecx*4], eax
|
||||
ret
|
||||
|
||||
reset_irq_active:
|
||||
mov eax, ebp
|
||||
mov ecx, ebp
|
||||
shr ecx, 5
|
||||
and eax, 31
|
||||
btr [irq_active_set+ecx*4], eax
|
||||
ret
|
||||
|
||||
align 4
|
||||
init_irqs:
|
||||
|
||||
mov ecx, IRQ_RESERVED
|
||||
mov edi, irqh_tab
|
||||
@@:
|
||||
mov eax, edi
|
||||
stosd
|
||||
stosd
|
||||
loop @B
|
||||
|
||||
mov ecx, IRQ_POOL_SIZE-1
|
||||
mov eax, irqh_pool+sizeof.IRQH
|
||||
mov [next_irqh], irqh_pool
|
||||
@@:
|
||||
mov [eax-sizeof.IRQH], eax
|
||||
add eax, sizeof.IRQH
|
||||
loop @B
|
||||
|
||||
mov [eax-sizeof.IRQH], dword 0
|
||||
ret
|
||||
|
||||
|
||||
align 4
|
||||
proc attach_int_handler stdcall, irq:dword, handler:dword, user_data:dword
|
||||
locals
|
||||
.irqh dd ?
|
||||
endl
|
||||
|
||||
DEBUGF 1, "K : Attach Interrupt %d Handler %x\n", [irq], [handler]
|
||||
|
||||
and [.irqh], 0
|
||||
|
||||
push ebx
|
||||
|
||||
mov ebx, [irq] ;irq num
|
||||
test ebx, ebx
|
||||
jz .err
|
||||
|
||||
cmp ebx, IRQ_RESERVED
|
||||
jae .err
|
||||
|
||||
mov edx, [handler]
|
||||
test edx, edx
|
||||
jz .err
|
||||
|
||||
spin_lock_irqsave IrqsList
|
||||
|
||||
;allocate handler
|
||||
|
||||
mov ecx, [next_irqh]
|
||||
test ecx, ecx
|
||||
jz .fail
|
||||
|
||||
mov eax, [ecx]
|
||||
mov [next_irqh], eax
|
||||
mov [.irqh], ecx
|
||||
|
||||
mov [irq_failed+ebx*4], 0;clear counter
|
||||
|
||||
mov eax, [user_data]
|
||||
mov [ecx+IRQH.handler], edx
|
||||
mov [ecx+IRQH.data], eax
|
||||
and [ecx+IRQH.num_ints], 0
|
||||
|
||||
lea edx, [irqh_tab+ebx*8]
|
||||
list_add_tail ecx, edx ;clobber eax
|
||||
stdcall enable_irq, ebx
|
||||
|
||||
.fail:
|
||||
spin_unlock_irqrestore IrqsList
|
||||
.err:
|
||||
pop ebx
|
||||
mov eax, [.irqh]
|
||||
ret
|
||||
|
||||
endp
|
||||
|
||||
if 0
|
||||
align 4
|
||||
proc get_int_handler stdcall, irq:dword
|
||||
|
||||
mov eax, [irq]
|
||||
cmp eax, 15
|
||||
ja .fail
|
||||
mov eax, [irq_tab + 4 * eax]
|
||||
ret
|
||||
.fail:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
end if
|
||||
|
||||
|
||||
align 4
|
||||
proc detach_int_handler
|
||||
|
||||
ret
|
||||
endp
|
||||
|
||||
|
||||
macro irq_serv_h [num] {
|
||||
forward
|
||||
align 4
|
||||
.irq_#num :
|
||||
push num
|
||||
jmp .main
|
||||
}
|
||||
|
||||
align 16
|
||||
irq_serv:
|
||||
|
||||
rept 12 irqn:1 {irq_serv_h irqn} ; 1--12
|
||||
rept 18 irqn:14 {irq_serv_h irqn} ; 14--31 (irq32 is vector 0x40)
|
||||
rept 23 irqn:33 {irq_serv_h irqn} ; 33--55
|
||||
|
||||
purge irq_serv_h
|
||||
|
||||
align 16
|
||||
.main:
|
||||
save_ring3_context
|
||||
mov ebp, [esp + 32]
|
||||
mov bx, app_data;os_data
|
||||
mov ds, bx
|
||||
mov es, bx
|
||||
|
||||
cmp [v86_irqhooks+ebp*8], 0
|
||||
jnz v86_irq
|
||||
|
||||
call set_irq_active
|
||||
|
||||
lea esi, [irqh_tab+ebp*8] ; esi= list head
|
||||
mov ebx, esi
|
||||
.next:
|
||||
mov ebx, [ebx+IRQH.list.next]; ebx= irqh pointer
|
||||
cmp ebx, esi
|
||||
je .done
|
||||
|
||||
push ebx ; FIX THIS
|
||||
push edi
|
||||
push esi
|
||||
|
||||
push [ebx+IRQH.data]
|
||||
call [ebx+IRQH.handler]
|
||||
pop ecx
|
||||
|
||||
pop esi
|
||||
pop edi
|
||||
pop ebx
|
||||
|
||||
test eax, eax
|
||||
jz .next
|
||||
|
||||
inc [ebx+IRQH.num_ints]
|
||||
call reset_irq_active
|
||||
jmp .next
|
||||
|
||||
.done:
|
||||
call reset_irq_active
|
||||
jnc .exit
|
||||
|
||||
; There is at least one configuration with one device which generates IRQ
|
||||
; that is not the same as it should be according to PCI config space.
|
||||
; For that device, the handler is registered at wrong IRQ.
|
||||
; As a workaround, when nobody acknowledges the generated IRQ,
|
||||
; try to ask all other registered handlers; if some handler acknowledges
|
||||
; the IRQ this time, relink it to the current IRQ list.
|
||||
; To make this more reliable, for every handler keep number of times
|
||||
; that it has acknowledged an IRQ, and assume that handlers with at least one
|
||||
; acknowledged IRQ are registered properly.
|
||||
; Note: this still isn't 100% correct, because two IRQs can fire simultaneously,
|
||||
; the better way would be to find the correct IRQ, but I don't know how to do
|
||||
; this in that case.
|
||||
cmp ebp, 1
|
||||
jz .fail
|
||||
push ebp
|
||||
xor ebp, ebp
|
||||
.try_other_irqs:
|
||||
cmp ebp, [esp]
|
||||
jz .try_next_irq
|
||||
cmp ebp, 1
|
||||
jz .try_next_irq
|
||||
cmp ebp, 6
|
||||
jz .try_next_irq
|
||||
cmp ebp, 12
|
||||
jz .try_next_irq
|
||||
cmp ebp, 14
|
||||
jz .try_next_irq
|
||||
cmp ebp, 15
|
||||
jz .try_next_irq
|
||||
lea esi, [irqh_tab+ebp*8]
|
||||
mov ebx, esi
|
||||
.try_next_handler:
|
||||
mov ebx, [ebx+IRQH.list.next]
|
||||
cmp ebx, esi
|
||||
je .try_next_irq
|
||||
cmp [ebx+IRQH.num_ints], 0
|
||||
jne .try_next_handler
|
||||
; keyboard handler acknowledges everything
|
||||
push [ebx+IRQH.data]
|
||||
call [ebx+IRQH.handler]
|
||||
pop ecx
|
||||
test eax, eax
|
||||
jz .try_next_handler
|
||||
|
||||
.found_in_wrong_list:
|
||||
DEBUGF 1,'K : warning: relinking handler from IRQ%d to IRQ%d\n',\
|
||||
ebp, [esp]
|
||||
pop ebp
|
||||
spin_lock_irqsave IrqsList
|
||||
list_del ebx
|
||||
lea edx, [irqh_tab+ebp*8]
|
||||
list_add_tail ebx, edx
|
||||
spin_unlock_irqrestore IrqsList
|
||||
jmp .exit
|
||||
|
||||
.try_next_irq:
|
||||
inc ebp
|
||||
cmp ebp, 16
|
||||
jb .try_other_irqs
|
||||
pop ebp
|
||||
|
||||
.fail:
|
||||
inc [irq_failed+ebp*4]
|
||||
.exit:
|
||||
|
||||
mov ecx, ebp
|
||||
call irq_eoi
|
||||
|
||||
; IRQ handler could make some kernel thread ready; reschedule
|
||||
mov bl, SCHEDULE_HIGHER_PRIORITY
|
||||
call find_next_task
|
||||
jz .return ; if there is only one running process
|
||||
call do_change_task
|
||||
.return:
|
||||
restore_ring3_context
|
||||
add esp, 4
|
||||
iret
|
||||
|
||||
align 4
|
||||
irqD:
|
||||
push eax
|
||||
push ecx
|
||||
xor eax, eax
|
||||
out 0xf0, al
|
||||
mov cl, 13
|
||||
call irq_eoi
|
||||
pop ecx
|
||||
pop eax
|
||||
iret
|
||||
|
||||
1035
kernel/branches/kolibri-lldw/core/malloc.inc
Normal file
1035
kernel/branches/kolibri-lldw/core/malloc.inc
Normal file
File diff suppressed because it is too large
Load Diff
1364
kernel/branches/kolibri-lldw/core/memory.inc
Normal file
1364
kernel/branches/kolibri-lldw/core/memory.inc
Normal file
File diff suppressed because it is too large
Load Diff
931
kernel/branches/kolibri-lldw/core/mtrr.inc
Normal file
931
kernel/branches/kolibri-lldw/core/mtrr.inc
Normal file
@@ -0,0 +1,931 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
; Initializes MTRRs.
|
||||
proc init_mtrr
|
||||
|
||||
cmp [BOOT.mtrr], byte 2
|
||||
je .exit
|
||||
|
||||
bt [cpu_caps], CAPS_MTRR
|
||||
jnc .exit
|
||||
|
||||
call mtrr_reconfigure
|
||||
stdcall set_mtrr, [LFBAddress], 0x1000000, MEM_WC
|
||||
|
||||
.exit:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Helper procedure for mtrr_reconfigure and set_mtrr,
|
||||
; called before changes in MTRRs.
|
||||
; 1. disable and flush caches
|
||||
; 2. clear PGE bit in cr4
|
||||
; 3. flush TLB
|
||||
; 4. disable mtrr
|
||||
|
||||
proc mtrr_begin_change
|
||||
mov eax, cr0
|
||||
or eax, 0x60000000 ;disable caching
|
||||
mov cr0, eax
|
||||
wbinvd ;invalidate cache
|
||||
|
||||
bt [cpu_caps], CAPS_PGE
|
||||
jnc .cr3_flush
|
||||
|
||||
mov eax, cr4
|
||||
btr eax, 7 ;clear cr4.PGE
|
||||
mov cr4, eax ;flush TLB
|
||||
jmp @F ;skip extra serialization
|
||||
|
||||
.cr3_flush:
|
||||
mov eax, cr3
|
||||
mov cr3, eax ;flush TLB
|
||||
@@:
|
||||
mov ecx, MSR_MTRR_DEF_TYPE
|
||||
rdmsr
|
||||
btr eax, 11 ;clear enable flag
|
||||
wrmsr ;disable mtrr
|
||||
ret
|
||||
endp
|
||||
|
||||
; Helper procedure for mtrr_reconfigure and set_mtrr,
|
||||
; called after changes in MTRRs.
|
||||
; 1. enable mtrr
|
||||
; 2. flush all caches
|
||||
; 3. flush TLB
|
||||
; 4. restore cr4.PGE flag, if required
|
||||
|
||||
proc mtrr_end_change
|
||||
mov ecx, MSR_MTRR_DEF_TYPE
|
||||
rdmsr
|
||||
or ah, 8 ; enable variable-ranges MTRR
|
||||
and al, 0xF0 ; default memtype = UC
|
||||
wrmsr
|
||||
|
||||
wbinvd ;again invalidate
|
||||
mov eax, cr0
|
||||
and eax, not 0x60000000
|
||||
mov cr0, eax ; enable caching
|
||||
|
||||
mov eax, cr3
|
||||
mov cr3, eax ;flush tlb
|
||||
|
||||
bt [cpu_caps], CAPS_PGE
|
||||
jnc @F
|
||||
|
||||
mov eax, cr4
|
||||
bts eax, 7 ;set cr4.PGE flag
|
||||
mov cr4, eax
|
||||
@@:
|
||||
ret
|
||||
endp
|
||||
|
||||
; Some limits to number of structures located in the stack.
|
||||
MAX_USEFUL_MTRRS = 16
|
||||
MAX_RANGES = 16
|
||||
|
||||
; mtrr_reconfigure keeps a list of MEM_WB ranges.
|
||||
; This structure describes one item in the list.
|
||||
struct mtrr_range
|
||||
next dd ? ; next item
|
||||
start dq ? ; first byte
|
||||
length dq ? ; length in bytes
|
||||
ends
|
||||
|
||||
uglobal
|
||||
align 4
|
||||
num_variable_mtrrs dd 0 ; number of variable-range MTRRs
|
||||
endg
|
||||
|
||||
; Helper procedure for MTRR initialization.
|
||||
; Takes MTRR configured by BIOS and tries to recongifure them
|
||||
; in order to allow non-UC data at top of 4G memory.
|
||||
; Example: if low part of physical memory is 3.5G = 0xE0000000 bytes wide,
|
||||
; BIOS can configure two MTRRs so that the first MTRR describes [0, 4G) as WB
|
||||
; and the second MTRR describes [3.5G, 4G) as UC;
|
||||
; WB+UC=UC, so the resulting memory map would be as needed,
|
||||
; but in this configuration our attempts to map LFB at (say) 0xE8000000 as WC
|
||||
; would be ignored, WB+UC+WC is still UC.
|
||||
; So we must keep top of 4G memory not covered by MTRRs,
|
||||
; using three WB MTRRs [0,2G) + [2G,3G) + [3G,3.5G),
|
||||
; this gives the same memory map, but allows to add further entries.
|
||||
; See mtrrtest.asm for detailed input/output from real hardware+BIOS.
|
||||
proc mtrr_reconfigure
|
||||
push ebp ; we're called from init_LFB, and it feels hurt when ebp is destroyed
|
||||
; 1. Prepare local variables.
|
||||
; 1a. Create list of MAX_RANGES free (aka not yet allocated) ranges.
|
||||
xor eax, eax
|
||||
lea ecx, [eax+MAX_RANGES]
|
||||
.init_ranges:
|
||||
sub esp, sizeof.mtrr_range - 4
|
||||
push eax
|
||||
mov eax, esp
|
||||
dec ecx
|
||||
jnz .init_ranges
|
||||
mov eax, esp
|
||||
; 1b. Fill individual local variables.
|
||||
xor edx, edx
|
||||
sub esp, MAX_USEFUL_MTRRS * 16 ; .mtrrs
|
||||
push edx ; .mtrrs_end
|
||||
push edx ; .num_used_mtrrs
|
||||
push eax ; .first_free_range
|
||||
push edx ; .first_range: no ranges yet
|
||||
mov cl, [cpu_phys_addr_width]
|
||||
or eax, -1
|
||||
shl eax, cl ; note: this uses cl&31 = cl-32, not the entire cl
|
||||
push eax ; .phys_reserved_mask
|
||||
virtual at esp
|
||||
.phys_reserved_mask dd ?
|
||||
.first_range dd ?
|
||||
.first_free_range dd ?
|
||||
.num_used_mtrrs dd ?
|
||||
.mtrrs_end dd ?
|
||||
.mtrrs rq MAX_USEFUL_MTRRS * 2
|
||||
.local_vars_size = $ - esp
|
||||
end virtual
|
||||
|
||||
; 2. Get the number of variable-range MTRRs from MTRRCAP register.
|
||||
; Abort if zero.
|
||||
mov ecx, 0xFE
|
||||
rdmsr
|
||||
test al, al
|
||||
jz .abort
|
||||
mov byte [num_variable_mtrrs], al
|
||||
; 3. Validate MTRR_DEF_TYPE register.
|
||||
mov ecx, 0x2FF
|
||||
rdmsr
|
||||
; If BIOS has not initialized variable-range MTRRs, fallback to step 7.
|
||||
test ah, 8
|
||||
jz .fill_ranges_from_memory_map
|
||||
; If the default memory type (not covered by MTRRs) is not UC,
|
||||
; then probably BIOS did something strange, so it is better to exit immediately
|
||||
; hoping for the best.
|
||||
cmp al, MEM_UC
|
||||
jnz .abort
|
||||
; 4. Validate all variable-range MTRRs
|
||||
; and copy configured MTRRs to the local array [.mtrrs].
|
||||
; 4a. Prepare for the loop over existing variable-range MTRRs.
|
||||
mov ecx, 0x200
|
||||
lea edi, [.mtrrs]
|
||||
.get_used_mtrrs_loop:
|
||||
; 4b. For every MTRR, read PHYSBASEn and PHYSMASKn.
|
||||
; In PHYSBASEn, clear upper bits and copy to ebp:ebx.
|
||||
rdmsr
|
||||
or edx, [.phys_reserved_mask]
|
||||
xor edx, [.phys_reserved_mask]
|
||||
mov ebp, edx
|
||||
mov ebx, eax
|
||||
inc ecx
|
||||
; If PHYSMASKn is not active, ignore this MTRR.
|
||||
rdmsr
|
||||
inc ecx
|
||||
test ah, 8
|
||||
jz .get_used_mtrrs_next
|
||||
; 4c. For every active MTRR, check that number of local entries is not too large.
|
||||
inc [.num_used_mtrrs]
|
||||
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
|
||||
ja .abort
|
||||
; 4d. For every active MTRR, store PHYSBASEn with upper bits cleared.
|
||||
; This contains the MTRR base and the memory type in low byte.
|
||||
mov [edi], ebx
|
||||
mov [edi+4], ebp
|
||||
; 4e. For every active MTRR, check that the range is continuous:
|
||||
; PHYSMASKn with upper bits set must be negated power of two, and
|
||||
; low bits of PHYSBASEn must be zeroes:
|
||||
; PHYSMASKn = 1...10...0,
|
||||
; PHYSBASEn = x...x0...0,
|
||||
; this defines a continuous range from x...x0...0 to x...x1...1,
|
||||
; length = 10...0 = negated PHYSMASKn.
|
||||
; Store length in the local array.
|
||||
and eax, not 0xFFF
|
||||
or edx, [.phys_reserved_mask]
|
||||
mov dword [edi+8], 0
|
||||
mov dword [edi+12], 0
|
||||
sub [edi+8], eax
|
||||
sbb [edi+12], edx
|
||||
; (x and -x) is the maximum power of two that divides x.
|
||||
; Condition for powers of two: (x and -x) equals x.
|
||||
and eax, [edi+8]
|
||||
and edx, [edi+12]
|
||||
cmp eax, [edi+8]
|
||||
jnz .abort
|
||||
cmp edx, [edi+12]
|
||||
jnz .abort
|
||||
sub eax, 1
|
||||
sbb edx, 0
|
||||
and eax, not 0xFFF
|
||||
and eax, ebx
|
||||
jnz .abort
|
||||
and edx, ebp
|
||||
jnz .abort
|
||||
; 4f. For every active MTRR, validate memory type: it must be either WB or UC.
|
||||
add edi, 16
|
||||
cmp bl, MEM_UC
|
||||
jz .get_used_mtrrs_next
|
||||
cmp bl, MEM_WB
|
||||
jnz .abort
|
||||
.get_used_mtrrs_next:
|
||||
; 4g. Repeat the loop at 4b-4f for all [num_variable_mtrrs] entries.
|
||||
mov eax, [num_variable_mtrrs]
|
||||
lea eax, [0x200+eax*2]
|
||||
cmp ecx, eax
|
||||
jb .get_used_mtrrs_loop
|
||||
; 4h. If no active MTRRs were detected, fallback to step 7.
|
||||
cmp [.num_used_mtrrs], 0
|
||||
jz .fill_ranges_from_memory_map
|
||||
mov [.mtrrs_end], edi
|
||||
; 5. Generate sorted list of ranges marked as WB.
|
||||
; 5a. Prepare for the loop over configured MTRRs filled at step 4.
|
||||
lea ecx, [.mtrrs]
|
||||
.fill_wb_ranges:
|
||||
; 5b. Ignore non-WB MTRRs.
|
||||
mov ebx, [ecx]
|
||||
cmp bl, MEM_WB
|
||||
jnz .next_wb_range
|
||||
mov ebp, [ecx+4]
|
||||
and ebx, not 0xFFF ; clear memory type and reserved bits
|
||||
; ebp:ebx = start of the range described by the current MTRR.
|
||||
; 5c. Find the first existing range containing a point greater than ebp:ebx.
|
||||
lea esi, [.first_range]
|
||||
.find_range_wb:
|
||||
; If there is no next range or start of the next range is greater than ebp:ebx,
|
||||
; exit the loop to 5d.
|
||||
mov edi, [esi]
|
||||
test edi, edi
|
||||
jz .found_place_wb
|
||||
mov eax, ebx
|
||||
mov edx, ebp
|
||||
sub eax, dword [edi+mtrr_range.start]
|
||||
sbb edx, dword [edi+mtrr_range.start+4]
|
||||
jb .found_place_wb
|
||||
; Otherwise, if end of the next range is greater than or equal to ebp:ebx,
|
||||
; exit the loop to 5e.
|
||||
mov esi, edi
|
||||
sub eax, dword [edi+mtrr_range.length]
|
||||
sbb edx, dword [edi+mtrr_range.length+4]
|
||||
jb .expand_wb
|
||||
or eax, edx
|
||||
jnz .find_range_wb
|
||||
jmp .expand_wb
|
||||
.found_place_wb:
|
||||
; 5d. ebp:ebx is not within any existing range.
|
||||
; Insert a new range between esi and edi.
|
||||
; (Later, during 5e, it can be merged with the following ranges.)
|
||||
mov eax, [.first_free_range]
|
||||
test eax, eax
|
||||
jz .abort
|
||||
mov [esi], eax
|
||||
mov edx, [eax+mtrr_range.next]
|
||||
mov [.first_free_range], edx
|
||||
mov dword [eax+mtrr_range.start], ebx
|
||||
mov dword [eax+mtrr_range.start+4], ebp
|
||||
; Don't fill [eax+mtrr_range.next] and [eax+mtrr_range.length] yet,
|
||||
; they will be calculated including merges at step 5e.
|
||||
mov esi, edi
|
||||
mov edi, eax
|
||||
.expand_wb:
|
||||
; 5e. The range at edi contains ebp:ebx, and esi points to the first range
|
||||
; to be checked for merge: esi=edi if ebp:ebx was found in an existing range,
|
||||
; esi is next after edi if a new range with ebp:ebx was created.
|
||||
; Merge it with following ranges while start of the next range is not greater
|
||||
; than the end of the new range.
|
||||
add ebx, [ecx+8]
|
||||
adc ebp, [ecx+12]
|
||||
; ebp:ebx = end of the range described by the current MTRR.
|
||||
.expand_wb_loop:
|
||||
; If there is no next range or start of the next range is greater than ebp:ebx,
|
||||
; exit the loop to 5g.
|
||||
test esi, esi
|
||||
jz .expand_wb_done
|
||||
mov eax, ebx
|
||||
mov edx, ebp
|
||||
sub eax, dword [esi+mtrr_range.start]
|
||||
sbb edx, dword [esi+mtrr_range.start+4]
|
||||
jb .expand_wb_done
|
||||
; Otherwise, if end of the next range is greater than or equal to ebp:ebx,
|
||||
; exit the loop to 5f.
|
||||
sub eax, dword [esi+mtrr_range.length]
|
||||
sbb edx, dword [esi+mtrr_range.length+4]
|
||||
jb .expand_wb_last
|
||||
; Otherwise, the current range is completely within the new range.
|
||||
; Free it and continue the loop.
|
||||
mov edx, [esi+mtrr_range.next]
|
||||
cmp esi, edi
|
||||
jz @f
|
||||
mov eax, [.first_free_range]
|
||||
mov [esi+mtrr_range.next], eax
|
||||
mov [.first_free_range], esi
|
||||
@@:
|
||||
mov esi, edx
|
||||
jmp .expand_wb_loop
|
||||
.expand_wb_last:
|
||||
; 5f. Start of the new range is inside range described by esi,
|
||||
; end of the new range is inside range described by edi.
|
||||
; If esi is equal to edi, the new range is completely within
|
||||
; an existing range, so proceed to the next range.
|
||||
cmp esi, edi
|
||||
jz .next_wb_range
|
||||
; Otherwise, set end of interval at esi to end of interval at edi
|
||||
; and free range described by edi.
|
||||
mov ebx, dword [esi+mtrr_range.start]
|
||||
mov ebp, dword [esi+mtrr_range.start+4]
|
||||
add ebx, dword [esi+mtrr_range.length]
|
||||
adc ebp, dword [esi+mtrr_range.length+4]
|
||||
mov edx, [esi+mtrr_range.next]
|
||||
mov eax, [.first_free_range]
|
||||
mov [esi+mtrr_range.next], eax
|
||||
mov [.first_free_range], esi
|
||||
mov esi, edx
|
||||
.expand_wb_done:
|
||||
; 5g. We have found the next range (maybe 0) after merging and
|
||||
; the new end of range (maybe ebp:ebx from the new range
|
||||
; or end of another existing interval calculated at step 5f).
|
||||
; Write them to range at edi.
|
||||
mov [edi+mtrr_range.next], esi
|
||||
sub ebx, dword [edi+mtrr_range.start]
|
||||
sbb ebp, dword [edi+mtrr_range.start+4]
|
||||
mov dword [edi+mtrr_range.length], ebx
|
||||
mov dword [edi+mtrr_range.length+4], ebp
|
||||
.next_wb_range:
|
||||
; 5h. Continue the loop 5b-5g over all configured MTRRs.
|
||||
add ecx, 16
|
||||
cmp ecx, [.mtrrs_end]
|
||||
jb .fill_wb_ranges
|
||||
; 6. Exclude all ranges marked as UC.
|
||||
; 6a. Prepare for the loop over configured MTRRs filled at step 4.
|
||||
lea ecx, [.mtrrs]
|
||||
.fill_uc_ranges:
|
||||
; 6b. Ignore non-UC MTRRs.
|
||||
mov ebx, [ecx]
|
||||
cmp bl, MEM_UC
|
||||
jnz .next_uc_range
|
||||
mov ebp, [ecx+4]
|
||||
and ebx, not 0xFFF ; clear memory type and reserved bits
|
||||
; ebp:ebx = start of the range described by the current MTRR.
|
||||
lea esi, [.first_range]
|
||||
; 6c. Find the first existing range containing a point greater than ebp:ebx.
|
||||
.find_range_uc:
|
||||
; If there is no next range, ignore this MTRR,
|
||||
; exit the loop and continue to next MTRR.
|
||||
mov edi, [esi]
|
||||
test edi, edi
|
||||
jz .next_uc_range
|
||||
; If start of the next range is greater than or equal to ebp:ebx,
|
||||
; exit the loop to 6e.
|
||||
mov eax, dword [edi+mtrr_range.start]
|
||||
mov edx, dword [edi+mtrr_range.start+4]
|
||||
sub eax, ebx
|
||||
sbb edx, ebp
|
||||
jnb .truncate_uc
|
||||
; Otherwise, continue the loop if end of the next range is less than ebp:ebx,
|
||||
; exit the loop to 6d otherwise.
|
||||
mov esi, edi
|
||||
add eax, dword [edi+mtrr_range.length]
|
||||
adc edx, dword [edi+mtrr_range.length+4]
|
||||
jnb .find_range_uc
|
||||
; 6d. ebp:ebx is inside (or at end of) an existing range.
|
||||
; Split the range. (The second range, maybe containing completely within UC-range,
|
||||
; maybe of zero length, can be removed at step 6e, if needed.)
|
||||
mov edi, [.first_free_range]
|
||||
test edi, edi
|
||||
jz .abort
|
||||
mov dword [edi+mtrr_range.start], ebx
|
||||
mov dword [edi+mtrr_range.start+4], ebp
|
||||
mov dword [edi+mtrr_range.length], eax
|
||||
mov dword [edi+mtrr_range.length+4], edx
|
||||
mov eax, [edi+mtrr_range.next]
|
||||
mov [.first_free_range], eax
|
||||
mov eax, [esi+mtrr_range.next]
|
||||
mov [edi+mtrr_range.next], eax
|
||||
; don't change [esi+mtrr_range.next] yet, it will be filled at step 6e
|
||||
mov eax, ebx
|
||||
mov edx, ebp
|
||||
sub eax, dword [esi+mtrr_range.start]
|
||||
sbb edx, dword [esi+mtrr_range.start+4]
|
||||
mov dword [esi+mtrr_range.length], eax
|
||||
mov dword [esi+mtrr_range.length+4], edx
|
||||
.truncate_uc:
|
||||
; 6e. edi is the first range after ebp:ebx, check it and next ranges
|
||||
; for intersection with the new range, truncate heads.
|
||||
add ebx, [ecx+8]
|
||||
adc ebp, [ecx+12]
|
||||
; ebp:ebx = end of the range described by the current MTRR.
|
||||
.truncate_uc_loop:
|
||||
; If start of the next range is greater than ebp:ebx,
|
||||
; exit the loop to 6g.
|
||||
mov eax, ebx
|
||||
mov edx, ebp
|
||||
sub eax, dword [edi+mtrr_range.start]
|
||||
sbb edx, dword [edi+mtrr_range.start+4]
|
||||
jb .truncate_uc_done
|
||||
; Otherwise, if end of the next range is greater than ebp:ebx,
|
||||
; exit the loop to 6f.
|
||||
sub eax, dword [edi+mtrr_range.length]
|
||||
sbb edx, dword [edi+mtrr_range.length+4]
|
||||
jb .truncate_uc_last
|
||||
; Otherwise, the current range is completely within the new range.
|
||||
; Free it and continue the loop if there is a next range.
|
||||
; If that was a last range, exit the loop to 6g.
|
||||
mov edx, [edi+mtrr_range.next]
|
||||
mov eax, [.first_free_range]
|
||||
mov [.first_free_range], edi
|
||||
mov [edi+mtrr_range.next], eax
|
||||
mov edi, edx
|
||||
test edi, edi
|
||||
jnz .truncate_uc_loop
|
||||
jmp .truncate_uc_done
|
||||
.truncate_uc_last:
|
||||
; 6f. The range at edi partially intersects with the UC-range described by MTRR.
|
||||
; Truncate it from the head.
|
||||
mov dword [edi+mtrr_range.start], ebx
|
||||
mov dword [edi+mtrr_range.start+4], ebp
|
||||
neg eax
|
||||
adc edx, 0
|
||||
neg edx
|
||||
mov dword [edi+mtrr_range.length], eax
|
||||
mov dword [edi+mtrr_range.length+4], edx
|
||||
.truncate_uc_done:
|
||||
; 6g. We have found the next range (maybe 0) after intersection.
|
||||
; Write it to [esi+mtrr_range.next].
|
||||
mov [esi+mtrr_range.next], edi
|
||||
.next_uc_range:
|
||||
; 6h. Continue the loop 6b-6g over all configured MTRRs.
|
||||
add ecx, 16
|
||||
cmp ecx, [.mtrrs_end]
|
||||
jb .fill_uc_ranges
|
||||
; Sanity check: if there are no ranges after steps 5-6,
|
||||
; fallback to step 7. Otherwise, go to 8.
|
||||
cmp [.first_range], 0
|
||||
jnz .ranges_ok
|
||||
.fill_ranges_from_memory_map:
|
||||
; 7. BIOS has not configured variable-range MTRRs.
|
||||
; Create one range from 0 to [MEM_AMOUNT].
|
||||
mov eax, [.first_free_range]
|
||||
mov edx, [eax+mtrr_range.next]
|
||||
mov [.first_free_range], edx
|
||||
mov [.first_range], eax
|
||||
xor edx, edx
|
||||
mov [eax+mtrr_range.next], edx
|
||||
mov dword [eax+mtrr_range.start], edx
|
||||
mov dword [eax+mtrr_range.start+4], edx
|
||||
mov ecx, [MEM_AMOUNT]
|
||||
mov dword [eax+mtrr_range.length], ecx
|
||||
mov dword [eax+mtrr_range.length+4], edx
|
||||
.ranges_ok:
|
||||
; 8. We have calculated list of WB-ranges.
|
||||
; Now we should calculate a list of MTRRs so that
|
||||
; * every MTRR describes a range with length = power of 2 and start that is aligned,
|
||||
; * every MTRR can be WB or UC
|
||||
; * (sum of all WB ranges) minus (sum of all UC ranges) equals the calculated list
|
||||
; * top of 4G memory must not be covered by any ranges
|
||||
; Example: range [0,0xBC000000) can be converted to
|
||||
; [0,0x80000000)+[0x80000000,0xC0000000)-[0xBC000000,0xC0000000)
|
||||
; WB +WB -UC
|
||||
; but not to [0,0x100000000)-[0xC0000000,0x100000000)-[0xBC000000,0xC0000000).
|
||||
; 8a. Check that list of ranges is [0,something) plus, optionally, [4G,something).
|
||||
; This holds in practice (see mtrrtest.asm for real-life examples)
|
||||
; and significantly simplifies the code: ranges are independent, start of range
|
||||
; is almost always aligned (the only exception >4G upper memory can be easily covered),
|
||||
; there is no need to consider adding holes before start of range, only
|
||||
; append them to end of range.
|
||||
xor eax, eax
|
||||
mov edi, [.first_range]
|
||||
cmp dword [edi+mtrr_range.start], eax
|
||||
jnz .abort
|
||||
cmp dword [edi+mtrr_range.start+4], eax
|
||||
jnz .abort
|
||||
cmp dword [edi+mtrr_range.length+4], eax
|
||||
jnz .abort
|
||||
mov edx, [edi+mtrr_range.next]
|
||||
test edx, edx
|
||||
jz @f
|
||||
cmp dword [edx+mtrr_range.start], eax
|
||||
jnz .abort
|
||||
cmp dword [edx+mtrr_range.start+4], 1
|
||||
jnz .abort
|
||||
cmp [edx+mtrr_range.next], eax
|
||||
jnz .abort
|
||||
@@:
|
||||
; 8b. Initialize: no MTRRs filled.
|
||||
mov [.num_used_mtrrs], eax
|
||||
lea esi, [.mtrrs]
|
||||
.range2mtrr_loop:
|
||||
; 8c. If we are dealing with upper-memory range (after 4G)
|
||||
; with length > start, create one WB MTRR with [start,2*start),
|
||||
; reset start to 2*start and return to this step.
|
||||
; Example: [4G,24G) -> [4G,8G) {returning} + [8G,16G) {returning}
|
||||
; + [16G,24G) {advancing to ?}.
|
||||
mov eax, dword [edi+mtrr_range.length+4]
|
||||
test eax, eax
|
||||
jz .less4G
|
||||
mov edx, dword [edi+mtrr_range.start+4]
|
||||
cmp eax, edx
|
||||
jb .start_aligned
|
||||
inc [.num_used_mtrrs]
|
||||
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
|
||||
ja .abort
|
||||
mov dword [esi], MEM_WB
|
||||
mov dword [esi+4], edx
|
||||
mov dword [esi+8], 0
|
||||
mov dword [esi+12], edx
|
||||
add esi, 16
|
||||
add dword [edi+mtrr_range.start+4], edx
|
||||
sub dword [edi+mtrr_range.length+4], edx
|
||||
jnz .range2mtrr_loop
|
||||
cmp dword [edi+mtrr_range.length], 0
|
||||
jz .range2mtrr_next
|
||||
.less4G:
|
||||
; 8d. If we are dealing with low-memory range (before 4G)
|
||||
; and appending a maximal-size hole would create a range covering top of 4G,
|
||||
; create a maximal-size WB range and return to this step.
|
||||
; Example: for [0,0xBC000000) the following steps would consider
|
||||
; variants [0,0x80000000)+(another range to be splitted) and
|
||||
; [0,0x100000000)-(another range to be splitted); we forbid the last variant,
|
||||
; so the first variant must be used.
|
||||
bsr ecx, dword [edi+mtrr_range.length]
|
||||
xor edx, edx
|
||||
inc edx
|
||||
shl edx, cl
|
||||
lea eax, [edx*2]
|
||||
add eax, dword [edi+mtrr_range.start]
|
||||
jnz .start_aligned
|
||||
inc [.num_used_mtrrs]
|
||||
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
|
||||
ja .abort
|
||||
mov eax, dword [edi+mtrr_range.start]
|
||||
mov dword [esi], eax
|
||||
or dword [esi], MEM_WB
|
||||
mov dword [esi+4], 0
|
||||
mov dword [esi+8], edx
|
||||
mov dword [esi+12], 0
|
||||
add esi, 16
|
||||
add dword [edi+mtrr_range.start], edx
|
||||
sub dword [edi+mtrr_range.length], edx
|
||||
jnz .less4G
|
||||
jmp .range2mtrr_next
|
||||
.start_aligned:
|
||||
; Start is aligned for any allowed length, maximum-size hole is allowed.
|
||||
; Select the best MTRR configuration for one range.
|
||||
; length=...101101
|
||||
; Without hole at the end, we need one WB MTRR for every 1-bit in length:
|
||||
; length=...100000 + ...001000 + ...000100 + ...000001
|
||||
; We can also append one hole at the end so that one 0-bit (selected by us)
|
||||
; becomes 1 and all lower bits become 0 for WB-range:
|
||||
; length=...110000 - (...00010 + ...00001)
|
||||
; In this way, we need one WB MTRR for every 1-bit higher than the selected bit,
|
||||
; one WB MTRR for the selected bit, one UC MTRR for every 0-bit between
|
||||
; the selected bit and lowest 1-bit (they become 1-bits after negation)
|
||||
; and one UC MTRR for lowest 1-bit.
|
||||
; So we need to select 0-bit with the maximal difference
|
||||
; (number of 0-bits) - (number of 1-bits) between selected and lowest 1-bit,
|
||||
; this equals the gain from using a hole. If the difference is negative for
|
||||
; all 0-bits, don't append hole.
|
||||
; Note that lowest 1-bit is not included when counting, but selected 0-bit is.
|
||||
; 8e. Find the optimal bit position for hole.
|
||||
; eax = current difference, ebx = best difference,
|
||||
; ecx = hole bit position, edx = current bit position.
|
||||
xor eax, eax
|
||||
xor ebx, ebx
|
||||
xor ecx, ecx
|
||||
bsf edx, dword [edi+mtrr_range.length]
|
||||
jnz @f
|
||||
bsf edx, dword [edi+mtrr_range.length+4]
|
||||
add edx, 32
|
||||
@@:
|
||||
push edx ; save position of lowest 1-bit for step 8f
|
||||
.calc_stat:
|
||||
inc edx
|
||||
cmp edx, 64
|
||||
jae .stat_done
|
||||
inc eax ; increment difference in hope for 1-bit
|
||||
; Note: bt conveniently works with both .length and .length+4,
|
||||
; depending on whether edx>=32.
|
||||
bt dword [edi+mtrr_range.length], edx
|
||||
jc .calc_stat
|
||||
dec eax ; hope was wrong, decrement difference to correct 'inc'
|
||||
dec eax ; and again, now getting the real difference
|
||||
cmp eax, ebx
|
||||
jle .calc_stat
|
||||
mov ebx, eax
|
||||
mov ecx, edx
|
||||
jmp .calc_stat
|
||||
.stat_done:
|
||||
; 8f. If we decided to create a hole, flip all bits between lowest and selected.
|
||||
pop edx ; restore position of lowest 1-bit saved at step 8e
|
||||
test ecx, ecx
|
||||
jz .fill_hi_init
|
||||
@@:
|
||||
inc edx
|
||||
cmp edx, ecx
|
||||
ja .fill_hi_init
|
||||
btc dword [edi+mtrr_range.length], edx
|
||||
jmp @b
|
||||
.fill_hi_init:
|
||||
; 8g. Create MTRR ranges corresponding to upper 32 bits.
|
||||
sub ecx, 32
|
||||
.fill_hi_loop:
|
||||
bsr edx, dword [edi+mtrr_range.length+4]
|
||||
jz .fill_hi_done
|
||||
inc [.num_used_mtrrs]
|
||||
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
|
||||
ja .abort
|
||||
mov eax, dword [edi+mtrr_range.start]
|
||||
mov [esi], eax
|
||||
mov eax, dword [edi+mtrr_range.start+4]
|
||||
mov [esi+4], eax
|
||||
xor eax, eax
|
||||
mov [esi+8], eax
|
||||
bts eax, edx
|
||||
mov [esi+12], eax
|
||||
cmp edx, ecx
|
||||
jl .fill_hi_uc
|
||||
or dword [esi], MEM_WB
|
||||
add dword [edi+mtrr_range.start+4], eax
|
||||
jmp @f
|
||||
.fill_hi_uc:
|
||||
sub dword [esi+4], eax
|
||||
sub dword [edi+mtrr_range.start+4], eax
|
||||
@@:
|
||||
add esi, 16
|
||||
sub dword [edi+mtrr_range.length], eax
|
||||
jmp .fill_hi_loop
|
||||
.fill_hi_done:
|
||||
; 8h. Create MTRR ranges corresponding to lower 32 bits.
|
||||
add ecx, 32
|
||||
.fill_lo_loop:
|
||||
bsr edx, dword [edi+mtrr_range.length]
|
||||
jz .range2mtrr_next
|
||||
inc [.num_used_mtrrs]
|
||||
cmp [.num_used_mtrrs], MAX_USEFUL_MTRRS
|
||||
ja .abort
|
||||
mov eax, dword [edi+mtrr_range.start]
|
||||
mov [esi], eax
|
||||
mov eax, dword [edi+mtrr_range.start+4]
|
||||
mov [esi+4], eax
|
||||
xor eax, eax
|
||||
mov [esi+12], eax
|
||||
bts eax, edx
|
||||
mov [esi+8], eax
|
||||
cmp edx, ecx
|
||||
jl .fill_lo_uc
|
||||
or dword [esi], MEM_WB
|
||||
add dword [edi+mtrr_range.start], eax
|
||||
jmp @f
|
||||
.fill_lo_uc:
|
||||
sub dword [esi], eax
|
||||
sub dword [edi+mtrr_range.start], eax
|
||||
@@:
|
||||
add esi, 16
|
||||
sub dword [edi+mtrr_range.length], eax
|
||||
jmp .fill_lo_loop
|
||||
.range2mtrr_next:
|
||||
; 8i. Repeat the loop at 8c-8h for all ranges.
|
||||
mov edi, [edi+mtrr_range.next]
|
||||
test edi, edi
|
||||
jnz .range2mtrr_loop
|
||||
; 9. We have calculated needed MTRRs, now setup them in the CPU.
|
||||
; 9a. Abort if number of MTRRs is too large.
|
||||
mov eax, [num_variable_mtrrs]
|
||||
cmp [.num_used_mtrrs], eax
|
||||
ja .abort
|
||||
|
||||
; 9b. Prepare for changes.
|
||||
call mtrr_begin_change
|
||||
|
||||
; 9c. Prepare for loop over MTRRs.
|
||||
lea esi, [.mtrrs]
|
||||
mov ecx, 0x200
|
||||
@@:
|
||||
; 9d. For every MTRR, copy PHYSBASEn as is: step 8 has configured
|
||||
; start value and type bits as needed.
|
||||
mov eax, [esi]
|
||||
mov edx, [esi+4]
|
||||
wrmsr
|
||||
inc ecx
|
||||
; 9e. For every MTRR, calculate PHYSMASKn = -(length) or 0x800
|
||||
; with upper bits cleared, 0x800 = MTRR is valid.
|
||||
xor eax, eax
|
||||
xor edx, edx
|
||||
sub eax, [esi+8]
|
||||
sbb edx, [esi+12]
|
||||
or eax, 0x800
|
||||
or edx, [.phys_reserved_mask]
|
||||
xor edx, [.phys_reserved_mask]
|
||||
wrmsr
|
||||
inc ecx
|
||||
; 9f. Continue steps 9d and 9e for all MTRRs calculated at step 8.
|
||||
add esi, 16
|
||||
dec [.num_used_mtrrs]
|
||||
jnz @b
|
||||
; 9g. Zero other MTRRs.
|
||||
xor eax, eax
|
||||
xor edx, edx
|
||||
mov ebx, [num_variable_mtrrs]
|
||||
lea ebx, [0x200+ebx*2]
|
||||
@@:
|
||||
cmp ecx, ebx
|
||||
jae @f
|
||||
wrmsr
|
||||
inc ecx
|
||||
wrmsr
|
||||
inc ecx
|
||||
jmp @b
|
||||
@@:
|
||||
|
||||
; 9i. Check PAT support and reprogram PAT_MASR for write combining memory
|
||||
bt [cpu_caps], CAPS_PAT
|
||||
jnc @F
|
||||
|
||||
mov ecx, MSR_CR_PAT
|
||||
mov eax, PAT_VALUE ;UC UCM WC WB
|
||||
mov edx, eax
|
||||
wrmsr
|
||||
@@:
|
||||
|
||||
; 9j. Changes are done.
|
||||
call mtrr_end_change
|
||||
|
||||
.abort:
|
||||
add esp, .local_vars_size + MAX_RANGES * sizeof.mtrr_range
|
||||
pop ebp
|
||||
ret
|
||||
endp
|
||||
|
||||
; Allocate&set one MTRR for given range.
|
||||
; size must be power of 2 that divides base.
|
||||
proc set_mtrr stdcall, base:dword,size:dword,mem_type:dword
|
||||
; find unused register
|
||||
mov ecx, 0x201
|
||||
.scan:
|
||||
mov eax, [num_variable_mtrrs]
|
||||
lea eax, [0x200+eax*2]
|
||||
cmp ecx, eax
|
||||
jae .ret
|
||||
rdmsr
|
||||
dec ecx
|
||||
test ah, 8
|
||||
jz .found
|
||||
rdmsr
|
||||
test edx, edx
|
||||
jnz @f
|
||||
and eax, not 0xFFF ; clear reserved bits
|
||||
cmp eax, [base]
|
||||
jz .ret
|
||||
@@:
|
||||
add ecx, 3
|
||||
jmp .scan
|
||||
; no free registers, ignore the call
|
||||
.ret:
|
||||
ret
|
||||
.found:
|
||||
; found, write values
|
||||
push ecx
|
||||
call mtrr_begin_change
|
||||
pop ecx
|
||||
xor edx, edx
|
||||
mov eax, [base]
|
||||
or eax, [mem_type]
|
||||
wrmsr
|
||||
|
||||
mov al, [cpu_phys_addr_width]
|
||||
xor edx, edx
|
||||
bts edx, eax
|
||||
xor eax, eax
|
||||
sub eax, [size]
|
||||
sbb edx, 0
|
||||
or eax, 0x800
|
||||
inc ecx
|
||||
wrmsr
|
||||
call mtrr_end_change
|
||||
ret
|
||||
endp
|
||||
|
||||
; Helper procedure for mtrr_validate.
|
||||
; Calculates memory type for given address according to variable-range MTRRs.
|
||||
; Assumes that MTRRs are enabled.
|
||||
; in: ebx = 32-bit physical address
|
||||
; out: eax = memory type for ebx
|
||||
proc mtrr_get_real_type
|
||||
; 1. Initialize: we have not yet found any MTRRs covering ebx.
|
||||
push 0
|
||||
mov ecx, 0x201
|
||||
.mtrr_loop:
|
||||
; 2. For every MTRR, check whether it is valid; if not, continue to the next MTRR.
|
||||
rdmsr
|
||||
dec ecx
|
||||
test ah, 8
|
||||
jz .next
|
||||
; 3. For every valid MTRR, check whether (ebx and PHYSMASKn) == PHYSBASEn,
|
||||
; excluding low 12 bits.
|
||||
and eax, ebx
|
||||
push eax
|
||||
rdmsr
|
||||
test edx, edx
|
||||
pop edx
|
||||
jnz .next
|
||||
xor edx, eax
|
||||
and edx, not 0xFFF
|
||||
jnz .next
|
||||
; 4. If so, set the bit corresponding to memory type defined by this MTRR.
|
||||
and eax, 7
|
||||
bts [esp], eax
|
||||
.next:
|
||||
; 5. Continue loop at 2-4 for all variable-range MTRRs.
|
||||
add ecx, 3
|
||||
mov eax, [num_variable_mtrrs]
|
||||
lea eax, [0x200+eax*2]
|
||||
cmp ecx, eax
|
||||
jb .mtrr_loop
|
||||
; 6. If no MTRRs cover address in ebx, use default MTRR type from MTRR_DEF_CAP.
|
||||
pop edx
|
||||
test edx, edx
|
||||
jz .default
|
||||
; 7. Find&clear 1-bit in edx.
|
||||
bsf eax, edx
|
||||
btr edx, eax
|
||||
; 8. If there was only one 1-bit, then all MTRRs are consistent, return that bit.
|
||||
test edx, edx
|
||||
jz .nothing
|
||||
; Otherwise, return MEM_UC (e.g. WB+UC is UC).
|
||||
xor eax, eax
|
||||
.nothing:
|
||||
ret
|
||||
.default:
|
||||
mov ecx, 0x2FF
|
||||
rdmsr
|
||||
movzx eax, al
|
||||
ret
|
||||
endp
|
||||
|
||||
; If MTRRs are configured improperly, this is not obvious to the user;
|
||||
; everything works, but the performance can be horrible.
|
||||
; Try to detect this and let the user know that the low performance
|
||||
; is caused by some problem and is not a global property of the system.
|
||||
; Let's hope he would report it to developers...
|
||||
proc mtrr_validate
|
||||
; 1. If MTRRs are not supported, they cannot be configured improperly.
|
||||
; Note: VirtualBox claims MTRR support in cpuid, but emulates MTRRCAP=0,
|
||||
; which is efficiently equivalent to absent MTRRs.
|
||||
; So check [num_variable_mtrrs] instead of CAPS_MTRR in [cpu_caps].
|
||||
cmp [num_variable_mtrrs], 0
|
||||
jz .exit
|
||||
; 2. If variable-range MTRRs are not configured, this is a problem.
|
||||
mov ecx, 0x2FF
|
||||
rdmsr
|
||||
test ah, 8
|
||||
jz .fail
|
||||
; 3. Get the memory type for address somewhere inside working memory.
|
||||
; It must be write-back.
|
||||
mov ebx, 0x27FFFF
|
||||
call mtrr_get_real_type
|
||||
cmp al, MEM_WB
|
||||
jnz .fail
|
||||
; 4. If we're using a mode with LFB,
|
||||
; get the memory type for last pixel of the framebuffer.
|
||||
; It must be write-combined.
|
||||
test word [SCR_MODE], 0x4000
|
||||
jz .exit
|
||||
mov eax, [_display.lfb_pitch]
|
||||
mul [_display.height]
|
||||
dec eax
|
||||
; LFB is mapped to virtual address LFB_BASE,
|
||||
; it uses global pages if supported by CPU.
|
||||
mov ebx, [sys_proc+PROC.pdt_0+(LFB_BASE shr 20)]
|
||||
test ebx, PDE_LARGE
|
||||
jnz @f
|
||||
mov ebx, [page_tabs+(LFB_BASE shr 10)]
|
||||
@@:
|
||||
and ebx, not 0xFFF
|
||||
add ebx, eax
|
||||
call mtrr_get_real_type
|
||||
cmp al, MEM_WC
|
||||
jz .exit
|
||||
; 5. The check at step 4 fails on Bochs:
|
||||
; Bochs BIOS configures MTRRs in a strange way not respecting [cpu_phys_addr_width],
|
||||
; so mtrr_reconfigure avoids to touch anything.
|
||||
; However, Bochs core ignores MTRRs (keeping them only for rdmsr/wrmsr),
|
||||
; so we don't care about proper setting for Bochs.
|
||||
; Use northbridge PCI id to detect Bochs: it emulates either i440fx or i430fx
|
||||
; depending on configuration file.
|
||||
mov eax, [pcidev_list.fd]
|
||||
cmp eax, pcidev_list ; sanity check: fail if no PCI devices
|
||||
jz .fail
|
||||
cmp [eax+PCIDEV.vendor_device_id], 0x12378086
|
||||
jz .exit
|
||||
cmp [eax+PCIDEV.vendor_device_id], 0x01228086
|
||||
jnz .fail
|
||||
.exit:
|
||||
ret
|
||||
.fail:
|
||||
mov ebx, mtrr_user_message
|
||||
mov ebp, notifyapp
|
||||
call fs_execute_from_sysdir_param
|
||||
ret
|
||||
endp
|
||||
213
kernel/branches/kolibri-lldw/core/mtrrtest.asm
Normal file
213
kernel/branches/kolibri-lldw/core/mtrrtest.asm
Normal file
@@ -0,0 +1,213 @@
|
||||
; Simple test for ring-3 debugging of mtrr.inc.
|
||||
; Contains some inputs taken from real-life MTRRs and expected outputs.
|
||||
format PE console
|
||||
;include 'win32a.inc'
|
||||
macro $Revision [args]
|
||||
{
|
||||
}
|
||||
macro ignore_empty_revision_keyword {
|
||||
macro $Revi#sion$ \{\}
|
||||
}
|
||||
ignore_empty_revision_keyword
|
||||
include '../proc32.inc'
|
||||
include '../struct.inc'
|
||||
entry start
|
||||
|
||||
; one test has 8, another test has 10
|
||||
; this is the maximal value for storing/copying, real value is in MTRRCAP
|
||||
MAX_VARIABLE_MTRR = 10
|
||||
|
||||
start:
|
||||
; Copy test inputs, run init_mtrr, compare with test outputs. Repeat.
|
||||
mov esi, test1_in_data
|
||||
mov edi, mtrrdata
|
||||
mov ecx, mtrrdata_size / 4
|
||||
rep movsd
|
||||
call init_mtrr
|
||||
mov esi, test1_out_data
|
||||
mov edi, mtrrdata
|
||||
mov ecx, mtrrdata_size / 4
|
||||
repz cmpsd
|
||||
jnz .fail
|
||||
mov esi, test2_in_data
|
||||
mov edi, mtrrdata
|
||||
mov ecx, mtrrdata_size / 4
|
||||
rep movsd
|
||||
call init_mtrr
|
||||
mov esi, test2_out_data
|
||||
mov edi, mtrrdata
|
||||
mov ecx, mtrrdata_size / 4
|
||||
repz cmpsd
|
||||
jnz .fail
|
||||
ret
|
||||
|
||||
.fail:
|
||||
int3
|
||||
jmp $
|
||||
|
||||
; Helper procedure for _rdmsr/_wrmsr, replacements of rdmsr/wrmsr.
|
||||
; Returns pointer to memory containing the given MSR.
|
||||
; in: ecx = MSR
|
||||
; out: esi -> MSR data
|
||||
proc get_msr_ptr
|
||||
mov esi, mtrrcap
|
||||
cmp ecx, 0xFE
|
||||
jz .ok
|
||||
mov esi, mtrr_def_type
|
||||
cmp ecx, 0x2FF
|
||||
jz .ok
|
||||
lea esi, [ecx-0x200]
|
||||
cmp esi, MAX_VARIABLE_MTRR*2
|
||||
jae .fail
|
||||
lea esi, [mtrr+esi*8]
|
||||
.ok:
|
||||
ret
|
||||
.fail:
|
||||
int3
|
||||
ret
|
||||
endp
|
||||
|
||||
; Emulates rdmsr.
|
||||
proc _rdmsr
|
||||
push esi
|
||||
call get_msr_ptr
|
||||
mov eax, [esi]
|
||||
mov edx, [esi+4]
|
||||
pop esi
|
||||
ret
|
||||
endp
|
||||
|
||||
; Emulates wrmsr.
|
||||
proc _wrmsr
|
||||
push esi
|
||||
call get_msr_ptr
|
||||
mov [esi], eax
|
||||
mov [esi+4], edx
|
||||
pop esi
|
||||
ret
|
||||
endp
|
||||
|
||||
; Macro to substitute rdmsr/wrmsr with emulating code.
|
||||
macro rdmsr
|
||||
{
|
||||
call _rdmsr
|
||||
}
|
||||
macro wrmsr
|
||||
{
|
||||
call _wrmsr
|
||||
}
|
||||
; Our emulation of rdmsr/wrmsr has nothing to do with real cache
|
||||
; and system-wide settings,
|
||||
; remove all attempts to wbinvd and disable/enable cache in cr0.
|
||||
macro wbinvd
|
||||
{
|
||||
}
|
||||
macro mov a,b
|
||||
{
|
||||
if ~(a eq cr0) & ~(b eq cr0)
|
||||
mov a, b
|
||||
end if
|
||||
}
|
||||
macro movi r,i
|
||||
{
|
||||
push i
|
||||
pop r
|
||||
}
|
||||
|
||||
include '../kglobals.inc'
|
||||
CAPS_MTRR = 12
|
||||
MSR_MTRR_DEF_TYPE = 0x2FF
|
||||
CAPS_PGE = 13
|
||||
CAPS_PAT = 16
|
||||
MSR_CR_PAT = 0x277
|
||||
PAT_VALUE = 0x00070106 ; (UC<<24)|(UCM<<16)|(WC<<8)|WB
|
||||
MEM_WB = 6 ;write-back memory
|
||||
MEM_WC = 1 ;write combined memory
|
||||
MEM_UC = 0 ;uncached memory
|
||||
include 'mtrr.inc'
|
||||
|
||||
BOOT_VARS = 0
|
||||
BOOT.mtrr db 1
|
||||
align 4
|
||||
cpu_caps dd 1 shl CAPS_MTRR
|
||||
LFBAddress dd 0xE0000000
|
||||
LFBSize dd 0x10000000
|
||||
MEM_AMOUNT dd 0 ; not used, needed for compilation
|
||||
|
||||
align 4
|
||||
; Test 1: input
|
||||
test1_in_data:
|
||||
test1_phys_addr_width db 36
|
||||
rb 3
|
||||
test1_in_mtrrcap dq 0xD08
|
||||
test1_in_mtrr_def_type dq 0xC00
|
||||
test1_in_mtrrs:
|
||||
dq 0x000000006, 0xF00000800
|
||||
dq 0x100000006, 0xFC0000800
|
||||
dq 0x0BC000000, 0xFFC000800
|
||||
dq 0x0C0000000, 0xFC0000800
|
||||
dq 0x138000000, 0xFF8000800
|
||||
dq 0, 0
|
||||
dq 0, 0
|
||||
dq 0, 0
|
||||
dq -1, -1 ; not used
|
||||
dq -1, -1 ; not used
|
||||
; Test 1: output
|
||||
test1_out_data:
|
||||
dd 36 ; phys_addr_width, readonly
|
||||
dq 0xD08 ; MTRRCAP, readonly
|
||||
dq 0xC00 ; MTRR_DEF_TYPE, should be the same
|
||||
dq 0x000000006, 0xF80000800
|
||||
dq 0x080000006, 0xFC0000800
|
||||
dq 0x0BC000000, 0xFFC000800
|
||||
dq 0x100000006, 0xFC0000800
|
||||
dq 0x138000000, 0xFF8000800
|
||||
dq 0x0E0000001, 0xFFF000800 ; added for [LFBAddress]
|
||||
dq 0, 0
|
||||
dq 0, 0
|
||||
dq -1, -1 ; not used
|
||||
dq -1, -1 ; not used
|
||||
|
||||
; Test 2: input
|
||||
test2_in_data:
|
||||
test2_phys_addr_width db 39
|
||||
rb 3
|
||||
test2_in_mtrrcap dq 0xD0A
|
||||
test2_in_mtrr_def_type dq 0xC00
|
||||
test2_in_mtrrs:
|
||||
dq 0x0000000006, 0x7F00000800
|
||||
dq 0x0100000006, 0x7FE0000800
|
||||
dq 0x00E0000000, 0x7FE0000800
|
||||
dq 0x00DC000000, 0x7FFC000800
|
||||
dq 0x00DBC00000, 0x7FFFC00800
|
||||
dq 0x011F800000, 0x7FFF800800
|
||||
dq 0x011F400000, 0x7FFFC00800
|
||||
dq 0x011F200000, 0x7FFFE00800
|
||||
dq 0, 0
|
||||
dq 0, 0
|
||||
|
||||
; Test 2: output
|
||||
test2_out_data:
|
||||
dd 39 ; phys_addr_width, readonly
|
||||
dq 0xD0A ; MTRRCAP, readonly
|
||||
dq 0xC00 ; MTRR_DEF_TYPE, should be the same
|
||||
dq 0x0000000006, 0x7F80000800
|
||||
dq 0x0080000006, 0x7FC0000800
|
||||
dq 0x00C0000006, 0x7FE0000800
|
||||
dq 0x00DC000000, 0x7FFC000800
|
||||
dq 0x00DBC00000, 0x7FFFC00800
|
||||
dq 0x0100000006, 0x7FE0000800
|
||||
dq 0x011F800000, 0x7FFF800800
|
||||
dq 0x011F400000, 0x7FFFC00800
|
||||
dq 0x011F200000, 0x7FFFE00800
|
||||
dq 0x00E0000001, 0x7FFF000800 ; added for [LFBAddress]
|
||||
IncludeIGlobals
|
||||
align 4
|
||||
mtrrdata:
|
||||
cpu_phys_addr_width db ?
|
||||
rb 3
|
||||
mtrrcap dq ?
|
||||
mtrr_def_type dq ?
|
||||
mtrr rq MAX_VARIABLE_MTRR*2
|
||||
mtrrdata_size = $ - mtrrdata
|
||||
IncludeUGlobals
|
||||
295
kernel/branches/kolibri-lldw/core/peload.inc
Normal file
295
kernel/branches/kolibri-lldw/core/peload.inc
Normal file
@@ -0,0 +1,295 @@
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; ;;
|
||||
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
|
||||
;; Distributed under terms of the GNU General Public License ;;
|
||||
;; ;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
$Revision$
|
||||
|
||||
include 'export.inc'
|
||||
|
||||
align 4
|
||||
|
||||
proc load_PE stdcall, file_name:dword
|
||||
locals
|
||||
image dd ?
|
||||
entry dd ?
|
||||
base dd ?
|
||||
endl
|
||||
|
||||
stdcall load_file, [file_name]
|
||||
test eax, eax
|
||||
jz .fail
|
||||
|
||||
mov [image], eax
|
||||
|
||||
mov edx, [eax+STRIPPED_PE_HEADER.SizeOfImage]
|
||||
; mov cl, [eax+STRIPPED_PE_HEADER.Subsystem]
|
||||
cmp word [eax], STRIPPED_PE_SIGNATURE
|
||||
jz @f
|
||||
|
||||
mov edx, [eax+60]
|
||||
; mov cl, [eax+5Ch+edx]
|
||||
mov edx, [eax+80+edx]
|
||||
|
||||
@@:
|
||||
mov [entry], 0
|
||||
; cmp cl, 1
|
||||
; jnz .cleanup
|
||||
stdcall kernel_alloc, edx
|
||||
test eax, eax
|
||||
jz .cleanup
|
||||
|
||||
mov [base], eax
|
||||
DEBUGF 1,'K : driver %s mapped to %x\n',[file_name],[base]
|
||||
|
||||
push ebx ebp
|
||||
mov ebx, [image]
|
||||
mov ebp, eax
|
||||
call map_PE
|
||||
pop ebp ebx
|
||||
|
||||
mov [entry], eax
|
||||
test eax, eax
|
||||
jnz .cleanup
|
||||
|
||||
stdcall kernel_free, [base]
|
||||
.cleanup:
|
||||
stdcall kernel_free, [image]
|
||||
mov eax, [entry]
|
||||
ret
|
||||
.fail:
|
||||
xor eax, eax
|
||||
ret
|
||||
endp
|
||||
|
||||
map_PE: ;ebp=base:dword, ebx=image:dword
|
||||
push edi
|
||||
push esi
|
||||
sub esp, .locals_size
|
||||
virtual at esp
|
||||
.numsections dd ?
|
||||
.import_names dd ?
|
||||
.import_targets dd ?
|
||||
.peheader dd ?
|
||||
.bad_import dd ?
|
||||
.import_idx dd ?
|
||||
.import_descr dd ?
|
||||
.relocs_rva dd ?
|
||||
.relocs_size dd ?
|
||||
.section_header_size dd ?
|
||||
.AddressOfEntryPoint dd ?
|
||||
.ImageBase dd ?
|
||||
.locals_size = $ - esp
|
||||
end virtual
|
||||
cmp word [ebx], STRIPPED_PE_SIGNATURE
|
||||
jz .stripped
|
||||
|
||||
mov edx, ebx
|
||||
add edx, [ebx+60]
|
||||
movzx eax, word [edx+6]
|
||||
mov [.numsections], eax
|
||||
mov eax, [edx+40]
|
||||
mov [.AddressOfEntryPoint], eax
|
||||
mov eax, [edx+52]
|
||||
mov [.ImageBase], eax
|
||||
mov ecx, [edx+84]
|
||||
mov [.section_header_size], 40
|
||||
mov eax, [edx+128]
|
||||
mov [.import_descr], eax
|
||||
mov eax, [edx+160]
|
||||
mov [.relocs_rva], eax
|
||||
mov eax, [edx+164]
|
||||
mov [.relocs_size], eax
|
||||
add edx, 256
|
||||
|
||||
jmp .common
|
||||
.stripped:
|
||||
mov eax, [ebx+STRIPPED_PE_HEADER.AddressOfEntryPoint]
|
||||
mov [.AddressOfEntryPoint], eax
|
||||
mov eax, [ebx+STRIPPED_PE_HEADER.ImageBase]
|
||||
mov [.ImageBase], eax
|
||||
movzx eax, [ebx+STRIPPED_PE_HEADER.NumberOfSections]
|
||||
mov [.numsections], eax
|
||||
movzx ecx, [ebx+STRIPPED_PE_HEADER.NumberOfRvaAndSizes]
|
||||
xor eax, eax
|
||||
mov [.relocs_rva], eax
|
||||
mov [.relocs_size], eax
|
||||
test ecx, ecx
|
||||
jz @f
|
||||
mov eax, [ebx+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_IMPORT*8]
|
||||
@@:
|
||||
mov [.import_descr], eax
|
||||
cmp ecx, SPE_DIRECTORY_BASERELOC
|
||||
jbe @f
|
||||
mov eax, [ebx+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_BASERELOC*8]
|
||||
mov [.relocs_rva], eax
|
||||
mov eax, [ebx+sizeof.STRIPPED_PE_HEADER+SPE_DIRECTORY_BASERELOC*8+4]
|
||||
mov [.relocs_size], eax
|
||||
@@:
|
||||
mov [.section_header_size], 28
|
||||
lea edx, [ebx+ecx*8+sizeof.STRIPPED_PE_HEADER+8]
|
||||
mov ecx, [ebx+STRIPPED_PE_HEADER.SizeOfHeaders]
|
||||
|
||||
.common:
|
||||
mov esi, ebx
|
||||
mov edi, ebp
|
||||
shr ecx, 2
|
||||
rep movsd
|
||||
|
||||
cmp [.numsections], 0
|
||||
jz .nosections
|
||||
.copy_sections:
|
||||
mov eax, [edx+8]
|
||||
test eax, eax
|
||||
je .no_section_data
|
||||
mov esi, ebx
|
||||
mov edi, ebp
|
||||
add esi, [edx+12]
|
||||
mov ecx, eax
|
||||
add edi, [edx+4]
|
||||
|
||||
add ecx, 3
|
||||
shr ecx, 2
|
||||
rep movsd
|
||||
|
||||
.no_section_data:
|
||||
mov ecx, [edx]
|
||||
cmp ecx, eax
|
||||
jbe .no_section_fill
|
||||
sub ecx, eax
|
||||
add eax, [edx+4]
|
||||
lea edi, [eax+ebp]
|
||||
|
||||
xor eax, eax
|
||||
rep stosb
|
||||
|
||||
.no_section_fill:
|
||||
add edx, [.section_header_size]
|
||||
dec [.numsections]
|
||||
jnz .copy_sections
|
||||
.nosections:
|
||||
cmp [.relocs_size], 0
|
||||
je .no_relocations
|
||||
mov esi, ebp
|
||||
mov ecx, ebp
|
||||
sub esi, [.ImageBase]
|
||||
add ecx, [.relocs_rva]
|
||||
.relocs_block:
|
||||
mov edi, [ecx]
|
||||
add edi, ebp
|
||||
mov ebx, [ecx+4]
|
||||
add ecx, 8
|
||||
sub [.relocs_size], ebx
|
||||
sub ebx, 8
|
||||
shr ebx, 1
|
||||
jz .relocs_next_block
|
||||
.one_reloc:
|
||||
movzx eax, word [ecx]
|
||||
add ecx, 2
|
||||
mov edx, eax
|
||||
shr eax, 12
|
||||
and edx, 4095
|
||||
cmp eax, 3
|
||||
jne @f
|
||||
add [edx+edi], esi
|
||||
@@:
|
||||
dec ebx
|
||||
jnz .one_reloc
|
||||
.relocs_next_block:
|
||||
cmp [.relocs_size], 0
|
||||
jg .relocs_block
|
||||
.no_relocations:
|
||||
cmp [.import_descr], 0
|
||||
je .no_imports
|
||||
add [.import_descr], ebp
|
||||
mov [.bad_import], 0
|
||||
.import_block:
|
||||
mov ecx, [.import_descr]
|
||||
cmp dword [ecx+4], 0
|
||||
jne @f
|
||||
cmp dword [ecx+12], 0
|
||||
je .done_imports
|
||||
@@:
|
||||
mov edx, dword [ecx]
|
||||
mov ecx, dword [ecx+16]
|
||||
test edx, edx
|
||||
jnz @f
|
||||
mov edx, ecx
|
||||
@@:
|
||||
mov [.import_idx], 0
|
||||
add ecx, ebp
|
||||
add edx, ebp
|
||||
mov [.import_names], edx
|
||||
mov [.import_targets], ecx
|
||||
.import_func:
|
||||
mov esi, [.import_idx]
|
||||
mov edi, [.import_names]
|
||||
mov eax, [edi+esi*4]
|
||||
test eax, eax
|
||||
je .next_import_block
|
||||
js .next_import_block
|
||||
lea edi, [ebp+eax]
|
||||
mov eax, [.import_targets]
|
||||
mov dword [eax+esi*4], 0
|
||||
lea esi, [edi+2]
|
||||
movzx ebx, word [edi]
|
||||
push 32
|
||||
mov ecx, [__exports+32]
|
||||
mov eax, [ecx+OS_BASE+ebx*4]
|
||||
add eax, OS_BASE
|
||||
push eax
|
||||
push esi
|
||||
call strncmp
|
||||
test eax, eax
|
||||
jz .import_func_found
|
||||
xor ebx, ebx
|
||||
.import_func_candidate:
|
||||
push 32
|
||||
mov ecx, [__exports+32]
|
||||
mov eax, [ecx+OS_BASE+ebx*4]
|
||||
add eax, OS_BASE
|
||||
push eax
|
||||
push esi
|
||||
call strncmp
|
||||
test eax, eax
|
||||
je .import_func_found
|
||||
inc ebx
|
||||
cmp ebx, [__exports+24]
|
||||
jb .import_func_candidate
|
||||
|
||||
mov esi, msg_unresolved
|
||||
call sys_msg_board_str
|
||||
lea esi, [edi+2]
|
||||
call sys_msg_board_str
|
||||
mov esi, msg_CR
|
||||
call sys_msg_board_str
|
||||
|
||||
mov [.bad_import], 1
|
||||
jmp .next_import_func
|
||||
.import_func_found:
|
||||
mov esi, [__exports+28]
|
||||
mov edx, [.import_idx]
|
||||
mov ecx, [.import_targets]
|
||||
mov eax, [esi+OS_BASE+ebx*4]
|
||||
add eax, OS_BASE
|
||||
mov [ecx+edx*4], eax
|
||||
.next_import_func:
|
||||
inc [.import_idx]
|
||||
jmp .import_func
|
||||
.next_import_block:
|
||||
add [.import_descr], 20
|
||||
jmp .import_block
|
||||
.done_imports:
|
||||
xor eax, eax
|
||||
cmp [.bad_import], 0
|
||||
jne @f
|
||||
.no_imports:
|
||||
mov eax, ebp
|
||||
add eax, [.AddressOfEntryPoint]
|
||||
@@:
|
||||
add esp, .locals_size
|
||||
pop esi
|
||||
pop edi
|
||||
ret
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user