[KERNEL] Get ready to apply CleverMouse PE patch

git-svn-id: svn://kolibrios.org@9047 a494cfbc-eb01-0410-851d-a64ba20cac60
This commit is contained in:
2021-07-09 19:19:04 +00:00
parent ced10e8541
commit 360e379fc7
238 changed files with 124759 additions and 0 deletions

View 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.

View 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

View 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")

View 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

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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
;--------------------------------------------------------------------

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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
;=============================================================================
;=============================================================================
;=============================================================================

View 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"

View 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

View 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

View 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:

View 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

View 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

View 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:

View 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")

View 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

View File

@@ -0,0 +1,2 @@
if tup.getconfig("NO_FASM") ~= "" then return end
tup.rule("kordldr.win.asm", "fasm %f %o", "kordldr.win.bin")

View File

@@ -0,0 +1,2 @@
@fasm -m 65535 kordldr.win.asm kordldr.win
@pause

View File

@@ -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

View File

@@ -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

View File

@@ -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. Добавляет сектор в конец списка (самый новый вход).

View File

@@ -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

View File

@@ -0,0 +1,2 @@
if tup.getconfig("NO_FASM") ~= "" then return end
tup.rule("bootsect.asm", "fasm %f %o ", "bootsect.bin")

View File

@@ -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. Если же нет, то считываются все сектора, кроме последнего, после чего
последний сектор считывается отдельно во временную область, и уже
оттуда нужная часть данных копируется в буфер.

View File

@@ -0,0 +1,2 @@
@fasm -m 65535 bootsect.asm bootsect.bin
@pause

View File

@@ -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

View File

@@ -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")

View File

@@ -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

View File

@@ -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.

View File

@@ -0,0 +1,3 @@
@fasm -m 65535 bootsect.asm bootsect.bin
@fasm -m 65535 kordldr.f1x.asm kordldr.f1x
@pause

View File

@@ -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

View File

@@ -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")

View File

@@ -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

View File

@@ -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.

View File

@@ -0,0 +1,3 @@
@fasm -m 65535 bootsect.asm bootsect.bin
@fasm -m 65535 kordldr.f32.asm kordldr.f32
@pause

View File

@@ -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

View 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)

View 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)

View 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)

View 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)

View 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:

View 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

View File

@@ -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")

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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
}

View 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 >>>>>>>>>

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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"

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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")

View 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

View 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
;------------------------------------------------------------------------------

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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
}

View File

@@ -0,0 +1,141 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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', \
\
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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View File

@@ -0,0 +1,434 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;;
;; Distributed under terms of the GNU General Public License ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
$Revision$
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; IRQ0 HANDLER (TIMER INTERRUPT) ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 32
irq0:
pushad
mov ax, app_data
mov ds, ax
mov es, ax
inc [timer_ticks]
mov eax, [timer_ticks]
call playNote ; <<<--- Speaker driver
sub eax, [next_usage_update]
cmp eax, 100
jb .nocounter
add [next_usage_update], 100
call updatecputimes
.nocounter:
xor ecx, ecx ; send End Of Interrupt signal
call irq_eoi
mov bl, SCHEDULE_ANY_PRIORITY
call find_next_task
jz .return ; if there is only one running process
call do_change_task
.return:
popad
iretd
align 4
change_task:
pushfd
cli
pushad
mov bl, SCHEDULE_ANY_PRIORITY
call find_next_task
jz .return ; the same task -> skip switch
call do_change_task
.return:
popad
popfd
ret
uglobal
align 4
; far_jump:
; .offs dd ?
; .sel dw ?
context_counter dd 0 ;noname & halyavin
next_usage_update dd 0
timer_ticks dd 0
; prev_slot dd ?
; event_sched dd ?
endg
align 4
update_counters:
mov edi, [TASK_BASE]
rdtsc
sub eax, [edi+TASKDATA.counter_add] ; time stamp counter add
add [edi+TASKDATA.counter_sum], eax ; counter sum
ret
align 4
updatecputimes:
mov ecx, [thread_count]
mov edi, TASK_DATA
.newupdate:
xor eax, eax
xchg eax, [edi+TASKDATA.counter_sum]
mov [edi+TASKDATA.cpu_usage], eax
add edi, 0x20
loop .newupdate
ret
;TODO: Надо бы убрать использование do_change_task из V86...
; и после этого перенести обработку TASKDATA.counter_add/sum в do_change_task
align 4
do_change_task:
;param:
; ebx = address of the APPDATA for incoming task (new)
;warning:
; [current_slot_idx] and [TASK_BASE] must be changed before (e.g. in find_next_task)
; [current_slot] is the outcoming (old), and set here to a new value (ebx)
;scratched: eax,ecx,esi
mov esi, ebx
xchg esi, [current_slot]
; set new stack after saving old
mov [esi+APPDATA.saved_esp], esp
mov esp, [ebx+APPDATA.saved_esp]
; set new thread io-map
mov eax, [ebx+APPDATA.io_map]
mov dword [page_tabs+((tss._io_map_0 and -4096) shr 10)], eax
mov eax, [ebx+APPDATA.io_map+4]
mov dword [page_tabs+((tss._io_map_1 and -4096) shr 10)], eax
; set new thread memory-map
mov eax, [ebx+APPDATA.process]
cmp eax, [current_process]
je @f
mov [current_process], eax
mov eax, [eax+PROC.pdt_0_phys]
mov cr3, eax
@@:
; set tss.esp0
mov eax, [ebx+APPDATA.saved_esp0]
mov [tss._esp0], eax
mov edx, [ebx+APPDATA.tls_base]
mov [tls_data_l+2], dx
shr edx, 16
mov [tls_data_l+4], dl
mov [tls_data_l+7], dh
mov dx, app_tls
mov fs, dx
; set gs selector unconditionally
Mov ax, graph_data
Mov gs, ax
; TS flag is not triggered by AVX* instructions, therefore
; we have to xsave/xrstor SIMD registers each task change
bt [cpu_caps+(CAPS_OSXSAVE/32)*4], CAPS_OSXSAVE mod 32
jnc .no_xsave
mov ecx, [esi+APPDATA.fpu_state]
mov eax, [xsave_eax]
mov edx, [xsave_edx]
xsave [ecx]
mov ecx, [current_slot_idx]
mov [fpu_owner], ecx
mov ecx, [current_slot]
mov ecx, [ecx+APPDATA.fpu_state]
xrstor [ecx]
.no_xsave:
; set CR0.TS
cmp bh, byte[fpu_owner] ;bh == incoming task (new)
clts ;clear a task switch flag
je @f
mov eax, cr0 ;and set it again if the owner
or eax, CR0_TS ;of a fpu has changed
mov cr0, eax
@@: ; set context_counter (only for user pleasure ???)
inc [context_counter] ;noname & halyavin
; set debug-registers, if it's necessary
test byte[ebx+APPDATA.dbg_state], 1
jz @f
xor eax, eax
mov dr6, eax
lea esi, [ebx+APPDATA.dbg_regs]
cld
macro lodsReg [reg] {
lodsd
mov reg, eax
} lodsReg dr0, dr1, dr2, dr3, dr7
purge lodsReg
@@:
ret
;end.
MAX_PRIORITY = 0 ; highest, used for kernel tasks
USER_PRIORITY = 1 ; default
IDLE_PRIORITY = 2 ; lowest, only IDLE thread goes here
NR_SCHED_QUEUES = 3 ; MUST equal IDLE_PRIORYTY + 1
uglobal
; [scheduler_current + i*4] = zero if there are no threads with priority i,
; pointer to APPDATA of the current thread with priority i otherwise.
align 4
scheduler_current rd NR_SCHED_QUEUES
endg
; Add the given thread to the given priority list for the scheduler.
; in: edx -> APPDATA, ecx = priority
proc scheduler_add_thread
; 1. Acquire the lock.
spin_lock_irqsave SchedulerLock
; 2. Store the priority in APPDATA structure.
mov [edx+APPDATA.priority], ecx
; 3. There are two different cases: the given list is empty or not empty.
; In first case, go to 6. Otherwise, advance to 4.
mov eax, [scheduler_current+ecx*4]
test eax, eax
jz .new_list
; 4. Insert the new item immediately before the current item.
mov ecx, [eax+APPDATA.in_schedule.prev]
mov [edx+APPDATA.in_schedule.next], eax
mov [edx+APPDATA.in_schedule.prev], ecx
mov [eax+APPDATA.in_schedule.prev], edx
mov [ecx+APPDATA.in_schedule.next], edx
; 5. Release the lock and return.
spin_unlock_irqrestore SchedulerLock
ret
.new_list:
; 6. Initialize the list with one item and make it the current item.
mov [edx+APPDATA.in_schedule.next], edx
mov [edx+APPDATA.in_schedule.prev], edx
mov [scheduler_current+ecx*4], edx
; 7. Release the lock and return.
spin_unlock_irqrestore SchedulerLock
ret
endp
; Remove the given thread from the corresponding priority list for the scheduler.
; in: edx -> APPDATA
proc scheduler_remove_thread
; 1. Acquire the lock.
spin_lock_irqsave SchedulerLock
; 2. Remove the item from the corresponding list.
mov eax, [edx+APPDATA.in_schedule.next]
mov ecx, [edx+APPDATA.in_schedule.prev]
mov [eax+APPDATA.in_schedule.prev], ecx
mov [ecx+APPDATA.in_schedule.next], eax
; 3. If the given thread is the current item in the list,
; advance the current item.
; 3a. Check whether the given thread is the current item;
; if no, skip the rest of this step.
mov ecx, [edx+APPDATA.priority]
cmp [scheduler_current+ecx*4], edx
jnz .return
; 3b. Set the current item to eax; step 2 has set eax = next item.
mov [scheduler_current+ecx*4], eax
; 3c. If there were only one item in the list, zero the current item.
cmp eax, edx
jnz .return
mov [scheduler_current+ecx*4], 0
.return:
; 4. Release the lock and return.
spin_unlock_irqrestore SchedulerLock
ret
endp
SCHEDULE_ANY_PRIORITY = 0
SCHEDULE_HIGHER_PRIORITY = 1
;info:
; Find next task to execute
;in:
; bl = SCHEDULE_ANY_PRIORITY:
; consider threads with any priority
; bl = SCHEDULE_HIGHER_PRIORITY:
; consider only threads with strictly higher priority than the current one,
; keep running the current thread if other ready threads have the same or lower priority
;retval:
; ebx = address of the APPDATA for the selected task (slot-base)
; edi = address of the TASKDATA for the selected task
; ZF = 1 if the task is the same
;warning:
; [current_slot_idx] = bh , [TASK_BASE] = edi -- as result
; [current_slot] is not set to new value (ebx)!!!
;scratched: eax,ecx
proc find_next_task
call update_counters
spin_lock_irqsave SchedulerLock
push NR_SCHED_QUEUES
; If bl == SCHEDULE_ANY_PRIORITY = 0, loop over all NR_SCHED lists.
; Otherwise, loop over first [APPDATA.priority] lists.
test bl, bl
jz .start
mov ebx, [current_slot]
mov edi, [TASK_BASE]
mov eax, [ebx+APPDATA.priority]
test eax, eax
jz .unlock_found
mov [esp], eax
.start:
xor ecx, ecx
.priority_loop:
mov ebx, [scheduler_current+ecx*4]
test ebx, ebx
jz .priority_next
.task_loop:
mov ebx, [ebx+APPDATA.in_schedule.next]
mov edi, ebx
shr edi, 3
add edi, TASK_TABLE - (SLOT_BASE shr 3)
mov al, [edi+TASKDATA.state]
test al, al
jz .task_found ; state == 0
cmp al, 5
jne .task_next ; state == 1,2,3,4,9
; state == 5
pushad ; more freedom for [APPDATA.wait_test]
call [ebx+APPDATA.wait_test]
mov [esp+28], eax
popad
or eax, eax
jnz @f
; testing for timeout
mov eax, [timer_ticks]
sub eax, [ebx+APPDATA.wait_begin]
cmp eax, [ebx+APPDATA.wait_timeout]
jb .task_next
xor eax, eax
@@:
mov [ebx+APPDATA.wait_param], eax ; retval for wait
mov [edi+TASKDATA.state], TSTATE_RUNNING
.task_found:
mov [scheduler_current+ecx*4], ebx
; If we have selected a thread with higher priority
; AND rescheduling is due to IRQ,
; turn the current scheduler list one entry back,
; so the current thread will be next after high-priority thread is done.
mov ecx, [esp]
cmp ecx, NR_SCHED_QUEUES
jz .unlock_found
mov eax, [current_slot]
mov eax, [eax+APPDATA.in_schedule.prev]
mov [scheduler_current+ecx*4], eax
.unlock_found:
pop ecx
spin_unlock_irqrestore SchedulerLock
.found:
; the line below assumes APPDATA is 256 bytes long and SLOT_BASE is
; aligned on 0x10000
mov byte [current_slot_idx], bh
mov [TASK_BASE], edi
rdtsc ;call _rdtsc
mov [edi+TASKDATA.counter_add], eax; for next using update_counters
cmp ebx, [current_slot]
ret
.task_next:
cmp ebx, [scheduler_current+ecx*4]
jnz .task_loop
.priority_next:
inc ecx
cmp ecx, [esp]
jb .priority_loop
mov ebx, [current_slot]
mov edi, [TASK_BASE]
jmp .unlock_found
endp
if 0
struc TIMER
{
.next dd ?
.exp_time dd ?
.func dd ?
.arg dd ?
}
uglobal
rdy_head rd 16
endg
align 4
pick_task:
xor eax, eax
.pick:
mov ebx, [rdy_head+eax*4]
test ebx, ebx
jz .next
mov [next_task], ebx
test [ebx+flags.billable]
jz @F
mov [bill_task], ebx
@@:
ret
.next:
inc eax
jmp .pick
; param
; eax= task
;
; retval
; eax= task
; ebx= queue
; ecx= front if 1 or back if 0
align 4
shed:
cmp [eax+.tics_left], 0;signed compare
mov ebx, [eax+.priority]
setg ecx
jg @F
mov edx, [eax+.tics_quantum]
mov [eax+.ticks_left], edx
cmp ebx, (IDLE_PRIORITY-1)
je @F
inc ebx
@@:
ret
; param
; eax= task
align 4
enqueue:
call shed;eax
cmp [rdy_head+ebx*4], 0
jnz @F
mov [rdy_head+ebx*4], eax
mov [rdy_tail+ebx*4], eax
mov [eax+.next_ready], 0
jmp .pick
@@:
test ecx, ecx
jz .back
mov ecx, [rdy_head+ebx*4]
mov [eax+.next_ready], ecx
mov [rdy_head+ebx*4], eax
jmp .pick
.back:
mov ecx, [rdy_tail+ebx*4]
mov [ecx+.next_ready], eax
mov [rdy_tail+ebx*4], eax
mov [eax+.next_ready], 0
.pick:
call pick_proc;select next task
ret
end if

Some files were not shown because too many files have changed in this diff Show More