Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 9046 → Rev 9047

/kernel/branches/kolibrios-pe-clevermouse/blkdev/disk.inc
0,0 → 1,1666
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2011-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; =============================================================================
; ================================= Constants =================================
; =============================================================================
; Error codes for callback functions.
DISK_STATUS_OK = 0 ; success
DISK_STATUS_GENERAL_ERROR = -1; if no other code is suitable
DISK_STATUS_INVALID_CALL = 1 ; invalid input parameters
DISK_STATUS_NO_MEDIA = 2 ; no media present
DISK_STATUS_END_OF_MEDIA = 3 ; end of media while reading/writing data
DISK_STATUS_NO_MEMORY = 4 ; insufficient memory for driver operation
; Driver flags. Represent bits in DISK.DriverFlags.
DISK_NO_INSERT_NOTIFICATION = 1
; Media flags. Represent bits in DISKMEDIAINFO.Flags.
DISK_MEDIA_READONLY = 1
 
; If too many partitions are detected,there is probably an error on the disk.
; 256 partitions should be enough for any reasonable use.
; Also, the same number is limiting the number of MBRs to process; if
; too many MBRs are visible,there probably is a loop in the MBR structure.
MAX_NUM_PARTITIONS = 256
 
; =============================================================================
; ================================ Structures =================================
; =============================================================================
; This structure defines all callback functions for working with the physical
; device. They are implemented by a driver. Objects with this structure reside
; in a driver.
struct DISKFUNC
strucsize dd ?
; Size of the structure. This field is intended for possible extensions of
; this structure. If a new function is added to this structure and a driver
; implements an old version, the caller can detect this by checking .strucsize,
; so the driver remains compatible.
close dd ?
; The pointer to the function which frees all driver-specific resources for
; the disk.
; Optional, may be NULL.
; void close(void* userdata);
closemedia dd ?
; The pointer to the function which informs the driver that the kernel has
; finished all processing with the current media. If media is removed, the
; driver should decline all requests to that media with DISK_STATUS_NO_MEDIA,
; even if new media is inserted, until this function is called. If media is
; removed, a new call to 'disk_media_changed' is not allowed until this
; function is called.
; Optional, may be NULL (if media is not removable).
; void closemedia(void* userdata);
querymedia dd ?
; The pointer to the function which determines capabilities of the media.
; int querymedia(void* userdata, DISKMEDIAINFO* info);
; Return value: one of DISK_STATUS_*
read dd ?
; The pointer to the function which reads data from the device.
; int read(void* userdata, void* buffer, __int64 startsector, int* numsectors);
; input: *numsectors = number of sectors to read
; output: *numsectors = number of sectors which were successfully read
; Return value: one of DISK_STATUS_*
write dd ?
; The pointer to the function which writes data to the device.
; Optional, may be NULL.
; int write(void* userdata, void* buffer, __int64 startsector, int* numsectors);
; input: *numsectors = number of sectors to write
; output: *numsectors = number of sectors which were successfully written
; Return value: one of DISK_STATUS_*
flush dd ?
; The pointer to the function which flushes the internal device cache.
; Optional, may be NULL.
; int flush(void* userdata);
; Return value: one of DISK_STATUS_*
; Note that read/write are called by the cache manager, so a driver should not
; create a software cache. This function is implemented for flushing a hardware
; cache, if it exists.
adjust_cache_size dd ?
; The pointer to the function which returns the cache size for this device.
; Optional, may be NULL.
; unsigned int adjust_cache_size(void* userdata, unsigned int suggested_size);
; Return value: 0 = disable cache, otherwise = used cache size in bytes.
ends
 
; This structure holds information on a medium.
; Objects with this structure are allocated by the kernel as a part of the DISK
; structure and are filled by a driver in the 'querymedia' callback.
struct DISKMEDIAINFO
Flags dd ?
; Combination of DISK_MEDIA_* bits.
SectorSize dd ?
; Size of the sector.
Capacity dq ?
; Size of the media in sectors.
ends
 
; This structure represents the disk cache. To follow the old implementation,
; there are two distinct caches for a disk, one for "system" data,and the other
; for "application" data.
struct DISKCACHE
; The following fields are inherited from data32.inc:cache_ideX.
pointer dd ?
data_size dd ? ; unused
data dd ?
sad_size dd ?
search_start dd ?
sector_size_log dd ?
ends
 
; This structure represents a disk device and its media for the kernel.
; This structure is allocated by the kernel in the 'disk_add' function,
; freed in the 'disk_dereference' function.
struct DISK
; Fields of disk object
Next dd ?
Prev dd ?
; All disk devices are linked in one list with these two fields.
; Head of the list is the 'disk_list' variable.
Functions dd ?
; Pointer to the 'DISKFUNC' structure with driver functions.
Name dd ?
; Pointer to the string used for accesses through the global filesystem.
UserData dd ?
; This field is passed to all callback functions so a driver can decide which
; physical device is addressed.
DriverFlags dd ?
; Bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit is defined.
; If it is set, the driver will never issue 'disk_media_changed' notification
; with argument set to true, so the kernel must try to detect media during
; requests from the file system.
RefCount dd ?
; Count of active references to this structure. One reference is kept during
; the lifetime of the structure between 'disk_add' and 'disk_del'.
; Another reference is taken during any filesystem operation for this disk.
; One reference is added if media is inserted.
; The structure is destroyed when the reference count decrements to zero:
; this usually occurs in 'disk_del', but can be delayed to the end of last
; filesystem operation, if one is active.
MediaLock MUTEX
; Lock to protect the MEDIA structure. See the description after
; 'disk_list_mutex' for the locking strategy.
; Fields of media object
MediaInserted db ?
; 0 if media is not inserted, nonzero otherwise.
MediaUsed db ?
; 0 if media fields are not used, nonzero otherwise. If .MediaRefCount is
; nonzero, this field is nonzero too; however, when .MediaRefCount goes
; to zero, there is some time interval during which media object is still used.
dw ? ; padding
; The following fields are not valid unless either .MediaInserted is nonzero
; or they are accessed from a code which has obtained the reference when
; .MediaInserted was nonzero.
MediaRefCount dd ?
; Count of active references to the media object. One reference is kept during
; the lifetime of the media between two calls to 'disk_media_changed'.
; Another reference is taken during any filesystem operation for this media.
; The callback 'closemedia' is called when the reference count decrements to
; zero: this usually occurs in 'disk_media_changed', but can be delayed to the
; end of the last filesystem operation, if one is active.
MediaInfo DISKMEDIAINFO
; This field keeps information on the current media.
NumPartitions dd ?
; Number of partitions on this media.
Partitions dd ?
; Pointer to array of .NumPartitions pointers to PARTITION structures.
cache_size dd ?
; inherited from cache_ideX_size
CacheLock MUTEX
; Lock to protect both caches.
SysCache DISKCACHE
AppCache DISKCACHE
; Two caches for the disk.
ends
 
; This structure represents one partition for the kernel. This is a base
; template, the actual contents after common fields is determined by the
; file system code for this partition.
struct PARTITION
FirstSector dq ?
; First sector of the partition.
Length dq ?
; Length of the partition in sectors.
Disk dd ?
; Pointer to parent DISK structure.
FSUserFunctions dd ?
; Handlers for the sysfunction 70h. This field is a pointer to the following
; array. The first dword is pointer to disconnect handler.
; The first dword is a number of supported subfunctions, other dwords
; point to handlers of corresponding subfunctions.
; ...fs-specific data may follow...
ends
 
; This is an external structure, it represents an entry in the partition table.
struct PARTITION_TABLE_ENTRY
Bootable db ?
; 80h = bootable partition, 0 = non-bootable partition, other values = invalid
FirstHead db ?
FirstSector db ?
FirstTrack db ?
; Coordinates of first sector in CHS.
Type db ?
; Partition type, one of predefined constants. 0 = empty, several types denote
; extended partition (see process_partition_table_entry), we are not interested
; in other values.
LastHead db ?
LastSector db ?
LastTrack db ?
; Coordinates of last sector in CHS.
FirstAbsSector dd ?
; Coordinate of first sector in LBA.
Length dd ?
; Length of the partition in sectors.
ends
 
; GUID Partition Table Header, UEFI 2.6, Table 18
struct GPTH
Signature rb 8
; 'EFI PART'
Revision dd ?
; 0x00010000
HeaderSize dd ?
; Size of this header in bytes, must fit to one sector.
HeaderCRC32 dd ?
; Set this field to zero, compute CRC32 via 0xEDB88320, compare.
Reserved dd ?
; Must be zero.
MyLBA dq ?
; LBA of the sector containing this GPT header.
AlternateLBA dq ?
; LBA of the sector containing the other GPT header.
; AlternateLBA of Primary GPTH points to Backup one and vice versa.
FirstUsableLBA dq ?
; Only sectors between first and last UsableLBA may form partitions
LastUsableLBA dq ?
DiskGUID rb 16
; Globally Unique IDentifier
PartitionEntryLBA dq ?
; First LBA of Partition Entry Array.
; Length in bytes is computed as a product of two following fields.
NumberOfPartitionEntries dd ?
; Actual number of partitions depends on the contents of Partition Entry Array.
; A partition entry is unused if zeroed.
SizeOfPartitionEntry dd ? ; in bytes
PartitionEntryArrayCRC32 dd ?
; Same CRC as for GPT header.
ends
 
; GPT Partition Entry, UEFI 2.6, Table 19
struct GPE
PartitionTypeGUID rb 16
UniquePartitionGUID rb 16
StartingLBA dq ?
EndingLBA dq ?
; Length in sectors is EndingLBA - StartingLBA + 1.
Attributes dq ?
PartitionName rb 72
ends
 
; =============================================================================
; ================================ Global data ================================
; =============================================================================
iglobal
; The pseudo-item for the list of all DISK structures.
; Initialized to the empty list.
disk_list:
dd disk_list
dd disk_list
endg
uglobal
; This mutex guards all operations with the global list of DISK structures.
disk_list_mutex MUTEX
; * There are two dependent objects, a disk and a media. In the simplest case,
; disk and media are both non-removable. However, in the general case both
; can be removed at any time, simultaneously or only media,and this makes things
; complicated.
; * For efficiency, both disk and media objects are located in the one
; structure named DISK. However, logically they are different.
; * The following operations use data of disk object: adding (disk_add);
; deleting (disk_del); filesystem (fs_lfn which eventually calls
; dyndisk_handler or dyndisk_enum_root).
; * The following operations use data of media object: adding/removing
; (disk_media_changed); filesystem (fs_lfn which eventually calls
; dyndisk_handler; dyndisk_enum_root doesn't work with media).
; * Notifications disk_add, disk_media_changed, disk_del are synchronized
; between themselves, this is a requirement for the driver. However, file
; system operations are asynchronous, can be issued at any time by any
; thread.
; * We must prevent a situation when a filesystem operation thinks that the
; object is still valid but in fact the notification has destroyed the
; object. So we keep a reference counter for both disk and media and destroy
; the object when this counter goes to zero.
; * The driver must know when it is safe to free driver-allocated resources.
; The object can be alive even after death notification has completed.
; We use special callbacks to satisfy both assertions: 'close' for the disk
; and 'closemedia' for the media. The destruction of the object includes
; calling the corresponding callback.
; * Each filesystem operation keeps one reference for the disk and one
; reference for the media. Notification disk_del forces notification on the
; media death, so the reference counter for the disk is always not less than
; the reference counter for the media.
; * Two operations "get the object" and "increment the reference counter" can
; not be done simultaneously. We use a mutex to guard the consistency here.
; It must be a part of the container for the object, so that this mutex can
; be acquired as a part of getting the object from the container. The
; container for disk object is the global list, and this list is guarded by
; 'disk_list_mutex'. The container for media object is the disk object, and
; the corresponding mutex is DISK.MediaLock.
; * Notifications do not change the data of objects, they can only remove
; objects. Thus we don't need another synchronization at this level. If two
; filesystem operations are referencing the same filesystem data, this is
; better resolved at the level of the filesystem.
endg
 
iglobal
; The function 'disk_scan_partitions' needs three sector-sized buffers for
; MBR, bootsector and fs-temporary sector data. It can not use the static
; buffers always, since it can be called for two or more disks in parallel.
; However, this case is not typical. We reserve three static 512-byte buffers
; and a flag that these buffers are currently used. If 'disk_scan_partitions'
; detects that the buffers are currently used, it allocates buffers from the
; heap. Also, the heap is used when sector size is other than 512.
; The flag is implemented as a global dword variable. When the static buffers
; are not used, the value is -1. When the static buffers are used, the value
; is normally 0 and temporarily can become greater. The function increments
; this value. If the resulting value is zero, it uses the buffers and
; decrements the value when the job is done. Otherwise, it immediately
; decrements the value and uses buffers from the heap, allocated in the
; beginning and freed in the end.
partition_buffer_users dd -1
endg
uglobal
; The static buffers for MBR, bootsector and fs-temporary sector data.
align 16
mbr_buffer rb 512
bootsect_buffer rb 512
fs_tmp_buffer rb 512
endg
 
iglobal
; This is the array of default implementations of driver callbacks.
; Same as DRIVERFUNC structure except for the first field; all functions must
; have the default implementations.
align 4
disk_default_callbacks:
dd disk_default_close
dd disk_default_closemedia
dd disk_default_querymedia
dd disk_default_read
dd disk_default_write
dd disk_default_flush
dd disk_default_adjust_cache_size
endg
 
; =============================================================================
; ================================= Functions =================================
; =============================================================================
 
; This function registers a disk device.
; This includes:
; - allocating an internal structure describing this device;
; - registering this structure in the global filesystem.
; The function initializes the disk as if there is no media. If a media is
; present, the function 'disk_media_changed' should be called after this
; function succeeds.
; Parameters:
; [esp+4] = pointer to DISKFUNC structure with the callbacks
; [esp+8] = pointer to name (ASCIIZ string)
; [esp+12] = userdata to be passed to the callbacks as is.
; [esp+16] = flags, bitfield. Currently only DISK_NO_INSERT_NOTIFICATION bit
; is defined.
; Return value:
; NULL = operation has failed
; non-NULL = handle of the disk. This handle can be used
; in the operations with other Disk* functions.
; The handle is the pointer to the internal structure DISK.
disk_add:
push ebx esi ; save used registers to be stdcall
; 1. Allocate the DISK structure.
; 1a. Call the heap manager.
movi eax, sizeof.DISK
call malloc
; 1b. Check the result. If allocation failed, return (go to 9) with eax = 0.
test eax, eax
jz .nothing
; 2. Copy the disk name to the DISK structure.
; 2a. Get length of the name, including the terminating zero.
mov ebx, [esp+8+8] ; ebx = pointer to name
push eax ; save allocated pointer to DISK
xor eax, eax ; the argument of malloc() is in eax
@@:
inc eax
cmp byte [ebx+eax-1], 0
jnz @b
; 2b. Call the heap manager.
call malloc
; 2c. Check the result. If allocation failed, go to 7.
pop esi ; restore allocated pointer to DISK
test eax, eax
jz .free
; 2d. Store the allocated pointer to the DISK structure.
mov [esi+DISK.Name], eax
; 2e. Copy the name.
@@:
mov dl, [ebx]
mov [eax], dl
inc ebx
inc eax
test dl, dl
jnz @b
; 3. Copy other arguments of the function to the DISK structure.
mov eax, [esp+4+8]
mov [esi+DISK.Functions], eax
mov eax, [esp+12+8]
mov [esi+DISK.UserData], eax
mov eax, [esp+16+8]
mov [esi+DISK.DriverFlags], eax
; 4. Initialize other fields of the DISK structure.
; Media is not inserted, reference counter is 1.
lea ecx, [esi+DISK.MediaLock]
call mutex_init
xor eax, eax
mov dword [esi+DISK.MediaInserted], eax
mov [esi+DISK.MediaRefCount], eax
inc eax
mov [esi+DISK.RefCount], eax
; The DISK structure is initialized.
; 5. Insert the new structure to the global list.
; 5a. Acquire the mutex.
mov ecx, disk_list_mutex
call mutex_lock
; 5b. Insert item to the tail of double-linked list.
mov edx, disk_list
list_add_tail esi, edx ;esi= new edx= list head
; 5c. Release the mutex.
call mutex_unlock
; 6. Return with eax = pointer to DISK.
xchg eax, esi
jmp .nothing
.free:
; Memory allocation for DISK structure succeeded, but for disk name failed.
; 7. Free the DISK structure.
xchg eax, esi
call free
; 8. Return with eax = 0.
xor eax, eax
.nothing:
; 9. Return.
pop esi ebx ; restore used registers to be stdcall
ret 16 ; purge 4 dword arguments to be stdcall
 
; This function deletes a disk device from the global filesystem.
; This includes:
; - removing a media including all partitions;
; - deleting this structure from the global filesystem;
; - dereferencing the DISK structure and possibly destroying it.
; Parameters:
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
; Return value: none.
disk_del:
push esi ; save used registers to be stdcall
; 1. Force media to be removed. If the media is already removed, the
; call does nothing.
mov esi, [esp+4+4] ; esi = handle of the disk
stdcall disk_media_changed, esi, 0
; 2. Delete the structure from the global list.
; 2a. Acquire the mutex.
mov ecx, disk_list_mutex
call mutex_lock
; 2b. Delete item from double-linked list.
mov eax, [esi+DISK.Next]
mov edx, [esi+DISK.Prev]
mov [eax+DISK.Prev], edx
mov [edx+DISK.Next], eax
; 2c. Release the mutex.
call mutex_unlock
; 3. The structure still has one reference created in disk_add. Remove this
; reference. If there are no other references, disk_dereference will free the
; structure.
call disk_dereference
; 4. Return.
pop esi ; restore used registers to be stdcall
ret 4 ; purge 1 dword argument to be stdcall
 
; This is an internal function which removes a previously obtained reference
; to the disk. If this is the last reference, this function lets the driver
; finalize all associated data, and afterwards frees the DISK structure.
; esi = pointer to DISK structure
disk_dereference:
; 1. Decrement reference counter. Use atomic operation to correctly handle
; possible simultaneous calls.
lock dec [esi+DISK.RefCount]
; 2. If the result is nonzero, there are other references, so nothing to do.
; In this case, return (go to 4).
jnz .nothing
; 3. If we are here, we just removed the last reference and must destroy the
; disk object.
; 3a. Call the driver.
mov al, DISKFUNC.close
stdcall disk_call_driver
; 3b. Free the structure.
xchg eax, esi
push ebx
call free
pop ebx
; 4. Return.
.nothing:
ret
 
; This is an internal function which removes a previously obtained reference
; to the media. If this is the last reference, this function calls 'closemedia'
; callback to signal the driver that the processing has finished and it is safe
; to inform about a new media.
; esi = pointer to DISK structure
disk_media_dereference:
; 1. Decrement reference counter. Use atomic operation to correctly handle
; possible simultaneous calls.
lock dec [esi+DISK.MediaRefCount]
; 2. If the result is nonzero, there are other references, so nothing to do.
; In this case, return (go to 4).
jnz .nothing
; 3. If we are here, we just removed the last reference and must destroy the
; media object.
; Note that the same place inside the DISK structure is reused for all media
; objects, so we must guarantee that reusing does not happen while freeing.
; Reusing is only possible when someone processes a new media. There are two
; mutually exclusive variants:
; * driver issues media insert notifications (DISK_NO_INSERT_NOTIFICATION bit
; in DISK.DriverFlags is not set). In this case, we require from the driver
; that such notification (except for the first one) can occur only after a
; call to 'closemedia' callback.
; * driver does not issue media insert notifications. In this case, the kernel
; itself must sometimes check whether media is inserted. We have the flag
; DISK.MediaUsed, visible to the kernel. This flag signals to the other parts
; of kernel that the way is free.
; In the first case other parts of the kernel do not use DISK.MediaUsed, so it
; does not matter when this flag is cleared. In the second case this flag must
; be cleared after all other actions, including call to 'closemedia'.
; 3a. Free all partitions.
push esi edi
mov edi, [esi+DISK.NumPartitions]
mov esi, [esi+DISK.Partitions]
test edi, edi
jz .nofree
.freeloop:
lodsd
mov ecx, [eax+PARTITION.FSUserFunctions]
call dword [ecx]
dec edi
jnz .freeloop
.nofree:
pop edi esi
; 3b. Free the cache.
call disk_free_cache
; 3c. Call the driver.
mov al, DISKFUNC.closemedia
stdcall disk_call_driver
; 3d. Clear the flag.
mov [esi+DISK.MediaUsed], 0
.nothing:
ret
 
; This function is called by the driver and informs the kernel that the media
; has changed. If the media is non-removable, it is called exactly once
; immediately after 'disk_add' and once from 'disk_del'.
; Parameters:
; [esp+4] = handle of the disk, i.e. the pointer to the DISK structure.
; [esp+8] = new status of the media: zero = no media, nonzero = media inserted.
disk_media_changed:
push ebx esi edi ; save used registers to be stdcall
; 1. Remove the existing media, if it is present.
mov esi, [esp+4+12] ; esi = pointer to DISK
; 1a. Check whether it is present. Since DISK.MediaInserted is changed only
; in this function and calls to this function are synchronized, no lock is
; required for checking.
cmp [esi+DISK.MediaInserted], 0
jz .noremove
; We really need to remove the media.
; 1b. Acquire mutex.
lea ecx, [esi+DISK.MediaLock]
call mutex_lock
; 1c. Clear the flag.
mov [esi+DISK.MediaInserted], 0
; 1d. Release mutex.
call mutex_unlock
; 1e. Remove the "lifetime" reference and possibly destroy the structure.
call disk_media_dereference
.noremove:
; 2. Test whether there is new media.
cmp dword [esp+8+12], 0
jz .noinsert
; Yep, there is.
; 3. Process the new media. We assume that all media fields are available to
; use, see comments in 'disk_media_dereference' (this covers using by previous
; media referencers) and note that calls to this function are synchronized
; (this covers using by new media referencers).
; 3a. Call the 'querymedia' callback.
; .Flags are set to zero for possible future extensions.
lea edx, [esi+DISK.MediaInfo]
and [edx+DISKMEDIAINFO.Flags], 0
mov al, DISKFUNC.querymedia
stdcall disk_call_driver, edx
; 3b. Check the result of the callback. Abort if it failed.
test eax, eax
jnz .noinsert
; 3c. Allocate the cache unless disabled by the driver. Abort if failed.
call disk_init_cache
test al, al
jz .noinsert
; 3d. Acquire the lifetime reference for the media object.
inc [esi+DISK.MediaRefCount]
; 3e. Scan for partitions. Ignore result; the list of partitions is valid even
; on errors.
call disk_scan_partitions
; 3f. Media is inserted and available for use.
inc [esi+DISK.MediaInserted]
.noinsert:
; 4. Return.
pop edi esi ebx ; restore used registers to be stdcall
ret 8 ; purge 2 dword arguments to be stdcall
 
; This function is a thunk for all functions of a disk driver.
; It checks whether the referenced function is implemented in the driver.
; If so, this function jumps to the function in the driver.
; Otherwise, it jumps to the default implementation.
; al = offset of function in the DISKFUNC structure;
; esi = pointer to the DISK structure;
; stack is the same as for the corresponding function except that the
; first parameter (void* userdata) is prepended automatically.
disk_call_driver:
movzx eax, al ; eax = offset of function in the DISKFUNC structure
; 1. Prepend the first argument to the stack.
pop ecx ; ecx = return address
push [esi+DISK.UserData] ; add argument
push ecx ; save return address
; 2. Check that the required function is inside the table. If not, go to 5.
mov ecx, [esi+DISK.Functions]
cmp eax, [ecx+DISKFUNC.strucsize]
jae .default
; 3. Check that the required function is implemented. If not, go to 5.
mov ecx, [ecx+eax]
test ecx, ecx
jz .default
; 4. Jump to the required function.
jmp ecx
.default:
; 5. Driver does not implement the required function; use default implementation.
jmp dword [disk_default_callbacks+eax-4]
 
; The default implementation of DISKFUNC.querymedia.
disk_default_querymedia:
movi eax, DISK_STATUS_INVALID_CALL
ret 8
 
; The default implementation of DISKFUNC.read and DISKFUNC.write.
disk_default_read:
disk_default_write:
movi eax, DISK_STATUS_INVALID_CALL
ret 20
 
; The default implementation of DISKFUNC.close, DISKFUNC.closemedia and
; DISKFUNC.flush.
disk_default_close:
disk_default_closemedia:
disk_default_flush:
xor eax, eax
ret 4
 
; The default implementation of DISKFUNC.adjust_cache_size.
disk_default_adjust_cache_size:
mov eax, [esp+8]
ret 8
 
; This is an internal function called from 'disk_media_changed' when a new media
; is detected. It creates the list of partitions for the media.
; If media is not partitioned, then the list consists of one partition which
; covers all the media.
; esi = pointer to the DISK structure.
disk_scan_partitions:
; 1. Initialize .NumPartitions and .Partitions fields as zeros: empty list.
and [esi+DISK.NumPartitions], 0
and [esi+DISK.Partitions], 0
; 2. Acquire the buffer for MBR and bootsector tests. See the comment before
; the 'partition_buffer_users' variable.
mov eax, [esi+DISK.MediaInfo.SectorSize]
cmp eax, 512
jnz @f
mov ebx, mbr_buffer ; assume the global buffer is free
lock inc [partition_buffer_users]
jz .buffer_acquired ; yes, it is free
lock dec [partition_buffer_users] ; no, we must allocate
@@:
lea eax, [eax*3]
stdcall kernel_alloc, eax
test eax, eax
jz .nothing
xchg eax, ebx
.buffer_acquired:
; MBR/EBRs are organized in the chain. We use a loop over MBR/EBRs, but no
; more than MAX_NUM_PARTITION times.
; 3. Prepare things for the loop.
; ebp will hold the sector number for current MBR/EBR.
; [esp] will hold the sector number for current extended partition, if there
; is one.
; [esp+4] will hold the counter that prevents long loops.
push ebp ; save ebp
push MAX_NUM_PARTITIONS ; the counter of max MBRs to process
xor ebp, ebp ; start from sector zero
push ebp ; no extended partition yet
; 4. MBR is 512 bytes long. If sector size is less than 512 bytes,
; assume no MBR, no partitions and go to 11.
cmp [esi+DISK.MediaInfo.SectorSize], 512
jb .notmbr
.new_mbr:
; 5. Read the current sector.
; Note that 'read' callback operates with 64-bit sector numbers, so we must
; push additional zero as a high dword of sector number.
mov al, DISKFUNC.read
push 1
stdcall disk_call_driver, ebx, ebp, 0, esp
pop ecx
; 6. If the read has failed, abort the loop.
dec ecx
jnz .mbr_failed
; 7. Check the MBR/EBR signature. If it is wrong, abort the loop.
; Soon we will access the partition table which starts at ebx+0x1BE,
; so we can fill its address right now. If we do it now, then the addressing
; [ecx+0x40] is shorter than [ebx+0x1fe]: one-byte offset vs 4-bytes offset.
lea ecx, [ebx+0x1be] ; ecx -> partition table
cmp word [ecx+0x40], 0xaa55
jnz .mbr_failed
; 8. The MBR is treated differently from EBRs. For MBR we additionally need to
; execute step 10 and possibly step 11.
test ebp, ebp
jnz .mbr
; 9. Handle GUID Partition Table
; 9a. Check if MBR is protective
call is_protective_mbr
jnz .no_gpt
; 9b. If so, try to scan GPT headers
call disk_scan_gpt
; 9c. If any GPT header is valid, ignore MBR
jz .done
; Otherwise process legacy/protective MBR
.no_gpt:
; The partition table can be present or not present. In the first case, we just
; read the MBR. In the second case, we just read the bootsector for a
; filesystem.
; The following algorithm is used to distinguish between these cases.
; A. If at least one entry of the partition table is invalid, this is
; a bootsector. See the description of 'is_partition_table_entry' for
; definition of validity.
; B. If all entries are empty (filesystem type field is zero) and the first
; byte is jmp opcode (0EBh or 0E9h), this is a bootsector which happens to
; have zeros in the place of partition table.
; C. Otherwise, this is an MBR.
; 10. Test for MBR vs bootsector.
; 10a. Check entries. If any is invalid, go to 11 (rule A).
call is_partition_table_entry
jc .notmbr
add ecx, 10h
call is_partition_table_entry
jc .notmbr
add ecx, 10h
call is_partition_table_entry
jc .notmbr
add ecx, 10h
call is_partition_table_entry
jc .notmbr
; 10b. Check types of the entries. If at least one is nonzero, go to 12 (rule C).
mov al, [ecx-30h+PARTITION_TABLE_ENTRY.Type]
or al, [ecx-20h+PARTITION_TABLE_ENTRY.Type]
or al, [ecx-10h+PARTITION_TABLE_ENTRY.Type]
or al, [ecx+PARTITION_TABLE_ENTRY.Type]
jnz .mbr
; 10c. Empty partition table or bootsector with many zeroes? (rule B)
cmp byte [ebx], 0EBh
jz .notmbr
cmp byte [ebx], 0E9h
jnz .mbr
.notmbr:
; 11. This is not an MBR. The media is not partitioned. Create one partition
; which covers all the media and abort the loop.
stdcall disk_add_partition, 0, 0, \
dword [esi+DISK.MediaInfo.Capacity], dword [esi+DISK.MediaInfo.Capacity+4], esi
jmp .done
.mbr:
; 12. Process all entries of the new MBR/EBR
lea ecx, [ebx+0x1be] ; ecx -> partition table
push 0 ; assume no extended partition
call process_partition_table_entry
add ecx, 10h
call process_partition_table_entry
add ecx, 10h
call process_partition_table_entry
add ecx, 10h
call process_partition_table_entry
pop ebp
; 13. Test whether we found a new EBR and should continue the loop.
; 13a. If there was no next EBR, return.
test ebp, ebp
jz .done
; Ok, we have EBR.
; 13b. EBRs addresses are relative to the start of extended partition.
; For simplicity, just abort if an 32-bit overflow occurs; large disks
; are most likely partitioned with GPT, not MBR scheme, since the precise
; calculation here would increase limit just twice at the price of big
; compatibility problems.
pop eax ; load extended partition
add ebp, eax
jc .mbr_failed
; 13c. If extended partition has not yet started, start it.
test eax, eax
jnz @f
mov eax, ebp
@@:
; 13d. If the limit is not exceeded, continue the loop.
dec dword [esp]
push eax ; store extended partition
jnz .new_mbr
.mbr_failed:
.done:
; 14. Cleanup after the loop.
pop eax ; not important anymore
pop eax ; not important anymore
pop ebp ; restore ebp
; 15. Release the buffer.
; 15a. Test whether it is the global buffer or we have allocated it.
cmp ebx, mbr_buffer
jz .release_partition_buffer
; 15b. If we have allocated it, free it.
xchg eax, ebx
call free
jmp .nothing
; 15c. Otherwise, release reference.
.release_partition_buffer:
lock dec [partition_buffer_users]
.nothing:
; 16. Return.
ret
 
 
; This function is called from disk_scan_partitions to validate and parse
; primary and backup GPTs.
proc disk_scan_gpt
push ecx
; Scan primary GPT (second sector)
stdcall scan_gpt, 1, 0
test eax, eax
; There is no code to restore backup GPT if it's corrupt.
; Therefore just exit if Primary GPT has been parsed successfully.
jz .exit
DEBUGF 1, 'K : Primary GPT is corrupt, trying backup one\n'
mov eax, dword[esi+DISK.MediaInfo.Capacity+0]
mov edx, dword[esi+DISK.MediaInfo.Capacity+4]
sub eax, 1
sbb edx, 0
; Scan backup GPT (last sector)
stdcall scan_gpt, eax, edx
test eax, eax
jz .exit
DEBUGF 1, 'K : Backup GPT is also corrupt, fallback to legacy MBR\n'
.exit:
; Return value is ZF
pop ecx
ret
endp
 
 
; This function is called from disk_scan_gpt to process a single GPT.
proc scan_gpt _mylba:qword
locals
GPEA_len dd ? ; Length of GPT Partition Entry Array in bytes
endl
push ebx edi
; Allocalte memory for GPT header
mov eax, [esi+DISK.MediaInfo.SectorSize]
stdcall kernel_alloc, eax
test eax, eax
jz .fail
; Save pointer to stack, just in case
push eax
mov ebx, eax
; Read GPT header
mov al, DISKFUNC.read
push 1
stdcall disk_call_driver, ebx, dword[_mylba+0], dword[_mylba+4], esp
pop ecx
test eax, eax
jnz .fail_free_gpt
; Check signature
cmp dword[ebx+GPTH.Signature+0], 'EFI '
jnz .fail_free_gpt
cmp dword[ebx+GPTH.Signature+4], 'PART'
jnz .fail_free_gpt
; Check Revision
cmp [ebx+GPTH.Revision], 0x00010000
jnz .fail_free_gpt
; Compute and check CRC32
xor edx, edx
xchg edx, [ebx+GPTH.HeaderCRC32]
mov eax, -1
stdcall crc_32, 0xEDB88320, ebx, [ebx+GPTH.HeaderSize]
xor eax, -1
cmp eax, edx
jnz .fail_free_gpt
; Reserved must be zero
cmp [ebx+GPTH.Reserved], 0
jnz .fail_free_gpt
; MyLBA of GPT header at LBA X must equal X
mov eax, dword[ebx+GPTH.MyLBA+0]
mov edx, dword[ebx+GPTH.MyLBA+4]
cmp eax, dword[_mylba+0]
jnz .fail_free_gpt
cmp edx, dword[_mylba+4]
jnz .fail_free_gpt
; Capacity - MyLBA = AlternateLBA
mov eax, dword[esi+DISK.MediaInfo.Capacity+0]
mov edx, dword[esi+DISK.MediaInfo.Capacity+4]
sub eax, dword[_mylba+0]
sbb edx, dword[_mylba+4]
cmp eax, dword[ebx+GPTH.AlternateLBA+0]
jnz .fail_free_gpt
cmp edx, dword[ebx+GPTH.AlternateLBA+4]
jnz .fail_free_gpt
 
; Compute GPT Partition Entry Array (GPEA) length in bytes
mov eax, [ebx+GPTH.NumberOfPartitionEntries]
mul [ebx+GPTH.SizeOfPartitionEntry]
test edx, edx ; far too big
jnz .fail_free_gpt
; Round up to sector boundary
mov ecx, [esi+DISK.MediaInfo.SectorSize] ; power of two
dec ecx
add eax, ecx
jc .fail_free_gpt ; too big
not ecx
and eax, ecx
; We will need this length to compute CRC32 of GPEA
mov [GPEA_len], eax
; Allocate memory for GPEA
stdcall kernel_alloc, eax
test eax, eax
jz .fail_free_gpt
; Save to not juggle with registers
push eax
mov edi, eax
mov eax, [GPEA_len]
xor edx, edx
; Get the number of sectors GPEA fits into
div [esi+DISK.MediaInfo.SectorSize]
push eax ; esp = pointer to the number of sectors
mov al, DISKFUNC.read
stdcall disk_call_driver, edi, dword[ebx+GPTH.PartitionEntryLBA+0], \
dword[ebx+GPTH.PartitionEntryLBA+4], esp
test eax, eax
pop eax
jnz .fail_free_gpea_gpt
; Compute and check CRC32 of GPEA
mov eax, -1
stdcall crc_32, 0xEDB88320, edi, [GPEA_len]
xor eax, -1
cmp eax, [ebx+GPTH.PartitionEntryArrayCRC32]
jnz .fail_free_gpea_gpt
 
; Process partitions, skip zeroed ones.
.next_gpe:
xor eax, eax
mov ecx, [ebx+GPTH.SizeOfPartitionEntry]
repz scasb
jz .skip
add edi, ecx
sub edi, [ebx+GPTH.SizeOfPartitionEntry]
; Length of a partition in sectors is EndingLBA - StartingLBA + 1
mov eax, dword[edi+GPE.EndingLBA+0]
mov edx, dword[edi+GPE.EndingLBA+4]
sub eax, dword[edi+GPE.StartingLBA+0]
sbb edx, dword[edi+GPE.StartingLBA+4]
add eax, 1
adc edx, 0
push ebx
mov ebx, [ebp-8] ; three-sectors-sized buffer
stdcall disk_add_partition, dword[edi+GPE.StartingLBA+0], \
dword[edi+GPE.StartingLBA+4], eax, edx, esi
pop ebx
add edi, [ebx+GPTH.SizeOfPartitionEntry]
.skip:
dec [ebx+GPTH.NumberOfPartitionEntries]
jnz .next_gpe
 
; Pointers to GPT header and GPEA are on the stack
stdcall kernel_free
stdcall kernel_free
pop edi ebx
xor eax, eax
ret
.fail_free_gpea_gpt:
stdcall kernel_free
.fail_free_gpt:
stdcall kernel_free
.fail:
pop edi ebx
xor eax, eax
inc eax
ret
endp
 
; ecx = pointer to partition records array (MBR + 446)
is_protective_mbr:
push ecx edi
xor eax, eax
cmp [ecx-2], ax
jnz .exit
; Partition record 0 has specific fields
cmp [ecx+0], al
jnz .exit
cmp byte[ecx+4], 0xEE
jnz .exit
cmp dword[ecx+8], 1
jnz .exit
mov edi, -1
cmp [ecx+12], edi
jz @f
add edi, dword[esi+DISK.MediaInfo.Capacity+0]
cmp [ecx+12], edi
jnz .exit
@@:
; Check that partition records 1-3 are filled with zero
lea edi, [ecx+16]
mov ecx, 16*3/2 ; 3 partitions
repz scasw
.exit:
pop edi ecx
; Return value is ZF
ret
 
; This is an internal function called from disk_scan_partitions. It checks
; whether the entry pointed to by ecx is a valid entry of partition table.
; The entry is valid if the first byte is 0 or 80h, the first sector plus the
; length is less than twice the size of media. Multiplication by two is
; required since the size mentioned in the partition table can be slightly
; greater than the real size.
is_partition_table_entry:
; 1. Check .Bootable field.
mov al, [ecx+PARTITION_TABLE_ENTRY.Bootable]
and al, 7Fh
jnz .invalid
; 3. Calculate first sector + length. Note that .FirstAbsSector is relative
; to the MBR/EBR, so the real sum is ebp + .FirstAbsSector + .Length.
mov eax, ebp
xor edx, edx
add eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
adc edx, 0
add eax, [ecx+PARTITION_TABLE_ENTRY.Length]
adc edx, 0
; 4. Divide by two.
shr edx, 1
rcr eax, 1
; 5. Compare with capacity. If the subtraction (edx:eax) - .Capacity does not
; overflow, this is bad.
sub eax, dword [esi+DISK.MediaInfo.Capacity]
sbb edx, dword [esi+DISK.MediaInfo.Capacity+4]
jnc .invalid
.valid:
; 5. Return success: CF is cleared.
clc
ret
.invalid:
; 6. Return fail: CF is set.
stc
ret
 
; This is an internal function called from disk_scan_partitions. It processes
; the entry pointed to by ecx.
; * If the entry is invalid, just ignore this entry.
; * If the type is zero, just ignore this entry.
; * If the type is one of types for extended partition, store the address
; of this partition as the new MBR in [esp+4].
; * Otherwise, add the partition to the list of partitions for this disk.
; We don't use the type from the entry to identify the file system;
; fs-specific checks do this more reliably.
process_partition_table_entry:
; 1. Check for valid entry. If invalid, return (go to 5).
call is_partition_table_entry
jc .nothing
; 2. Check for empty entry. If invalid, return (go to 5).
mov al, [ecx+PARTITION_TABLE_ENTRY.Type]
test al, al
jz .nothing
; 3. Check for extended partition. If extended, go to 6.
irp type,\
0x05,\ ; DOS: extended partition
0x0f,\ ; WIN95: extended partition, LBA-mapped
0xc5,\ ; DRDOS/secured: extended partition
0xd5 ; Old Multiuser DOS secured: extended partition
{
cmp al, type
jz .extended
}
; 4. If we are here, that is a normal partition. Add it to the list.
; Note that the first sector is relative to MBR/EBR.
mov eax, ebp
xor edx, edx
add eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
adc edx, 0
push ecx
stdcall disk_add_partition, eax, edx, \
[ecx+PARTITION_TABLE_ENTRY.Length], 0, esi
pop ecx
.nothing:
; 5. Return.
ret
.extended:
; 6. If we are here, that is an extended partition. Store the address.
mov eax, [ecx+PARTITION_TABLE_ENTRY.FirstAbsSector]
mov [esp+4], eax
ret
 
; This is an internal function called from disk_scan_partitions and
; process_partition_table_entry. It adds one partition to the list of
; partitions for the media.
; Important note: start, length, disk MUST be present and
; MUST be in the same order as in PARTITION structure.
; esi duplicates [disk].
proc disk_add_partition stdcall uses ebx edi, start:qword, length:qword, disk:dword
; 1. Check that this partition will not exceed the limit on total number.
cmp [esi+DISK.NumPartitions], MAX_NUM_PARTITIONS
jae .nothing
; 2. Check that this partition does not overlap with any already registered
; partition. Since any file system assumes that the disk data will not change
; outside of its control, such overlap could be destructive.
; Since the number of partitions is usually very small and is guaranteed not
; to be large, the simple linear search is sufficient.
; 2a. Prepare the loop: edi will point to the current item of .Partitions
; array, ecx will be the current item, ebx will hold number of items left.
mov edi, [esi+DISK.Partitions]
mov ebx, [esi+DISK.NumPartitions]
test ebx, ebx
jz .partitionok
.scan_existing:
; 2b. Get the next partition.
mov ecx, [edi]
add edi, 4
; The range [.FirstSector, .FirstSector+.Length) must be either entirely to
; the left of [start, start+length) or entirely to the right.
; 2c. Subtract .FirstSector - start. The possible overflow distinguish between
; cases "to the left" (2e) and "to the right" (2d).
mov eax, dword [ecx+PARTITION.FirstSector]
mov edx, dword [ecx+PARTITION.FirstSector+4]
sub eax, dword [start]
sbb edx, dword [start+4]
jb .less
; 2d. .FirstSector is greater than or equal to start. Check that .FirstSector
; is greater than or equal to start+length; the subtraction
; (.FirstSector-start) - length must not cause overflow. Go to 2g if life is
; good or to 2f in the other case.
sub eax, dword [length]
sbb edx, dword [length+4]
jb .overlap
jmp .next_existing
.less:
; 2e. .FirstSector is less than start. Check that .FirstSector+.Length is less
; than or equal to start. If the addition (.FirstSector-start) + .Length does
; not cause overflow, then .FirstSector + .Length is strictly less than start;
; since the equality is also valid, use decrement preliminarily. Go to 2g or
; 2f depending on the overflow.
sub eax, 1
sbb edx, 0
add eax, dword [ecx+PARTITION.Length]
adc edx, dword [ecx+PARTITION.Length+4]
jnc .next_existing
.overlap:
; 2f. The partition overlaps with previously registered partition. Say warning
; and return with nothing done.
dbgstr 'two partitions overlap, ignoring the last one'
jmp .nothing
.next_existing:
; 2g. The partition does not overlap with the current partition. Continue the
; loop.
dec ebx
jnz .scan_existing
.partitionok:
; 3. The partition has passed tests. Reallocate the partitions array for a new
; entry.
; 3a. Call the allocator.
mov eax, [esi+DISK.NumPartitions]
inc eax ; one more entry
shl eax, 2 ; each entry is dword
call malloc
; 3b. Test the result. If failed, return with nothing done.
test eax, eax
jz .nothing
; 3c. Copy the old array to the new array.
mov edi, eax
push esi
mov ecx, [esi+DISK.NumPartitions]
mov esi, [esi+DISK.Partitions]
rep movsd
pop esi
; 3d. Set the field in the DISK structure to the new array.
xchg [esi+DISK.Partitions], eax
; 3e. Free the old array.
call free
; 4. Recognize the file system.
; 4a. Call the filesystem recognizer. It will allocate the PARTITION structure
; with possible filesystem-specific fields.
call disk_detect_partition
; 4b. Check return value. If zero, return with list not changed; so far only
; the array was reallocated, this is ok for other code.
test eax, eax
jz .nothing
; 5. Insert the new partition to the list.
stosd
inc [esi+DISK.NumPartitions]
; 6. Return.
.nothing:
ret
endp
 
; This is an internal function called from disk_add_partition.
; It tries to recognize the file system on the partition and allocates the
; corresponding PARTITION structure with filesystem-specific fields.
disk_detect_partition:
; This function inherits the stack frame from disk_add_partition. In stdcall
; with ebp-based frame arguments start from ebp+8, since [ebp]=saved ebp
; and [ebp+4]=return address.
virtual at ebp+8
.start dq ?
.length dq ?
.disk dd ?
end virtual
; 1. Read the bootsector to the buffer.
; When disk_add_partition is called, ebx contains a pointer to
; a three-sectors-sized buffer. This function saves ebx in the stack
; immediately before ebp.
mov ebx, [ebp-4] ; get buffer
add ebx, [esi+DISK.MediaInfo.SectorSize] ; advance over MBR data to bootsector data
add ebp, 8 ; ebp points to part of PARTITION structure
xor eax, eax ; first sector of the partition
call fs_read32_sys
push eax
; 2. Run tests for all supported filesystems. If at least one test succeeded,
; go to 4.
; For tests:
; ebp -> first three fields of PARTITION structure, .start, .length, .disk;
; [esp] = error code after bootsector read: 0 = ok, otherwise = failed,
; ebx points to the buffer for bootsector,
; ebx+[esi+DISK.MediaInfo.SectorSize] points to sector-sized buffer that can be used for anything.
call fat_create_partition
test eax, eax
jnz .success
call ntfs_create_partition
test eax, eax
jnz .success
call ext2_create_partition
test eax, eax
jnz .success
call xfs_create_partition
test eax, eax
jnz .success
; 3. No file system has recognized the volume, so just allocate the PARTITION
; structure without extra fields.
movi eax, sizeof.PARTITION
call malloc
test eax, eax
jz .nothing
mov edx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+PARTITION.FirstSector], edx
mov edx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+PARTITION.FirstSector+4], edx
mov edx, dword [ebp+PARTITION.Length]
mov dword [eax+PARTITION.Length], edx
mov edx, dword [ebp+PARTITION.Length+4]
mov dword [eax+PARTITION.Length+4], edx
mov [eax+PARTITION.Disk], esi
mov [eax+PARTITION.FSUserFunctions], default_fs_functions
.success:
.nothing:
sub ebp, 8 ; restore ebp
; 4. Return with eax = pointer to PARTITION or NULL.
pop ecx
ret
 
iglobal
align 4
default_fs_functions:
dd free
dd (default_fs_functions_end - default_fs_functions - 4) / 4
dd 0
dd 0
dd 0
dd 0
dd 0
dd default_fs_get_file_info
default_fs_functions_end:
endg
 
proc default_fs_get_file_info uses edi
movi eax, ERROR_UNSUPPORTED_FS
cmp byte[esi], 0
jnz .done
movi ecx, 40 ; len of BDFE without filename
cmp [ebx+f70s5arg.xflags], 0
jz @f
add ecx, 2 ; volume label requested, space for utf16 terminator
@@:
mov ebx, [ebx+f70s5arg.buf]
stdcall is_region_userspace, ebx, ecx
movi eax, ERROR_MEMORY_POINTER
jnz .done
mov edi, ebx
xor eax, eax
rep stosb
mov [ebx+bdfe.attr], 0x10 ; directory flag
mov word[ebx+bdfe.name], 0 ; word because of possible utf16
mov eax, dword[ebp+PARTITION.Length+DQ.lo]
mov edx, dword[ebp+PARTITION.Length+DQ.hi]
mov ecx, [ebp+PARTITION.Disk]
mov ecx, [ecx+DISK.MediaInfo.SectorSize]
bsf ecx, ecx
shld edx, eax, cl
shl eax, cl
mov [ebx+bdfe.size.lo], eax
mov [ebx+bdfe.size.hi], edx
xor eax, eax
.done:
ret
endp
 
; This function is called from file_system_lfn.
; This handler gets the control each time when fn 70 is called
; with unknown item of root subdirectory.
; in: esi = ebp -> path string
; out: if the handler processes path, it must not return in file_system_lfn,
; but instead pop return address and return directly to the caller
; otherwise simply return
dyndisk_handler:
push ebx edi ; save registers used in file_system_lfn
; 1. Acquire the mutex.
mov ecx, disk_list_mutex
call mutex_lock
; 2. Loop over the list of DISK structures.
; 2a. Initialize.
mov ebx, disk_list
.scan:
; 2b. Get the next item.
mov ebx, [ebx+DISK.Next]
; 2c. Check whether the list is done. If so, go to 3.
cmp ebx, disk_list
jz .notfound
; 2d. Compare names. If names match, go to 5.
mov edi, [ebx+DISK.Name]
push esi
@@:
; esi points to the name from fs operation; it is terminated by zero or slash.
lodsb
test al, al
jz .eoin_dec
cmp al, '/'
jz .eoin
; edi points to the disk name.
inc edi
; edi points to lowercase name, this is a requirement for the driver.
; Characters at esi can have any register. Lowercase the current character.
; This lowercasing works for latin letters and digits; since the disk name
; should not contain other symbols, this is ok.
or al, 20h
cmp al, [edi-1]
jz @b
.wrongname:
; 2f. Names don't match. Continue the loop.
pop esi
jmp .scan
.notfound:
; The loop is done and no name matches.
; 3. Release the mutex.
call mutex_unlock
; 4. Return normally.
pop edi ebx ; restore registers used in file_system_lfn
ret
; part of 2d: the name matches partially, but we must check that this is full
; equality.
.eoin_dec:
dec esi
.eoin:
cmp byte [edi], 0
jnz .wrongname
; We found the addressed DISK structure.
; 5. Reference the disk.
lock inc [ebx+DISK.RefCount]
; 6. Now we are sure that the DISK structure is not going to die at least
; while we are working with it, so release the global mutex.
call mutex_unlock
pop ecx ; pop from the stack saved value of esi
; 7. Acquire the mutex for media object.
pop edi ; restore edi
lea ecx, [ebx+DISK.MediaLock]
call mutex_lock
; 8. Get the media object. If it is not NULL, reference it.
xor edx, edx
cmp [ebx+DISK.MediaInserted], dl
jz @f
mov edx, ebx
inc [ebx+DISK.MediaRefCount]
@@:
; 9. Now we are sure that the media object, if it exists, is not going to die
; at least while we are working with it, so release the mutex for media object.
call mutex_unlock
mov ecx, ebx
pop ebx eax ; restore ebx, pop return address
; 10. Check whether the fs operation wants to enumerate partitions (go to 11)
; or work with some concrete partition (go to 12).
cmp byte [esi], 0
jnz .haspartition
; 11. The fs operation wants to enumerate partitions.
; Check whether the media is inserted.
mov esi, fs_dyndisk_next_nomedia
test edx, edx
jz @f
mov esi, fs_dyndisk_next
@@: ; Let the procedure from fs_lfn.inc do the job.
jmp file_system_lfn.maindir_noesi
 
.root:
pop ecx edx
xor eax, eax
cmp byte [ebx], 9
jz .cleanup_ecx
.access_denied:
movi eax, ERROR_ACCESS_DENIED
.cleanup_ecx:
mov [esp+32], eax
mov esi, ecx ; disk*dereference assume that esi points to DISK
test edx, edx ; if there are no media, we didn't reference it
jz @f
call disk_media_dereference
@@:
call disk_dereference
stdcall kernel_free, ebp
ret
 
.dyndisk_cleanup:
pop ecx edx
movi eax, ERROR_FILE_NOT_FOUND
jmp .cleanup_ecx
 
.haspartition:
; 12. The fs operation has specified some partition.
push edx ecx
xor eax, eax
lodsb
sub eax, '0'
jz .dyndisk_cleanup
cmp eax, 10
jnc .dyndisk_cleanup
mov ecx, eax
lodsb
cmp eax, '/'
jz @f
test eax, eax
jnz .dyndisk_cleanup
dec esi
@@:
cmp byte [esi], 0
jnz @f
cmp byte [ebx], 1
jz @f
cmp byte [ebx], 5
jnz .root
@@:
dec ecx ; convert to zero-based partition index
pop edx ; edx = pointer to DISK, dword [esp] = NULL or edx
; If the driver does not support insert notifications and we are the only fs
; operation with this disk, ask the driver whether the media
; was inserted/removed/changed. Otherwise, assume that media status is valid.
test byte [edx+DISK.DriverFlags], DISK_NO_INSERT_NOTIFICATION
jz .media_accurate
push ecx esi
mov esi, edx
cmp dword [esp+8], 0
jz .test_no_media
cmp [esi+DISK.MediaRefCount], 2
jnz .media_accurate_pop
lea edx, [esi+DISK.MediaInfo]
and [edx+DISKMEDIAINFO.Flags], 0
mov al, DISKFUNC.querymedia
stdcall disk_call_driver, edx
test eax, eax
jz .media_accurate_pop
stdcall disk_media_dereference ; drop our reference so that disk_media_changed could close the media
stdcall disk_media_changed, esi, 0
and dword [esp+8], 0 ; no media
.test_no_media:
stdcall disk_media_changed, esi, 1 ; issue fake notification
; if querymedia() inside disk_media_changed returns error, the notification is ignored
cmp [esi+DISK.MediaInserted], 0
jz .media_accurate_pop
lock inc [esi+DISK.MediaRefCount]
mov dword [esp+8], esi
.media_accurate_pop:
mov edx, esi
pop esi ecx
.media_accurate:
pop eax
test eax, eax
jz .nomedia
cmp ecx, [edx+DISK.NumPartitions]
jae .notfound2
mov eax, [edx+DISK.Partitions]
mov eax, [eax+ecx*4]
mov edi, [eax+PARTITION.FSUserFunctions]
mov ecx, [ebx]
cmp [edi+4], ecx
jbe .unsupported
cmp dword[edi+8+ecx*4], 0 ; user function not implemented
jz .unsupported
pushd edx ebp eax [edi+8+ecx*4]
cmp ecx, 10
jnz .callFS
or ecx, -1
mov edi, esi
xor eax, eax
repnz scasb
mov edx, edi
dec edi
mov al, '/'
std
repnz scasb
cld
inc edi
mov [edi], ah
mov ebp, [current_slot]
add ebp, APPDATA.cur_dir
pushd ebx esi edx [ebp] ebp edi
sub esi, 2
mov [ebp], esi
mov edi, edx
mov esi, [ebx+16]
mov eax, [ebx+20]
cmp eax, 4
jc @f
xor eax, eax
@@:
call getFullPath
pop edi ebp
mov byte [edi], '/'
popd [ebp] edi esi ebx
add edi, 2
test eax, eax
jz .errorRename
cmp byte [edi], 0
jz .errorRename
.callFS:
pop eax ebp
call eax
pop ebp edx
mov dword [esp+20], ebx
.cleanup:
mov dword [esp+32], eax
mov esi, edx
call disk_media_dereference
@@:
call disk_dereference
stdcall kernel_free, ebp
ret
 
.unsupported:
movi eax, ERROR_UNKNOWN_FS
cmp edi, default_fs_functions
jz .cleanup
movi eax, ERROR_UNSUPPORTED_FS
jmp .cleanup
 
.errorRename:
pop eax eax ebp edx
.notfound2:
movi eax, ERROR_FILE_NOT_FOUND
jmp .cleanup
 
.nomedia:
test ecx, ecx
jnz .notfound2
mov dword [esp+32], ERROR_DEVICE
mov esi, edx
jmp @b
 
; This is a callback for enumerating partitions called from
; file_system_lfn.maindir in the case of inserted media.
; It just increments eax until DISK.NumPartitions reached and then
; cleans up.
fs_dyndisk_next:
mov ecx, [esp+8]
cmp eax, [ecx+DISK.NumPartitions]
jae .nomore
inc eax
clc
ret
.nomore:
pusha
mov esi, ecx
call disk_media_dereference
call disk_dereference
popa
stc
ret
 
; This is a callback for enumerating partitions called from
; file_system_lfn.maindir in the case of missing media.
; In this case we create one pseudo-partition.
fs_dyndisk_next_nomedia:
cmp eax, 1
jae .nomore
inc eax
clc
ret
.nomore:
mov ecx, [esp+8]
pusha
mov esi, ecx
call disk_dereference
popa
stc
ret
 
; This function is called from file_system_lfn.
; This handler is called when virtual root is enumerated
; and must return all items which can be handled by this.
; It is called several times, first time with eax=0
; in: eax = 0 for first call, previously returned value for subsequent calls
; out: eax = 0 => no more items
; eax != 0 => buffer pointed to by edi contains name of item
dyndisk_enum_root:
push edx ; save register used in file_system_lfn
mov ecx, disk_list_mutex ; it will be useful
; 1. If this is the first call, acquire the mutex and initialize.
test eax, eax
jnz .notfirst
call mutex_lock
mov eax, disk_list
.notfirst:
; 2. Get next item.
mov eax, [eax+DISK.Next]
; 3. If there are no more items, go to 6.
cmp eax, disk_list
jz .last
; 4. Copy name from the DISK structure to edi.
push eax esi
mov esi, [eax+DISK.Name]
@@:
lodsb
stosb
test al, al
jnz @b
pop esi eax
; 5. Return with eax = item.
pop edx ; restore register used in file_system_lfn
ret
.last:
; 6. Release the mutex and return with eax = 0.
call mutex_unlock
xor eax, eax
pop edx ; restore register used in file_system_lfn
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/rd.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/flp_drv.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/cd_drv.inc
0,0 → 1,1218
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
;-----------------------------------------------------------------------------
;**********************************************************
; Direct work with CD (ATAPI) device
;**********************************************************
; Author of a part of the source code - Kulakov Vladimir Gennadievich
; Adaptation, revision and development - Mario79, <Lrz>
 
; Maximum number of repeats of a read operation
MaxRetr = 10
; Maximum waiting time for ready to receive a command
; (in ticks)
BSYWaitTime = 1000 ;2
NoTickWaitTime = 0xfffff
CDBlockSize = 2048
;********************************************
;* READING SECTOR WITH REPEATS *
;* Repeated reads on failures *
;********************************************
ReadCDWRetr:
;-----------------------------------------------------------
; input : eax = block to read
; ebx = destination
;-----------------------------------------------------------
pushad
mov eax, [CDSectorAddress]
mov ebx, [CDDataBuf_pointer]
call cd_calculate_cache
xor edi, edi
add esi, 8
inc edi
;--------------------------------------
align 4
.hdreadcache:
cmp [esi], eax ; correct sector
je .yeshdcache
 
add esi, 8
inc edi
dec ecx
jnz .hdreadcache
 
call find_empty_slot_CD_cache ; ret in edi
 
push edi
push eax
call cd_calculate_cache_2
shl edi, 11
add edi, eax
mov [CDDataBuf_pointer], edi
pop eax
pop edi
 
call ReadCDWRetr_1
cmp [DevErrorCode], 0
jne .exit
 
mov [CDDataBuf_pointer], ebx
call cd_calculate_cache_1
lea esi, [edi*8+esi]
mov [esi], eax ; sector number
;--------------------------------------
.yeshdcache:
mov esi, edi
shl esi, 11 ;9
push eax
call cd_calculate_cache_2
add esi, eax
pop eax
mov edi, ebx ;[CDDataBuf_pointer]
mov ecx, 512 ;/4
cld
rep movsd ; move data
;--------------------------------------
.exit:
popad
ret
;-----------------------------------------------------------------------------
ReadCDWRetr_1:
pushad
; Loop until the command is successful or the number of attempts is over
mov ecx, MaxRetr
;--------------------------------------
align 4
@@NextRetr:
; Send a command
;*************************************************
;* FULL READ OF COMPACT DISK SECTOR *
;* User data, subchannel *
;* information and control information are read *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disc number on channel; *
;* CDSectorAddress - address of reading sector. *
;* The data is read into the CDDataBuf array. *
;*************************************************
;ReadCD:
push ecx
; Flush the packet command buffer
call clear_packet_buffer
; Generate a packet command to read a data sector
; Set the command code Read CD
mov [PacketCommand], byte 0x28 ;0xBE
; Set the sector address
mov ax, word [CDSectorAddress+2]
xchg al, ah
mov word [PacketCommand+2], ax
mov ax, word [CDSectorAddress]
xchg al, ah
mov word [PacketCommand+4], ax
; Set the number of sectors to read
mov [PacketCommand+8], byte 1
; Send a command
call SendPacketDatCommand
pop ecx
 
test eax, eax
jz @@End_4
 
or ecx, ecx ;{SPraid.simba} (for cd load)
jz @@End_4
 
dec ecx
 
cmp [timer_ticks_enable], 0
jne @f
 
mov eax, NoTickWaitTime
;--------------------------------------
align 4
.wait:
dec eax
jz @@NextRetr
 
jmp .wait
;--------------------------------------
align 4
@@:
loop @@NextRetr
;--------------------------------------
@@End_4:
mov dword [DevErrorCode], eax
popad
ret
;-----------------------------------------------------------------------------
; General purpose procedures to execute packet commands in PIO Mode
; Maximum allowable waiting time for the device to respond to a packet command (in ticks)
;-----------------------------------------------------------------------------
MaxCDWaitTime = 1000 ;200 ;10 seconds
uglobal
; Memory area for generating a packet command
PacketCommand:
rb 12 ;DB 12 DUP (?)
; address of reading data sector
CDSectorAddress: dd ?
; Start time of the next disk operation
TickCounter_1 dd 0
; Time to start waiting for device readiness
WURStartTime dd 0
; pointer to buffer to read data into
CDDataBuf_pointer dd 0
endg
;-----------------------------------------------------------------------------
;****************************************************
;* SEND TO ATAPI DEVICE PACKET COMMAND, *
;* THAT MEANS TRASMIT ONE DATA SECTOR OF SIZE *
;* 2048 BYTE FROM DEVICE TO HOST *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;* PacketCommand - 12-byte command packet; *
;* CDBlockSize - size of receiving data block. *
; return eax DevErrorCode
;****************************************************
SendPacketDatCommand:
xor eax, eax
; Set CHS mode
mov byte [ATAAddressMode], al
; Send ATA command to send packet command
mov byte [ATAFeatures], al
mov byte [ATASectorCount], al
mov byte [ATASectorNumber], al
; Load the size of the sending block
mov [ATAHead], al
mov [ATACylinder], CDBlockSize
mov [ATACommand], 0xA0
call SendCommandToHDD_1
test eax, eax
jnz @@End_8 ; finish, saving the error code
; Waiting for the drive to be ready to receive a packet command
mov dx, [ATABasePortAddr]
add dx, 7 ; port 1x7h
mov ecx, NoTickWaitTime
;--------------------------------------
align 4
@@WaitDevice0:
cmp [timer_ticks_enable], 0
jne @f
 
dec ecx
jz @@Err1_1
 
jmp .test
;--------------------------------------
align 4
@@:
call change_task
; Check command execution time
mov eax, [timer_ticks]
sub eax, [TickCounter_1]
cmp eax, BSYWaitTime
ja @@Err1_1 ; time out error
; Check readiness
;--------------------------------------
align 4
.test:
in al, dx
test al, 0x80 ; BSY signal state
jnz @@WaitDevice0
 
test al, 1 ; ERR signal state
jnz @@Err6
 
test al, 0x8 ; DRQ signal state
jz @@WaitDevice0
; Send a packet command
cli
mov dx, [ATABasePortAddr]
mov ax, [PacketCommand]
out dx, ax
mov ax, [PacketCommand+2]
out dx, ax
mov ax, [PacketCommand+4]
out dx, ax
mov ax, [PacketCommand+6]
out dx, ax
mov ax, [PacketCommand+8]
out dx, ax
mov ax, [PacketCommand+10]
out dx, ax
sti
; Waiting for data to be ready
mov dx, [ATABasePortAddr]
add dx, 7 ; port 1x7h
mov ecx, NoTickWaitTime
;--------------------------------------
align 4
@@WaitDevice1:
cmp [timer_ticks_enable], 0
jne @f
 
dec ecx
jz @@Err1_1
 
jmp .test_1
;--------------------------------------
align 4
@@:
call change_task
; Check command execution time
mov eax, [timer_ticks]
sub eax, [TickCounter_1]
cmp eax, MaxCDWaitTime
ja @@Err1_1 ; time out error
; Check readiness
;--------------------------------------
align 4
.test_1:
in al, dx
test al, 0x80 ; BSY signal state
jnz @@WaitDevice1
 
test al, 1 ; ERR signal state
jnz @@Err6_temp
 
test al, 0x8 ; DRQ signal state
jz @@WaitDevice1
; Receive data block from controller
mov edi, [CDDataBuf_pointer]
; Load controller's data register address
mov dx, [ATABasePortAddr]
; Load the block size in bytes into the counter
xor ecx, ecx
mov cx, CDBlockSize
; Calculate block size in 16-bit words
shr cx, 1 ; divide block size by 2
; Receive data block
cli
cld
rep insw
sti
;--------------------------------------
; Successful completion of data receive
@@End_8:
xor eax, eax
ret
;--------------------------------------
; Write error code
@@Err1_1:
xor eax, eax
inc eax
ret
;--------------------------------------
@@Err6_temp:
mov eax, 7
ret
;--------------------------------------
@@Err6:
mov eax, 6
ret
;-----------------------------------------------------------------------------
;***********************************************
;* SEND TO ATAPI DEVICE PACKET COMMAND, *
;* THAT DOESNT MEAN TRANSMIT DATA *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;* PacketCommand - 12-byte command packet. *
;***********************************************
SendPacketNoDatCommand:
pushad
xor eax, eax
; Set CHS mode
mov byte [ATAAddressMode], al
; Send ATA command to send packet command
mov byte [ATAFeatures], al
mov byte [ATASectorCount], al
mov byte [ATASectorNumber], al
mov word [ATACylinder], ax
mov byte [ATAHead], al
mov [ATACommand], 0xA0
call SendCommandToHDD_1
test eax, eax
jnz @@End_9 ; finish, saving the error code
; Waiting for the drive to be ready to receive a packet command
mov dx, [ATABasePortAddr]
add dx, 7 ; port 1x7h
;--------------------------------------
align 4
@@WaitDevice0_1:
call change_task
; Check waiting time
mov eax, [timer_ticks]
sub eax, [TickCounter_1]
cmp eax, BSYWaitTime
ja @@Err1_3 ; time out error
; Check readiness
in al, dx
test al, 0x80 ; BSY signal state
jnz @@WaitDevice0_1
 
test al, 1 ; ERR signal state
jnz @@Err6_1
 
test al, 0x8 ; DRQ signal state
jz @@WaitDevice0_1
; Send packet command
; cli
mov dx, [ATABasePortAddr]
mov ax, word [PacketCommand]
out dx, ax
mov ax, word [PacketCommand+2]
out dx, ax
mov ax, word [PacketCommand+4]
out dx, ax
mov ax, word [PacketCommand+6]
out dx, ax
mov ax, word [PacketCommand+8]
out dx, ax
mov ax, word [PacketCommand+10]
out dx, ax
; sti
cmp [ignore_CD_eject_wait], 1
je @@clear_DEC
; Waiting for confirmation of command receive
mov dx, [ATABasePortAddr]
add dx, 7 ; port 1x7h
;--------------------------------------
align 4
@@WaitDevice1_1:
call change_task
; Check command execution time
mov eax, [timer_ticks]
sub eax, [TickCounter_1]
cmp eax, MaxCDWaitTime
ja @@Err1_3 ; time out error
; Wait for device release
in al, dx
test al, 0x80 ; BSY signal state
jnz @@WaitDevice1_1
 
test al, 1 ; ERR signal state
jnz @@Err6_1
 
test al, 0x40 ; DRDY signal state
jz @@WaitDevice1_1
;--------------------------------------
@@clear_DEC:
and [DevErrorCode], 0
popad
ret
;--------------------------------------
; Write error code
@@Err1_3:
xor eax, eax
inc eax
jmp @@End_9
;--------------------------------------
@@Err6_1:
mov eax, 6
;--------------------------------------
@@End_9:
mov [DevErrorCode], eax
popad
ret
;-----------------------------------------------------------------------------
;****************************************************
;* SEND COMMAND TO GIVEN DISK *
;* Input parameters are passed through the global *
;* variables: *
;* ChannelNumber - channel number (1 or 2); *
;* DiskNumber - disk number (0 or 1); *
;* ATAFeatures - "features"; *
;* ATASectorCount - sector count; *
;* ATASectorNumber - initial sector number; *
;* ATACylinder - initial cylinder number; *
;* ATAHead - initial head number; *
;* ATAAddressMode - addressing mode (0-CHS, 1-LBA); *
;* ATACommand - command code. *
;* If the function finished successfully: *
;* in ATABasePortAddr - base address of HDD; *
;* in DevErrorCode - zero. *
;* If error has occured then in DevErrorCode will *
;* be the error code. *
;****************************************************
SendCommandToHDD_1:
; Check the addressing mode code
cmp [ATAAddressMode], 1
ja @@Err2_4
; Check the channel number correctness
movzx ebx, [ChannelNumber]
dec ebx
cmp ebx, 1
ja @@Err3_4
; Set the base address
shl ebx, 2
mov eax, [cdpos]
dec eax
shr eax, 2
imul eax, sizeof.IDE_DATA
add eax, IDE_controller_1
add eax, ebx
mov ax, [eax+IDE_DATA.BAR0_val]
mov [ATABasePortAddr], ax
; Waiting for HDD ready to receive a command
; Choose desired disk
mov dx, [ATABasePortAddr]
add dx, 6 ; address of the heads register
mov al, [DiskNumber]
cmp al, 1 ; check the disk number
ja @@Err4_4
 
shl al, 4
or al, 10100000b
out dx, al
; Waiting for disk ready
inc dx
mov eax, [timer_ticks]
mov [TickCounter_1], eax
mov ecx, NoTickWaitTime
;--------------------------------------
align 4
@@WaitHDReady_2:
cmp [timer_ticks_enable], 0
jne @f
 
dec ecx
jz @@Err1_4
 
jmp .test
;--------------------------------------
align 4
@@:
call change_task
; Check waiting time
mov eax, [timer_ticks]
sub eax, [TickCounter_1]
cmp eax, BSYWaitTime ;300 ; wait for 3 seconds
ja @@Err1_4 ; time out error
;--------------------------------------
align 4
.test:
in al, dx ; Read the state register
; Check the state of BSY signal
test al, 0x80
jnz @@WaitHDReady_2
; Check the state of DRQ signal
test al, 0x8
jnz @@WaitHDReady_2
; load command to controller's registers
cli
mov dx, [ATABasePortAddr]
inc dx ; "features" register
mov al, [ATAFeatures]
out dx, al
inc dx ; sector counter
mov al, [ATASectorCount]
out dx, al
inc dx ; sector number register
mov al, [ATASectorNumber]
out dx, al
inc dx ; cylinder number (low byte)
mov ax, [ATACylinder]
out dx, al
inc dx ; cylinder number (high byte)
mov al, ah
out dx, al
inc dx ; head number / disk number
mov al, [DiskNumber]
shl al, 4
cmp [ATAHead], 0xF ; check head number
ja @@Err5_4
 
or al, [ATAHead]
or al, 10100000b
mov ah, [ATAAddressMode]
shl ah, 6
or al, ah
out dx, al
; Send command
mov al, [ATACommand]
inc dx ; command register
out dx, al
sti
;--------------------------------------
@@End_10:
xor eax, eax
ret
;--------------------------------------
; Write error code
@@Err1_4:
xor eax, eax
inc eax
ret
;--------------------------------------
@@Err2_4:
mov eax, 2
ret
;--------------------------------------
@@Err3_4:
mov eax, 3
ret
;--------------------------------------
@@Err4_4:
mov eax, 4
ret
;--------------------------------------
@@Err5_4:
mov eax, 5
ret
;-----------------------------------------------------------------------------
;*************************************************
;* WAIT FOR THE DEVICE IS READY FOR WORK *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;*************************************************
WaitUnitReady:
pusha
; Remember the peration start time
mov eax, [timer_ticks]
mov [WURStartTime], eax
; Clear the packet command buffer
call clear_packet_buffer
; Generate TEST UNIT READY command
mov [PacketCommand], word 0
; waiting loop for device readiness
mov ecx, NoTickWaitTime
;--------------------------------------
align 4
@@SendCommand:
; Send readiness check command
call SendPacketNoDatCommand
cmp [timer_ticks_enable], 0
jne @f
 
cmp [DevErrorCode], 0
je @@End_11
 
dec ecx
jz .Error
 
jmp @@SendCommand
;--------------------------------------
align 4
@@:
call change_task
; Check the error code
cmp [DevErrorCode], 0
je @@End_11
; Check waiting time
mov eax, [timer_ticks]
sub eax, [WURStartTime]
cmp eax, MaxCDWaitTime
jb @@SendCommand
;--------------------------------------
.Error:
; time out error
mov [DevErrorCode], 1
;--------------------------------------
@@End_11:
popa
ret
;-----------------------------------------------------------------------------
;*************************************************
;* FORBID DISK CHANGE *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;*************************************************
prevent_medium_removal:
pusha
; Clear the packet command buffer
call clear_packet_buffer
; Set command code
mov [PacketCommand], byte 0x1E
; Set "Forbid" code
mov [PacketCommand+4], byte 11b
; Send command
call SendPacketNoDatCommand
mov eax, ATAPI_IDE0_lock
add eax, [cdpos]
dec eax
mov [eax], byte 1
popa
ret
;-----------------------------------------------------------------------------
;*************************************************
;* ALLOW DISK CHANGE *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;*************************************************
allow_medium_removal:
pusha
; Clear the packet command buffer
call clear_packet_buffer
; Set command code
mov [PacketCommand], byte 0x1E
; unset "Forbid" code
mov [PacketCommand+4], byte 0
; Send command
call SendPacketNoDatCommand
mov eax, ATAPI_IDE0_lock
add eax, [cdpos]
dec eax
mov [eax], byte 0
popa
ret
;-----------------------------------------------------------------------------
;*************************************************
;* LOAD DISK TO THE DRIVE *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;*************************************************
LoadMedium:
pusha
; Clear the packet command buffer
call clear_packet_buffer
; Generate START/STOP UNIT command
; Set command code
mov [PacketCommand], word 0x1B
; Set disk loading operation
mov [PacketCommand+4], word 00000011b
; Send command
call SendPacketNoDatCommand
popa
ret
;-----------------------------------------------------------------------------
;*************************************************
;* REMOVE THE DISK FROM THE DRIVE *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;*************************************************
EjectMedium:
pusha
; Clear the packet command buffer
call clear_packet_buffer
; Generate START/STOP UNIT command
; Set command code
mov [PacketCommand], word 0x1B
; Set the operation to eject disk
mov [PacketCommand+4], word 00000010b
; Send command
call SendPacketNoDatCommand
popa
ret
;-----------------------------------------------------------------------------
;*************************************************
;* Check the event of pressing the eject button *
;* *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;*************************************************
proc check_ATAPI_device_event_has_work?
mov eax, [timer_ticks]
sub eax, [timer_ATAPI_check]
cmp eax, 100
jb .no
 
xor eax, eax
inc eax
ret
;--------------------------------------
.no:
xor eax, eax
ret
endp
;-----------------------------------------------------------------------------
align 4
check_ATAPI_device_event:
pusha
mov eax, [timer_ticks]
sub eax, [timer_ATAPI_check]
cmp eax, 100
jb .end_1
 
pushfd
mov al, [DRIVE_DATA+1]
and al, 11b
cmp al, 10b
jz .ide3
;--------------------------------------
.ide2_1:
mov al, [DRIVE_DATA+1]
and al, 1100b
cmp al, 1000b
jz .ide2
;--------------------------------------
.ide1_1:
mov al, [DRIVE_DATA+1]
and al, 110000b
cmp al, 100000b
jz .ide1
;--------------------------------------
.ide0_1:
mov al, [DRIVE_DATA+1]
and al, 11000000b
cmp al, 10000000b
jz .ide0
;--------------------------------------
.ide7_1:
mov al, [DRIVE_DATA+6]
and al, 11b
cmp al, 10b
jz .ide7
;--------------------------------------
.ide6_1:
mov al, [DRIVE_DATA+6]
and al, 1100b
cmp al, 1000b
jz .ide6
;--------------------------------------
.ide5_1:
mov al, [DRIVE_DATA+6]
and al, 110000b
cmp al, 100000b
jz .ide5
;--------------------------------------
.ide4_1:
mov al, [DRIVE_DATA+6]
and al, 11000000b
cmp al, 10000000b
jz .ide4
;--------------------------------------
.ide11_1:
mov al, [DRIVE_DATA+11]
and al, 11b
cmp al, 10b
jz .ide11
;--------------------------------------
.ide10_1:
mov al, [DRIVE_DATA+11]
and al, 1100b
cmp al, 1000b
jz .ide10
;--------------------------------------
.ide9_1:
mov al, [DRIVE_DATA+11]
and al, 110000b
cmp al, 100000b
jz .ide9
;--------------------------------------
.ide8_1:
mov al, [DRIVE_DATA+11]
and al, 11000000b
cmp al, 10000000b
jz .ide8
;--------------------------------------
.end:
popfd
mov eax, [timer_ticks]
mov [timer_ATAPI_check], eax
;--------------------------------------
.end_1:
popa
ret
;-----------------------------------------------------------------------------
.ide3:
cli
cmp [ATAPI_IDE3_lock], 1
jne .ide2_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel2_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 2
mov [DiskNumber], 1
mov [cdpos], 4
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide2_1
;-----------------------------------------------------------------------------
.ide2:
cli
cmp [ATAPI_IDE2_lock], 1
jne .ide1_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel2_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 2
mov [DiskNumber], 0
mov [cdpos], 3
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide1_1
;-----------------------------------------------------------------------------
.ide1:
cli
cmp [ATAPI_IDE1_lock], 1
jne .ide0_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel1_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 1
mov [DiskNumber], 1
mov [cdpos], 2
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide0_1
;-----------------------------------------------------------------------------
.ide0:
cli
cmp [ATAPI_IDE0_lock], 1
jne .ide7_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel1_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 1
mov [DiskNumber], 0
mov [cdpos], 1
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide7_1
;-----------------------------------------------------------------------------
.ide7:
cli
cmp [ATAPI_IDE7_lock], 1
jne .ide6_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel4_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 2
mov [DiskNumber], 1
mov [cdpos], 8
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide6_1
;-----------------------------------------------------------------------------
.ide6:
cli
cmp [ATAPI_IDE6_lock], 1
jne .ide5_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel4_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 2
mov [DiskNumber], 0
mov [cdpos], 7
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide5_1
;-----------------------------------------------------------------------------
.ide5:
cli
cmp [ATAPI_IDE5_lock], 1
jne .ide4_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel3_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 1
mov [DiskNumber], 1
mov [cdpos], 6
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide4_1
;-----------------------------------------------------------------------------
.ide4:
cli
cmp [ATAPI_IDE4_lock], 1
jne .ide11_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel3_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 1
mov [DiskNumber], 0
mov [cdpos], 5
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide11_1
;-----------------------------------------------------------------------------
.ide11:
cli
cmp [ATAPI_IDE11_lock], 1
jne .ide10_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel6_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 2
mov [DiskNumber], 1
mov [cdpos], 12
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide10_1
;-----------------------------------------------------------------------------
.ide10:
cli
cmp [ATAPI_IDE10_lock], 1
jne .ide9_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel6_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 2
mov [DiskNumber], 0
mov [cdpos], 11
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide9_1
;-----------------------------------------------------------------------------
.ide9:
cli
cmp [ATAPI_IDE9_lock], 1
jne .ide8_1
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel5_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 1
mov [DiskNumber], 1
mov [cdpos], 10
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .ide8_1
;-----------------------------------------------------------------------------
.ide8:
cli
cmp [ATAPI_IDE8_lock], 1
jne .end
 
cmp [cd_status], 0
jne .end
 
mov ecx, ide_channel5_mutex
call mutex_lock
call reserve_ok2
mov [ChannelNumber], 1
mov [DiskNumber], 0
mov [cdpos], 9
call GetEvent_StatusNotification
cmp [CDDataBuf+4], byte 1
jne @f
 
call .eject
;--------------------------------------
@@:
call syscall_cdaudio.free
jmp .end
;-----------------------------------------------------------------------------
.eject:
call clear_CD_cache
call allow_medium_removal
mov [ignore_CD_eject_wait], 1
call EjectMedium
mov [ignore_CD_eject_wait], 0
ret
;-----------------------------------------------------------------------------
iglobal
timer_ATAPI_check dd 0
ATAPI_IDE0_lock db 0
ATAPI_IDE1_lock db 0
ATAPI_IDE2_lock db 0
ATAPI_IDE3_lock db 0
ATAPI_IDE4_lock db 0
ATAPI_IDE5_lock db 0
ATAPI_IDE6_lock db 0
ATAPI_IDE7_lock db 0
ATAPI_IDE8_lock db 0
ATAPI_IDE9_lock db 0
ATAPI_IDE10_lock db 0
ATAPI_IDE11_lock db 0
ignore_CD_eject_wait db 0
endg
;-----------------------------------------------------------------------------
;*************************************************
;* Get an event or device status message *
;* *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel *
;*************************************************
GetEvent_StatusNotification:
pusha
mov [CDDataBuf_pointer], CDDataBuf
; Clear the packet command buffer
call clear_packet_buffer
; Set command code
mov [PacketCommand], byte 4Ah
mov [PacketCommand+1], byte 00000001b
; Set message class request
mov [PacketCommand+4], byte 00010000b
; Size of allocated area
mov [PacketCommand+7], byte 8h
mov [PacketCommand+8], byte 0h
; Send command
call SendPacketDatCommand
popa
ret
;-----------------------------------------------------------------------------
;*************************************************
; Read information from TOC (Table of contents) *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel *
;*************************************************
Read_TOC:
pusha
mov [CDDataBuf_pointer], CDDataBuf
; Clear the packet command buffer
call clear_packet_buffer
; Generate a packet command to read a data sector
mov [PacketCommand], byte 0x43
; Set format
mov [PacketCommand+2], byte 1
; Size of allocated area
mov [PacketCommand+7], byte 0xFF
mov [PacketCommand+8], byte 0h
; Send a command
call SendPacketDatCommand
popa
ret
;-----------------------------------------------------------------------------
;*****************************************************
;* DETERMINE THE TOTAL NUMBER OF SECTORS ON THE DISK *
;* Input parameters are passed through global *
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel *
;*****************************************************
;ReadCapacity:
; pusha
;; Clear the packet command buffer
; call clear_packet_buffer
;; Set the buffer size in bytes
; mov [CDBlockSize],8
;; Generate READ CAPACITY command
; mov [PacketCommand],word 25h
;; Send command
; call SendPacketDatCommand
; popa
; ret
;-----------------------------------------------------------------------------
clear_packet_buffer:
; Clear the packet command buffer
and [PacketCommand], dword 0
and [PacketCommand+4], dword 0
and [PacketCommand+8], dword 0
ret
;-----------------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/bd_drv.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/hd_drv.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/disk_cache.inc
0,0 → 1,1387
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2011-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; Read/write functions try to do large operations,
; it is significantly faster than several small operations.
; This requires large buffers.
; We can't use input/output buffers directly - they can be controlled
; by user-mode application, so they can be modified between the operation
; and copying to/from cache, giving invalid data in cache.
; It is unclear how to use cache directly, currently cache items are
; allocated/freed sector-wise, so items for sequential sectors can be
; scattered over all the cache.
; So read/write functions allocate a temporary buffer which is
; 1) not greater than half of free memory and
; 2) not greater than the following constant.
CACHE_MAX_ALLOC_SIZE = 4 shl 20
 
; Legacy interface for filesystems fs_{read,write}32_{sys,app}
; gives only one sector for FS. However, per-sector reading is inefficient,
; so internally fs_read32_{sys,app} reads to the cache several sequential
; sectors, hoping that they will be useful.
; Total number of sectors is given by the following constant.
CACHE_LEGACY_READ_SIZE = 16
 
; This structure describes one item in the cache.
struct CACHE_ITEM
SectorLo dd ? ; low 32 bits of sector
SectorHi dd ? ; high 32 bits of sector
Status dd ? ; one of CACHE_ITEM_*
ends
 
; Possible values for CACHE_ITEM_*
CACHE_ITEM_EMPTY = 0
CACHE_ITEM_COPY = 1
CACHE_ITEM_MODIFIED = 2
 
; Read several sequential sectors using cache #1.
; in: edx:eax = start sector, relative to start of partition
; in: ecx = number of sectors to read
; in: ebx -> buffer
; in: ebp -> PARTITION
; out: eax = error code, 0 = ok
; out: ecx = number of sectors that were read
fs_read64_sys:
; Save ebx, set ebx to SysCache and let the common part do its work.
push ebx ebx
mov ebx, [ebp+PARTITION.Disk]
add ebx, DISK.SysCache
jmp fs_read64_common
 
; Read several sequential sectors using cache #2.
; in: edx:eax = start sector, relative to start of partition
; in: ecx = number of sectors to read
; in: edi -> buffer
; in: ebp -> PARTITION
; out: eax = error code, 0 = ok
; out: ecx = number of sectors that were read
fs_read64_app:
; Save ebx, set ebx to AppCache and let the common part do its work.
push ebx ebx
mov ebx, [ebp+PARTITION.Disk]
add ebx, DISK.AppCache
 
; Common part of fs_read64_{app,sys}:
; read several sequential sectors using the given cache.
fs_read64_common:
; 1. Setup stack frame.
push esi edi ; save used registers to be stdcall
push 0 ; initialize .error_code
push ebx edx eax ecx ecx ; initialize stack variables
virtual at esp
.local_vars:
.num_sectors_orig dd ?
; Number of sectors that should be read. Used to generate output value of ecx.
.num_sectors dd ?
; Number of sectors that remain to be read. Decreases from .num_sectors_orig to 0.
.sector_lo dd ? ; low 32 bits of the current sector
.sector_hi dd ? ; high 32 bits of the current sector
.cache dd ? ; pointer to DISKCACHE
.error_code dd ? ; current status
.local_vars_size = $ - .local_vars
.saved_regs rd 2
.buffer dd ? ; filled by fs_read64_{sys,app}
end virtual
; 2. Validate parameters against partition length:
; immediately return error if edx:eax are beyond partition end,
; decrease .num_sectors and .num_sectors_orig, if needed,
; so that the entire operation fits in the partition limits.
mov eax, dword [ebp+PARTITION.Length]
mov edx, dword [ebp+PARTITION.Length+4]
sub eax, [.sector_lo]
sbb edx, [.sector_hi]
jb .end_of_media
jnz .no_end_of_media
cmp ecx, eax
jbe .no_end_of_media
; If .num_sectors got decreased, set status to DISK_STATUS_END_OF_MEDIA;
; if all subsequent operations would be successful, this would become the final
; status, otherwise this would be rewritten by failed operation.
mov [.num_sectors], eax
mov [.num_sectors_orig], eax
mov [.error_code], DISK_STATUS_END_OF_MEDIA
.no_end_of_media:
; 3. If number of sectors to read is zero, either because zero-sectors operation
; was requested or because it got decreased to zero due to partition limits,
; just return the current status.
cmp [.num_sectors], 0
jz .return
; 4. Shift sector from partition-relative to absolute.
mov eax, dword [ebp+PARTITION.FirstSector]
mov edx, dword [ebp+PARTITION.FirstSector+4]
add [.sector_lo], eax
adc [.sector_hi], edx
; 5. If the cache is disabled, pass the request directly to the driver.
cmp [ebx+DISKCACHE.pointer], 0
jz .nocache
; 6. Look for sectors in the cache, sequentially from the beginning.
; Stop at the first sector that is not in the cache
; or when all sectors were read from the cache.
; 6a. Acquire the lock.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_lock
.lookup_in_cache_loop:
; 6b. For each sector, call the lookup function without adding to the cache.
mov eax, [.sector_lo]
mov edx, [.sector_hi]
call cache_lookup_read
; 6c. If it has failed, the sector is not in cache;
; release the lock and go to 7.
jc .not_found_in_cache
; The sector is found in cache.
; 6d. Copy data for the caller, advance [.buffer].
mov esi, edi
mov edi, [.buffer]
mov eax, 1
shl eax, cl
mov ecx, eax
shr ecx, 2
rep movsd
mov [.buffer], edi
; 6e. Advance the sector.
add [.sector_lo], 1
adc [.sector_hi], 0
; 6f. Decrement number of sectors left.
; If all sectors were read, release the lock and return.
dec [.num_sectors]
jnz .lookup_in_cache_loop
; Release the lock acquired at 6a.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_unlock
.return:
mov eax, [.error_code]
mov ecx, [.num_sectors_orig]
sub ecx, [.num_sectors]
.nothing:
add esp, .local_vars_size
pop edi esi ebx ebx ; restore used registers to be stdcall
ret
.not_found_in_cache:
; Release the lock acquired at 6a.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_unlock
; The current sector is not present in the cache.
; Ask the driver to read all requested not-yet-read sectors,
; put results in the cache.
; Also, see the comment before the definition of CACHE_MAX_ALLOC_SIZE.
; 7. Allocate buffer for operations.
; Normally, create buffer that is sufficient for all remaining data.
; However, for extra-large requests make an upper limit:
; do not use more than half of the free memory
; or more than CACHE_MAX_ALLOC_SIZE bytes.
mov ecx, [ebx+DISKCACHE.sector_size_log]
mov ebx, [pg_data.pages_free]
shr ebx, 1
jz .nomemory
cmp ebx, CACHE_MAX_ALLOC_SIZE shr 12
jbe @f
mov ebx, CACHE_MAX_ALLOC_SIZE shr 12
@@:
shl ebx, 12
shr ebx, cl
jz .nomemory
cmp ebx, [.num_sectors]
jbe @f
mov ebx, [.num_sectors]
@@:
mov eax, ebx
shl eax, cl
stdcall kernel_alloc, eax
; If failed, return the appropriate error code.
test eax, eax
jz .nomemory
mov esi, eax
; Split the request to chunks that fit in the allocated buffer.
.read_loop:
; 8. Get iteration size: either size of allocated buffer in sectors
; or number of sectors left, select what is smaller.
cmp ebx, [.num_sectors]
jbe @f
mov ebx, [.num_sectors]
@@:
; 9. Create second portion of local variables.
; Note that variables here and above are esp-relative;
; it means that all addresses should be corrected when esp is changing.
push ebx esi esi
push ebx
; In particular, num_sectors is now [.num_sectors+.local_vars2_size].
virtual at esp
.local_vars2:
.current_num_sectors dd ? ; number of sectors that were read
.current_buffer dd ?
; pointer inside .allocated_buffer that points
; to the beginning of not-processed data
.allocated_buffer dd ? ; saved in safe place
.iteration_size dd ? ; saved in safe place
.local_vars2_size = $ - .local_vars2
end virtual
; 10. Call the driver, reading the next chunk.
push esp ; numsectors
push [.sector_hi+.local_vars2_size+4] ; startsector
push [.sector_lo+.local_vars2_size+8] ; startsector
push esi ; buffer
mov esi, [ebp+PARTITION.Disk]
mov al, DISKFUNC.read
call disk_call_driver
; If failed, save error code.
test eax, eax
jz @f
mov [.error_code+.local_vars2_size], eax
@@:
; 11. Copy data for the caller, advance .buffer.
cmp [.current_num_sectors], 0
jz .copy_done
mov ebx, [.cache+.local_vars2_size]
mov eax, [.current_num_sectors]
mov ecx, [ebx+DISKCACHE.sector_size_log]
shl eax, cl
mov esi, [.allocated_buffer]
mov edi, [.buffer+.local_vars2_size]
mov ecx, eax
shr ecx, 2
rep movsd
mov [.buffer+.local_vars2_size], edi
; 12. Copy data to the cache.
; 12a. Acquire the lock.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_lock
; 12b. Prepare for the loop: create a local variable that
; stores number of sectors to be copied.
push [.current_num_sectors]
.store_to_cache:
; 12c. For each sector, call the lookup function with adding to the cache, if not yet.
mov eax, [.sector_lo+.local_vars2_size+4]
mov edx, [.sector_hi+.local_vars2_size+4]
call cache_lookup_write
test eax, eax
jnz .cache_error
; 12d. If the sector was already present in the cache as modified,
; data that were read at step 10 for this sector are obsolete,
; so rewrite data for the caller from the cache.
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
jnz .not_modified
mov esi, edi
mov edi, [.buffer+.local_vars2_size+4]
mov eax, [esp]
shl eax, cl
sub edi, eax
mov eax, 1
shl eax, cl
mov ecx, eax
shr ecx, 2
rep movsd
add [.current_buffer+4], eax
jmp .sector_done
.not_modified:
; 12e. For each not-modified sector,
; copy data, mark the item as not-modified copy of the disk,
; advance .current_buffer and .sector_hi:.sector_lo to the next sector.
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY
mov eax, 1
shl eax, cl
mov esi, [.current_buffer+4]
mov ecx, eax
shr ecx, 2
rep movsd
mov [.current_buffer+4], esi
.sector_done:
add [.sector_lo+.local_vars2_size+4], 1
adc [.sector_hi+.local_vars2_size+4], 0
; 12f. Continue the loop 12c-12e until all sectors are read.
dec dword [esp]
jnz .store_to_cache
.cache_error:
; 12g. Restore after the loop: pop the local variable.
pop ecx
; 12h. Release the lock.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_unlock
.copy_done:
; 13. Remove portion of local variables created at step 9.
pop ecx
pop esi esi ebx
; 14. Continue iterations while number of sectors read by the driver
; is equal to number of sectors requested and there are additional sectors.
cmp ecx, ebx
jnz @f
sub [.num_sectors], ebx
jnz .read_loop
@@:
; 15. Free the buffer allocated at step 7 and return.
stdcall kernel_free, esi
jmp .return
 
; Special branches:
.nomemory:
; memory allocation failed at step 7: return the corresponding error
mov [.error_code], DISK_STATUS_NO_MEMORY
jmp .return
.nocache:
; step 5, after correcting number of sectors to fit in partition limits
; and advancing partition-relative sector to absolute,
; sees that cache is disabled: pass corrected request to the driver
lea eax, [.num_sectors]
push eax ; numsectors
push [.sector_hi+4] ; startsector
push [.sector_lo+8] ; startsector
push [.buffer+12] ; buffer
mov esi, [ebp+PARTITION.Disk]
mov al, DISKFUNC.read
call disk_call_driver
test eax, eax
jnz @f
mov eax, [.error_code]
@@:
mov ecx, [.num_sectors]
jmp .nothing
.end_of_media:
; requested sector is beyond the partition end: return the corresponding error
mov [.error_code], DISK_STATUS_END_OF_MEDIA
jmp .return
 
; Write several sequential sectors using cache #1.
; in: edx:eax = start sector
; in: ecx = number of sectors to write
; in: ebx -> buffer
; in: ebp -> PARTITION
; out: eax = error code, 0 = ok
; out: ecx = number of sectors that were written
fs_write64_sys:
; Save ebx, set ebx to SysCache and let the common part do its work.
push ebx
mov ebx, [ebp+PARTITION.Disk]
add ebx, DISK.SysCache
jmp fs_write64_common
 
; Write several sequential sectors using cache #2.
; in: edx:eax = start sector
; in: ecx = number of sectors to write
; in: ebx -> buffer
; in: ebp -> PARTITION
; out: eax = error code, 0 = ok
; out: ecx = number of sectors that were written
fs_write64_app:
; Save ebx, set ebx to AppCache and let the common part do its work.
push ebx
mov ebx, [ebp+PARTITION.Disk]
add ebx, DISK.AppCache
 
; Common part of fs_write64_{app,sys}:
; write several sequential sectors using the given cache.
fs_write64_common:
; 1. Setup stack frame.
push esi edi ; save used registers to be stdcall
push 0 ; initialize .error_code
push edx eax ecx ecx ; initialize stack variables
push [.buffer-4] ; copy [.buffer] to [.cur_buffer]
; -4 is due to esp-relative addressing
virtual at esp
.local_vars:
.cur_buffer dd ? ; pointer to data that are currently copying
.num_sectors_orig dd ?
; Number of sectors that should be written. Used to generate output value of ecx.
.num_sectors dd ?
; Number of sectors that remain to be written.
.sector_lo dd ? ; low 32 bits of the current sector
.sector_hi dd ? ; high 32 bits of the current sector
.error_code dd ? ; current status
.local_vars_size = $ - .local_vars
.saved_regs rd 2
.buffer dd ? ; filled by fs_write64_{sys,app}
end virtual
; 2. Validate parameters against partition length:
; immediately return error if edx:eax are beyond partition end,
; decrease .num_sectors and .num_sectors_orig, if needed,
; so that the entire operation fits in the partition limits.
mov eax, dword [ebp+PARTITION.Length]
mov edx, dword [ebp+PARTITION.Length+4]
sub eax, [.sector_lo]
sbb edx, [.sector_hi]
jb .end_of_media
jnz .no_end_of_media
cmp ecx, eax
jbe .no_end_of_media
; If .num_sectors got decreased, set status to DISK_STATUS_END_OF_MEDIA;
; if all subsequent operations would be successful, this would become the final
; status, otherwise this would be rewritten by failed operation.
mov [.num_sectors], eax
mov [.num_sectors_orig], eax
mov [.error_code], DISK_STATUS_END_OF_MEDIA
.no_end_of_media:
; 3. If number of sectors to write is zero, either because zero-sectors operation
; was requested or because it got decreased to zero due to partition limits,
; just return the current status.
cmp [.num_sectors], 0
jz .return
; 4. Shift sector from partition-relative to absolute.
mov eax, dword [ebp+PARTITION.FirstSector]
mov edx, dword [ebp+PARTITION.FirstSector+4]
add [.sector_lo], eax
adc [.sector_hi], edx
; 5. If the cache is disabled, pass the request directly to the driver.
cmp [ebx+DISKCACHE.pointer], 0
jz .nocache
; 6. Store sectors in the cache, sequentially from the beginning.
; 6a. Acquire the lock.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_lock
.lookup_in_cache_loop:
; 6b. For each sector, call the lookup function with adding to the cache, if not yet.
mov eax, [.sector_lo]
mov edx, [.sector_hi]
call cache_lookup_write
test eax, eax
jnz .cache_error
; 6c. For each sector, copy data, mark the item as modified and not saved,
; advance .current_buffer to the next sector.
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
mov eax, 1
shl eax, cl
mov esi, [.cur_buffer]
mov ecx, eax
shr ecx, 2
rep movsd
mov [.cur_buffer], esi
; 6d. Remove the sector from the other cache.
; Normally it should not be there, but prefetching could put to the app cache
; data that normally should belong to the sys cache and vice versa.
; Note: this requires that both caches must be protected by the same lock.
mov eax, [.sector_lo]
mov edx, [.sector_hi]
push ebx
sub ebx, [ebp+PARTITION.Disk]
xor ebx, DISK.SysCache xor DISK.AppCache
add ebx, [ebp+PARTITION.Disk]
call cache_lookup_read
jc @f
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY
@@:
pop ebx
; 6e. Advance .sector_hi:.sector_lo to the next sector.
add [.sector_lo], 1
adc [.sector_hi], 0
; 6f. Continue the loop at 6b-6e until all sectors are processed.
dec [.num_sectors]
jnz .lookup_in_cache_loop
.unlock_return:
; 6g. Release the lock and return.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_unlock
.return:
mov eax, [.error_code]
mov ecx, [.num_sectors_orig]
sub ecx, [.num_sectors]
.nothing:
add esp, .local_vars_size
pop edi esi ebx
ret
 
; Special branches:
.cache_error:
; error at flushing the cache while adding sector to the cache:
; return the error from the lookup function
mov [.error_code], eax
jmp .unlock_return
.end_of_media:
; requested sector is beyond the partition end: return the corresponding error
mov eax, DISK_STATUS_END_OF_MEDIA
xor ecx, ecx
jmp .nothing
.nocache:
; step 5, after correcting number of sectors to fit in partition limits
; and advancing partition-relative sector to absolute,
; sees that cache is disabled: pass corrected request to the driver
lea eax, [.num_sectors]
push eax ; numsectors
push [.sector_hi+4] ; startsector
push [.sector_lo+8] ; startsector
push [.buffer+12] ; buffer
mov esi, [ebp+PARTITION.Disk]
mov al, DISKFUNC.write
call disk_call_driver
mov ecx, [.num_sectors]
jmp .nothing
 
; Legacy. Use fs_read64_sys instead.
; This function is intended to replace the old 'hd_read' function when
; [hdd_appl_data] = 0, so its input/output parameters are the same, except
; that it can't use the global variables 'hd_error' and 'hdd_appl_data'.
; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure
; eax is relative to partition start
; out: eax = error code; 0 = ok
fs_read32_sys:
; Save ebx, set ebx to SysCache and let the common part do its work.
push ebx
mov ebx, [ebp+PARTITION.Disk]
add ebx, DISK.SysCache
jmp fs_read32_common
 
; Legacy. Use fs_read64_app instead.
; This function is intended to replace the old 'hd_read' function when
; [hdd_appl_data] = 1, so its input/output parameters are the same, except
; that it can't use the global variables 'hd_error' and 'hdd_appl_data'.
; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure
; eax is relative to partition start
; out: eax = error code; 0 = ok
fs_read32_app:
; Save ebx, set ebx to AppCache and let the common part do its work.
push ebx
mov ebx, [ebp+PARTITION.Disk]
add ebx, DISK.AppCache
 
; This label is the common part of fs_read32_sys and fs_read32_app.
fs_read32_common:
; 1. Check that the required sector is inside the partition. If no, return
; DISK_STATUS_END_OF_MEDIA.
cmp dword [ebp+PARTITION.Length+4], 0
jnz @f
cmp dword [ebp+PARTITION.Length], eax
ja @f
mov eax, DISK_STATUS_END_OF_MEDIA
pop ebx
ret
@@:
; 2. Get the absolute sector on the disk.
push ecx edx esi edi
xor edx, edx
add eax, dword [ebp+PARTITION.FirstSector]
adc edx, dword [ebp+PARTITION.FirstSector+4]
; 3. If there is no cache for this disk, just pass the request to the driver.
cmp [ebx+DISKCACHE.pointer], 0
jnz .scancache
push 1
push esp ; numsectors
push edx ; startsector
push eax ; startsector
pushd [esp+32]; buffer
mov esi, [ebp+PARTITION.Disk]
mov al, DISKFUNC.read
call disk_call_driver
pop ecx
pop edi esi edx ecx
pop ebx
ret
.scancache:
push ebx edx eax
virtual at esp
.local_vars:
.sector_lo dd ?
.sector_hi dd ?
.cache dd ?
.local_vars_size = $ - .local_vars
.saved_regs rd 4
.buffer dd ?
end virtual
; 4. Scan for the requested sector in the cache.
; If found, copy the data and return.
; 4a. Acquire the lock.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_lock
; 4b. Call the lookup function without adding to the cache.
mov eax, [.sector_lo]
mov edx, [.sector_hi]
call cache_lookup_read
; If not found, go to 5.
jc .not_found_in_cache
.found_in_cache:
; 4c. Copy the data.
mov esi, edi
mov edi, [.buffer]
mov eax, 1
shl eax, cl
mov ecx, eax
shr ecx, 2
rep movsd
; 4d. Release the lock and return success.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_unlock
.return:
xor eax, eax
.return_eax:
add esp, .local_vars_size
pop edi esi edx ecx
pop ebx
ret
.not_found_in_cache:
; 5. Decide whether we need to prefetch further sectors.
; If so, advance to 6. If not, go to 13.
; Assume that devices < 3MB are floppies which are slow
; (ramdisk does not have a cache, so we don't even get here for ramdisk).
; This is a dirty hack, but the entire function is somewhat hacky. Use fs_read64*.
mov ecx, [ebp+PARTITION.Disk]
cmp dword [ecx+DISK.MediaInfo.Capacity+4], 0
jnz @f
cmp dword [ecx+DISK.MediaInfo.Capacity], 3 shl (20-9)
jb .floppy
@@:
; We want to prefetch CACHE_LEGACY_READ_SIZE sectors.
; 6. Release the lock acquired at step 4a.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_unlock
; 7. Allocate buffer for CACHE_LEGACY_READ_SIZE sectors.
mov eax, CACHE_LEGACY_READ_SIZE
mov ecx, [ebx+DISKCACHE.sector_size_log]
shl eax, cl
stdcall kernel_alloc, eax
; If failed, return the corresponding error code.
test eax, eax
jz .nomemory
; 8. Create second portion of local variables.
push eax eax
push CACHE_LEGACY_READ_SIZE
virtual at esp
.local_vars2:
.num_sectors dd ? ; number of sectors left
.current_buffer dd ? ; pointer to data that are currently copying
.allocated_buffer dd ? ; saved at safe place
.local_vars2_size = $ - .local_vars2
end virtual
; 9. Call the driver to read CACHE_LEGACY_READ_SIZE sectors.
push esp ; numsectors
push [.sector_hi+.local_vars2_size+4] ; startsector
push [.sector_lo+.local_vars2_size+8] ; startsector
push eax ; buffer
mov esi, [ebp+PARTITION.Disk]
mov al, DISKFUNC.read
call disk_call_driver
; Note: we're ok if at least one sector is read,
; read error somewhere after that just limits data to be put in cache.
cmp [.num_sectors], 0
jz .read_error
; 10. Copy data for the caller.
mov esi, [.allocated_buffer]
mov edi, [.buffer+.local_vars2_size]
mov ecx, [ebx+DISKCACHE.sector_size_log]
mov eax, 1
shl eax, cl
mov ecx, eax
shr ecx, 2
rep movsd
; 11. Store all sectors that were successfully read to the cache.
; 11a. Acquire the lock.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_lock
.store_to_cache:
; 11b. For each sector, call the lookup function with adding to the cache, if not yet.
mov eax, [.sector_lo+.local_vars2_size]
mov edx, [.sector_hi+.local_vars2_size]
call cache_lookup_write
test eax, eax
jnz .cache_error
; 11c. Ignore sectors marked as modified: for them the cache is more recent that disk data.
mov eax, 1
shl eax, cl
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
jnz .not_modified
add [.current_buffer], eax
jmp .sector_done
.not_modified:
; 11d. For each sector, copy data, mark the item as not-modified copy of the disk,
; advance .current_buffer and .sector_hi:.sector_lo to the next sector.
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY
mov esi, [.current_buffer]
mov ecx, eax
shr ecx, 2
rep movsd
mov [.current_buffer], esi
.sector_done:
add [.sector_lo+.local_vars2_size], 1
adc [.sector_hi+.local_vars2_size], 0
; 11e. Continue the loop at 11b-11d until all sectors are processed.
dec [.num_sectors]
jnz .store_to_cache
.cache_error:
; 11f. Release the lock.
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
call mutex_unlock
.copy_done:
; 12. Remove portion of local variables created at step 8,
; free the buffer allocated at step 7 and return.
pop ecx ecx
stdcall kernel_free
jmp .return
.read_error:
; If no sectors were read, free the buffer allocated at step 7
; and pass the error to the caller.
push eax
stdcall kernel_free, [.allocated_buffer+4]
pop eax
add esp, .local_vars2_size
jmp .return_eax
.nomemory:
mov eax, DISK_STATUS_NO_MEMORY
jmp .return_eax
.floppy:
; We don't want to prefetch anything, just read one sector.
; We are still holding the lock acquired at step 4a.
; 13. Call the lookup function adding sector to the cache.
call cache_lookup_write
test eax, eax
jnz .floppy_cache_error
push esi
 
; 14. Call the driver to read one sector.
push 1
push esp
push edx
push [.sector_lo+16]
push edi
mov esi, [ebp+PARTITION.Disk]
mov al, DISKFUNC.read
call disk_call_driver
pop ecx
dec ecx
jnz .floppy_read_error
; 15. Get the slot and pointer to the cache item,
; change the status to not-modified copy of the disk
; and go to 4c.
pop esi
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY
mov ecx, [ebx+DISKCACHE.sector_size_log]
jmp .found_in_cache
 
; On error at steps 13-14, release the lock
; and pass the error to the caller.
.floppy_read_error:
pop ecx
.floppy_cache_error:
mov ecx, [ebp+PARTITION.Disk]
add ecx, DISK.CacheLock
push eax
call mutex_unlock
pop eax
jmp .return_eax
 
; This function is intended to replace the old 'hd_write' function when
; [hdd_appl_data] = 0, so its input/output parameters are the same, except
; that it can't use the global variables 'hd_error' and 'hdd_appl_data'.
; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure
; eax is relative to partition start
; out: eax = error code; 0 = ok
fs_write32_sys:
; Just call the advanced function.
push ecx edx
xor edx, edx
mov ecx, 1
call fs_write64_sys
pop edx ecx
ret
 
; This function is intended to replace the old 'hd_write' function when
; [hdd_appl_data] = 1, so its input/output parameters are the same, except
; that it can't use the global variables 'hd_error' and 'hdd_appl_data'.
; in: eax = sector, ebx = buffer, ebp = pointer to PARTITION structure
; eax is relative to partition start
; out: eax = error code; 0 = ok
fs_write32_app:
; Just call the advanced function.
push ecx edx
xor edx, edx
mov ecx, 1
call fs_write64_app
pop edx ecx
ret
 
; Lookup for the given sector in the given cache.
; If the sector is not present, return error.
; The caller must acquire the cache lock.
; in: edx:eax = sector
; in: ebx -> DISKCACHE structure
; out: CF set if sector is not in cache
; out: ecx = sector_size_log
; out: esi -> sector:status
; out: edi -> sector data
proc cache_lookup_read
mov esi, [ebx+DISKCACHE.pointer]
add esi, sizeof.CACHE_ITEM
 
mov edi, 1
 
.hdreadcache:
 
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY
je .nohdcache
 
cmp [esi+CACHE_ITEM.SectorLo], eax
jne .nohdcache
cmp [esi+CACHE_ITEM.SectorHi], edx
jne .nohdcache
mov ecx, [ebx+DISKCACHE.sector_size_log]
shl edi, cl
add edi, [ebx+DISKCACHE.data]
clc
ret
 
.nohdcache:
 
add esi, sizeof.CACHE_ITEM
inc edi
cmp edi, [ebx+DISKCACHE.sad_size]
jbe .hdreadcache
stc
ret
endp
 
; Lookup for the given sector in the given cache.
; If the sector is not present, allocate space for it,
; possibly flushing data.
; in: edx:eax = sector
; in: ebx -> DISKCACHE structure
; in: ebp -> PARTITION structure
; out: eax = error code
; out: esi -> sector:status
; out: edi -> sector data
proc cache_lookup_write
call cache_lookup_read
jnc .return0
push edx eax
;-----------------------------------------------------------
; find empty or read slot, flush cache if next 12.5% is used by write
; output : ecx = cache slot
;-----------------------------------------------------------
; Note: the code is essentially inherited, so probably
; no analysis of efficiency were done.
; However, it works.
.search_again:
mov eax, [ebx+DISKCACHE.sad_size]
mov ecx, [ebx+DISKCACHE.search_start]
shr eax, 3
lea esi, [ecx*sizeof.CACHE_ITEM/4]
shl esi, 2
add esi, [ebx+DISKCACHE.pointer]
.search_for_empty:
inc ecx
add esi, sizeof.CACHE_ITEM
cmp ecx, [ebx+DISKCACHE.sad_size]
jbe .inside_cache
mov ecx, 1
mov esi, [ebx+DISKCACHE.pointer]
add esi, sizeof.CACHE_ITEM
.inside_cache:
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
jb .found_slot ; it's empty or read
dec eax
jnz .search_for_empty
stdcall write_cache64, [ebp+PARTITION.Disk] ; no empty slots found, write all
test eax, eax
jne .found_slot_access_denied
jmp .search_again ; and start again
.found_slot:
mov [ebx+DISKCACHE.search_start], ecx
popd [esi+CACHE_ITEM.SectorLo]
popd [esi+CACHE_ITEM.SectorHi]
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_EMPTY
mov edi, ecx
mov ecx, [ebx+DISKCACHE.sector_size_log]
shl edi, cl
add edi, [ebx+DISKCACHE.data]
.return0:
xor eax, eax ; success
ret
.found_slot_access_denied:
add esp, 8
ret
endp
 
; Flush the given cache.
; The caller must acquire the cache lock.
; in: ebx -> DISKCACHE
; in: first argument in stdcall convention -> PARTITION
proc write_cache64
; 1. Setup stack frame.
push esi edi ; save used registers to be stdcall
sub esp, .local_vars_size ; reserve space for local vars
virtual at esp
.local_vars:
.cache_end dd ? ; item past the end of the cache
.size_left dd ? ; items left to scan
.current_ptr dd ? ; pointer to the current item
;
; Write operations are coalesced in chains,
; one chain describes a sequential interval of sectors,
; they can be sequential or scattered in the cache.
.sequential dd ?
; boolean variable, 1 if the current chain is sequential in the cache,
; 0 if additional buffer is needed to perform the operation
.chain_start_pos dd ? ; data of chain start item
.chain_start_ptr dd ? ; pointer to chain start item
.chain_size dd ? ; chain size (thanks, C.O.)
.iteration_size dd ?
; If the chain size is too large, split the operation to several iterations.
; This is size in sectors for one iterations.
.iteration_buffer dd ? ; temporary buffer for non-sequential chains
.local_vars_size = $ - .local_vars
rd 2 ; saved registers
dd ? ; return address
.disk dd ? ; first argument
end virtual
; 1. If there is no cache for this disk, nothing to do, just return zero.
cmp [ebx+DISKCACHE.pointer], 0
jz .return0
; 2. Prepare for the loop: initialize current pointer and .size_left,
; calculate .cache_end.
mov ecx, [ebx+DISKCACHE.sad_size]
mov [.size_left], ecx
lea ecx, [ecx*sizeof.CACHE_ITEM/4]
shl ecx, 2
mov esi, [ebx+DISKCACHE.pointer]
add esi, sizeof.CACHE_ITEM
add ecx, esi
mov [.cache_end], ecx
; 3. Main loop: go over all items, go to 5 for every modified item.
.look:
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
jz .begin_write
.look_next:
add esi, sizeof.CACHE_ITEM
dec [.size_left]
jnz .look
; 4. Return success.
.return0:
xor eax, eax
.return:
add esp, .local_vars_size
pop edi esi ; restore used registers to be stdcall
ret 4 ; return popping one argument
.begin_write:
; We have found a modified item.
; 5. Prepare for chain finding: save the current item, initialize chain variables.
mov [.current_ptr], esi
; Initialize chain as sequential zero-length starting at the current item.
mov [.chain_start_ptr], esi
mov eax, [ebx+DISKCACHE.sad_size]
sub eax, [.size_left]
inc eax
mov ecx, [ebx+DISKCACHE.sector_size_log]
shl eax, cl
add eax, [ebx+DISKCACHE.data]
mov [.chain_start_pos], eax
mov [.chain_size], 0
mov [.sequential], 1
; 6. Expand the chain backward.
; Note: the main loop in step 2 looks for items sequentially,
; so the previous item is not modified. If the previous sector
; is present in the cache, it automatically makes the chain scattered.
; 6a. Calculate sector number: one before the sector for the current item.
mov eax, [esi+CACHE_ITEM.SectorLo]
mov edx, [esi+CACHE_ITEM.SectorHi]
sub eax, 1
sbb edx, 0
.find_chain_start:
; 6b. For each sector where the previous item does not expand the chain,
; call the lookup function without adding to the cache.
call cache_lookup_read
; 6c. If the sector is not found in cache or is not modified, stop expanding
; and advance to step 7.
jc .found_chain_start
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
jnz .found_chain_start
; 6d. We have found a new block that expands the chain backwards.
; It makes the chain non-sequential.
; Normally, sectors come in sequential blocks, so try to look at previous items
; before returning to 6b; if there is a sequential block indeed, this saves some
; time instead of many full-fledged lookups.
mov [.sequential], 0
mov [.chain_start_pos], edi
.look_backward:
; 6e. For each sector, update chain start pos/ptr, decrement sector number,
; look at the previous item.
mov [.chain_start_ptr], esi
inc [.chain_size]
sub eax, 1
sbb edx, 0
sub esi, sizeof.CACHE_ITEM
; If the previous item exists...
cmp esi, [ebx+DISKCACHE.pointer]
jbe .find_chain_start
; ...describes the correct sector...
cmp [esi+CACHE_ITEM.SectorLo], eax
jnz .find_chain_start
cmp [esi+CACHE_ITEM.SectorHi], edx
jnz .find_chain_start
; ...and is modified...
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
jnz .found_chain_start
; ...expand the chain one sector backwards and continue the loop at 6e.
; Otherwise, advance to step 7 if the previous item describes the correct sector
; but is not modified, and return to step 6b otherwise.
mov edi, 1
shl edi, cl
sub [.chain_start_pos], edi
jmp .look_backward
.found_chain_start:
; 7. Expand the chain forward.
; 7a. Prepare for the loop at 7b:
; set esi = pointer to current item, edx:eax = current sector.
mov esi, [.current_ptr]
mov eax, [esi+CACHE_ITEM.SectorLo]
mov edx, [esi+CACHE_ITEM.SectorHi]
.look_forward:
; 7b. First, look at the next item. If it describes the next sector:
; if it is modified, expand the chain with that sector and continue this step,
; if it is not modified, the chain is completed, so advance to step 8.
inc [.chain_size]
add eax, 1
adc edx, 0
add esi, sizeof.CACHE_ITEM
cmp esi, [.cache_end]
jae .find_chain_end
cmp [esi+CACHE_ITEM.SectorLo], eax
jnz .find_chain_end
cmp [esi+CACHE_ITEM.SectorHi], edx
jnz .find_chain_end
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
jnz .found_chain_end
jmp .look_forward
.find_chain_end:
; 7c. Otherwise, call the lookup function.
call cache_lookup_read
; 7d. If the next sector is present in the cache and is modified,
; mark the chain as non-sequential and continue to step 7b.
jc .found_chain_end
cmp [esi+CACHE_ITEM.Status], CACHE_ITEM_MODIFIED
jnz .found_chain_end
mov [.sequential], 0
jmp .look_forward
.found_chain_end:
; 8. Decide whether the chain is sequential or scattered.
; Advance to step 9 for sequential chains, go to step 10 for scattered chains.
cmp [.sequential], 0
jz .write_non_sequential
.write_sequential:
; 9. Write a sequential chain to disk.
; 9a. Pass the entire chain to the driver.
mov eax, [.chain_start_ptr]
lea ecx, [.chain_size]
push ecx ; numsectors
pushd [eax+CACHE_ITEM.SectorHi] ; startsector
pushd [eax+CACHE_ITEM.SectorLo] ; startsector
push [.chain_start_pos+12] ; buffer
mov esi, [ebp+PARTITION.Disk]
mov al, DISKFUNC.write
call disk_call_driver
; 9b. If failed, pass the error code to the driver.
test eax, eax
jnz .return
; 9c. If succeeded, mark all sectors in the chain as not-modified,
; advance current item and number of items left to skip the chain.
mov esi, [.current_ptr]
mov eax, [.chain_size]
sub [.size_left], eax
@@:
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY
add esi, sizeof.CACHE_ITEM
dec eax
jnz @b
; 9d. Continue the main loop at step 2 if there are more sectors.
; Return success otherwise.
cmp [.size_left], 0
jnz .look
jmp .return0
.write_non_sequential:
; Write a non-sequential chain to the disk.
; 10. Allocate a temporary buffer.
; Use [.chain_size] sectors, but
; not greater than CACHE_MAX_ALLOC_SIZE bytes
; and not greater than half of free memory.
mov eax, [pg_data.pages_free]
shr eax, 1
jz .nomemory
cmp eax, CACHE_MAX_ALLOC_SIZE shr 12
jbe @f
mov eax, CACHE_MAX_ALLOC_SIZE shr 12
@@:
shl eax, 12
shr eax, cl
jz .nomemory
cmp eax, [.chain_size]
jbe @f
mov eax, [.chain_size]
@@:
mov [.iteration_size], eax
shl eax, cl
stdcall kernel_alloc, eax
test eax, eax
jz .nomemory
mov [.iteration_buffer], eax
.write_non_sequential_iteration:
; 11. Split the chain so that each iteration fits in the allocated buffer.
; Iteration size is the minimum of chain size and allocated size.
mov eax, [.chain_size]
cmp eax, [.iteration_size]
jae @f
mov [.iteration_size], eax
@@:
; 12. Prepare arguments for the driver.
mov esi, [.chain_start_ptr]
mov edi, [.iteration_buffer]
push [.iteration_size]
push esp ; numsectors
push [esi+CACHE_ITEM.SectorHi] ; startsector
push [esi+CACHE_ITEM.SectorLo] ; startsector
push edi ; buffer
; 13. Copy data from the cache to the temporary buffer,
; advancing chain_start pos/ptr and marking sectors as not-modified.
; 13a. Prepare for the loop: push number of sectors to process.
push [.iteration_size+20] ; temporary variable
.copy_loop:
; 13b. For each sector, copy the data.
; Note that edi is advanced automatically.
mov esi, [.chain_start_pos+24]
mov ecx, [ebx+DISKCACHE.sector_size_log]
mov eax, 1
shl eax, cl
mov ecx, eax
shr ecx, 2
rep movsd
mov ecx, eax ; keep for 13e
; 13c. Mark the item as not-modified.
mov esi, [.chain_start_ptr+24]
mov [esi+CACHE_ITEM.Status], CACHE_ITEM_COPY
; 13d. Check whether the next sector continues the chain.
; If so, advance to 13e. Otherwise, go to 13f.
mov eax, [esi+CACHE_ITEM.SectorLo]
mov edx, [esi+CACHE_ITEM.SectorHi]
add esi, sizeof.CACHE_ITEM
add eax, 1
adc edx, 0
cmp esi, [.cache_end+24]
jae .no_forward
cmp [esi+CACHE_ITEM.SectorLo], eax
jnz .no_forward
cmp [esi+CACHE_ITEM.SectorHi], edx
jnz .no_forward
; 13e. Increment position/pointer to the chain and
; continue the loop.
add [.chain_start_pos+24], ecx
mov [.chain_start_ptr+24], esi
dec dword [esp]
jnz .copy_loop
jmp .copy_done
.no_forward:
; 13f. Call the lookup function without adding to the cache.
; Update position/pointer with returned value.
; Note: for the last sector in the chain, edi/esi may contain
; garbage; we are not going to use them in this case.
push edi
call cache_lookup_read
mov [.chain_start_pos+28], edi
mov [.chain_start_ptr+28], esi
pop edi
dec dword [esp]
jnz .copy_loop
.copy_done:
; 13g. Restore the stack after 13a.
pop ecx
; 14. Call the driver.
mov esi, [ebp+PARTITION.Disk]
mov al, DISKFUNC.write
call disk_call_driver
pop ecx ; numsectors
; 15. If the driver has returned an error, free the buffer allocated at step 10
; and pass the error to the caller.
; Otherwise, remove the processed part from the chain and continue iterations
; starting in step 11 if there are more data to process.
test eax, eax
jnz .nonsequential_error
sub [.chain_size], ecx
jnz .write_non_sequential_iteration
; 16. The chain is written. Free the temporary buffer
; and continue the loop at step 2.
stdcall kernel_free, [.iteration_buffer]
mov esi, [.current_ptr]
jmp .look_next
.nonsequential_error:
push eax
stdcall kernel_free, [.iteration_buffer+4]
pop eax
jmp .return
.nomemory:
mov eax, DISK_STATUS_NO_MEMORY
jmp .return
endp
 
; This internal function is called from disk_add to initialize the caching for
; a new DISK.
; The algorithm is inherited from getcache.inc: take 1/32 part of the available
; physical memory, round down to 8 pages, limit by 128K from below and by 1M
; from above. Reserve 1/8 part of the cache for system data and 7/8 for app
; data.
; After the size is calculated, but before the cache is allocated, the device
; driver can adjust the size. In particular, setting size to zero disables
; caching: there is no sense in a cache for a ramdisk. In fact, such action
; is most useful example of a non-trivial adjustment.
; esi = pointer to DISK structure
disk_init_cache:
; 1. Verify sector size. The code requires it to be a power of 2 not less than 4.
; In the name of sanity check that sector size is not too small or too large.
bsf ecx, [esi+DISK.MediaInfo.SectorSize]
jz .invalid_sector_size
mov eax, 1
shl eax, cl
cmp eax, [esi+DISK.MediaInfo.SectorSize]
jnz .invalid_sector_size
cmp ecx, 6
jb .invalid_sector_size
cmp ecx, 14
jbe .normal_sector_size
.invalid_sector_size:
DEBUGF 1,'K : sector size %x is invalid\n',[esi+DISK.MediaInfo.SectorSize]
xor eax, eax
ret
.normal_sector_size:
mov [esi+DISK.SysCache.sector_size_log], ecx
mov [esi+DISK.AppCache.sector_size_log], ecx
; 2. Calculate the suggested cache size.
; 2a. Get the size of free physical memory in pages.
mov eax, [pg_data.pages_free]
; 2b. Use the value to calculate the size.
shl eax, 12 - 5 ; 1/32 of it in bytes
and eax, -8*4096 ; round down to the multiple of 8 pages
; 2c. Force lower and upper limits.
cmp eax, 1024*1024
jb @f
mov eax, 1024*1024
@@:
cmp eax, 128*1024
ja @f
mov eax, 128*1024
@@:
; 2d. Give a chance to the driver to adjust the size.
push eax
mov al, DISKFUNC.adjust_cache_size
call disk_call_driver
; Cache size calculated.
mov [esi+DISK.cache_size], eax
test eax, eax
jz .nocache
; 3. Allocate memory for the cache.
; 3a. Call the allocator.
stdcall kernel_alloc, eax
test eax, eax
jnz @f
; 3b. If it failed, say a message and return with eax = 0.
dbgstr 'no memory for disk cache'
jmp .nothing
@@:
; 4. Fill two DISKCACHE structures.
mov [esi+DISK.SysCache.pointer], eax
lea ecx, [esi+DISK.CacheLock]
call mutex_init
; The following code is inherited from getcache.inc.
mov edx, [esi+DISK.SysCache.pointer]
and [esi+DISK.SysCache.search_start], 0
and [esi+DISK.AppCache.search_start], 0
mov eax, [esi+DISK.cache_size]
shr eax, 3
mov [esi+DISK.SysCache.data_size], eax
add edx, eax
imul eax, 7
mov [esi+DISK.AppCache.data_size], eax
mov [esi+DISK.AppCache.pointer], edx
 
mov eax, [esi+DISK.SysCache.data_size]
call calculate_cache_slots
add eax, [esi+DISK.SysCache.pointer]
mov [esi+DISK.SysCache.data], eax
mov [esi+DISK.SysCache.sad_size], ecx
 
push edi
mov edi, [esi+DISK.SysCache.pointer]
lea ecx, [(ecx+1)*3]
xor eax, eax
rep stosd
pop edi
 
mov eax, [esi+DISK.AppCache.data_size]
call calculate_cache_slots
add eax, [esi+DISK.AppCache.pointer]
mov [esi+DISK.AppCache.data], eax
mov [esi+DISK.AppCache.sad_size], ecx
 
push edi
mov edi, [esi+DISK.AppCache.pointer]
lea ecx, [(ecx+1)*3]
xor eax, eax
rep stosd
pop edi
 
; 5. Return with nonzero al.
mov al, 1
; 6. Return.
.nothing:
ret
; No caching is required for this driver. Zero cache pointers and return with
; nonzero al.
.nocache:
mov [esi+DISK.SysCache.pointer], eax
mov [esi+DISK.AppCache.pointer], eax
mov al, 1
ret
 
calculate_cache_slots:
push eax
mov ecx, [esi+DISK.MediaInfo.SectorSize]
add ecx, sizeof.CACHE_ITEM
xor edx, edx
div ecx
mov ecx, eax
imul eax, [esi+DISK.MediaInfo.SectorSize]
sub [esp], eax
pop eax
dec ecx
ret
 
 
; This internal function is called from disk_media_dereference to free the
; allocated cache, if there is one.
; esi = pointer to DISK structure
disk_free_cache:
; The algorithm is straightforward.
mov eax, [esi+DISK.SysCache.pointer]
test eax, eax
jz .nothing
stdcall kernel_free, eax
.nothing:
ret
 
; This function flushes all modified data from both caches for the given DISK.
; esi = pointer to DISK
disk_sync:
; The algorithm is straightforward.
cmp [esi+DISK.SysCache.pointer], 0
jz .nothing
lea ecx, [esi+DISK.CacheLock]
call mutex_lock
push ebx
push esi ; for second write_cache64
push esi ; for first write_cache64
lea ebx, [esi+DISK.SysCache]
call write_cache64
add ebx, DISK.AppCache - DISK.SysCache
call write_cache64
pop ebx
lea ecx, [esi+DISK.CacheLock]
call mutex_unlock
.nothing:
mov al, DISKFUNC.flush
call disk_call_driver
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/fdc.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/ide_cache.inc
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
;--------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev/rdsave.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/blkdev
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/core/clipboard.inc
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
;------------------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/taskman.inc
0,0 → 1,1059
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
GREEDY_KERNEL = 0
 
struct APP_HEADER_00_
banner dq ?
version dd ? ;+8
start dd ? ;+12
i_end dd ? ;+16
mem_size dd ? ;+20
i_param dd ? ;+24
ends
 
struct APP_HEADER_01_
banner dq ?
version dd ? ;+8
start dd ? ;+12
i_end dd ? ;+16
mem_size dd ? ;+20
stack_top dd ? ;+24
i_param dd ? ;+28
i_icon dd ? ;+32
ends
 
struct APP_HDR
cmdline rd 1 ;0x00
path rd 1 ;0x04
eip rd 1 ;0x08
esp rd 1 ;0x0C
_edata rd 1 ;0x10
_emem rd 1 ;0x14
img_base rd 1 ;0x18
img_size rd 1
filename_size rd 1
cmdline_size rd 1
path_string rd 1
ends
 
macro _clear_ op
{ mov ecx, op/4
xor eax, eax
cld
rep stosd
}
 
align 4
_strnlen:
mov edx, ecx
xor eax, eax
repne scasb
jne @F
inc ecx
@@:
mov eax, edx
sub eax, ecx
retn
 
fs_execute_from_sysdir:
xor ebx, ebx
fs_execute_from_sysdir_param:
stdcall kernel_alloc, maxPathLength
push eax ebx
mov esi, ebp
mov edi, eax
xor eax, eax
call getFullPath
pop ecx ebx
xor edx, edx
; @brief Executes a program
; @param edx Flags
; @param ecx Commandline
; @param ebx Absolute file path
; @param eax String length
; @returns Negated error code or new process number
proc fs_execute
locals
cmdline rd 1
flags rd 1
slot rd 1 ; index of new thread slot
slot_base rd 1 ; base address of it
; app header data
hdr_cmdline rd 1
hdr_path rd 1
hdr_eip rd 1
hdr_esp rd 1
hdr_edata rd 1
hdr_emem rd 1
file_base rd 1
file_size rd 1
filename_size rd 1
cmdline_size rd 1
path_string rd 1
endl
 
mov [flags], edx
mov [cmdline], ecx
mov [path_string], ebx
mov [filename_size], eax
mov esi, -ERROR_FILE_NOT_FOUND
test eax, eax
jz .err_file
stdcall load_file, ebx
test eax, eax
jz .err_file
 
mov [file_base], eax
mov [file_size], ebx
lea ebx, [hdr_cmdline]
call test_app_header ; fill our app header data locals with values from header of given program (if its correct)
mov esi, -TASKMAN_ERROR_NOT_A_EXECUTABLE
test eax, eax
jz .err_hdr
 
call lock_application_table
call alloc_thread_slot ; create a slot for new thread
mov esi, -TASKMAN_ERROR_TOO_MANY_PROCESSES
test eax, eax
jz .err_0
 
mov [slot], eax
shl eax, 8
lea edi, [SLOT_BASE+eax]
mov [slot_base], edi
; clean extended information about process
mov ecx, sizeof.APPDATA/4
xor eax, eax
cld
rep stosd
; write application name ( APPDATA.appname )
stdcall strrchr, [path_string], '/'
lea esi, [eax+1] ; -> name without path
mov ecx, 11
mov edi, [slot_base]
@@:
call utf8to16
call uni2ansi_char
cmp al, '.'
jz @f
test al, al
jz @f
stosb
loop @b
@@:
mov edi, [cmdline]
xor eax, eax
test edi, edi
jz @f
mov ecx, 65535
call _strnlen
cmp eax, 256
jb @f
; if cmdline length >= 256 then increase needed memory size by this length
lea ebx, [eax+1]
add [hdr_emem], ebx
@@:
mov [cmdline_size], eax
stdcall create_process, [hdr_emem] ; create a new process
mov esi, -TASKMAN_ERROR_OUT_OF_MEMORY
test eax, eax
jz .err_hdr
 
; add new process to the list
mov ebx, [sys_proc+LHEAD.prev]
__list_add eax, ebx, sys_proc
; fill the structure fields:
mov ebx, [hdr_emem]
mov [eax+PROC.mem_used], ebx
 
; write that main thread of app belongs to new process
mov ebx, [slot_base]
mov [ebx+APPDATA.process], eax
 
; initialize the thread list of process: at this moment it consists only of one main thread
lea edx, [ebx+APPDATA.list]
lea ecx, [eax+PROC.thr_list]
list_add_tail edx, ecx
 
; allocate space and copy app header data locals and cmdline string there, put pointer to exec_params of new thread
mov eax, [cmdline_size]
add eax, sizeof.APP_HDR
stdcall kernel_alloc, eax
mov [ebx+APPDATA.exec_params], eax
mov edi, eax
lea esi, [hdr_cmdline]
mov ecx, sizeof.APP_HDR/4
rep movsd
mov ecx, [cmdline_size]
mov esi, [cmdline]
rep movsb
; set other parameters of application
lea eax, [hdr_cmdline]
stdcall set_app_params , [slot], eax, [flags]
mov eax, [process_number] ; return process number
call unlock_application_table
ret
 
.err_0:
call unlock_application_table
.err_hdr:
stdcall kernel_free, [file_base]
.err_file:
stdcall kernel_free, [path_string]
mov eax, esi
ret
endp
 
align 4
test_app_header:
virtual at eax
APP_HEADER_00 APP_HEADER_00_
end virtual
virtual at eax
APP_HEADER_01 APP_HEADER_01_
end virtual
 
cmp dword [eax], 'MENU'
jne .fail
cmp word [eax+4], 'ET'
jne .fail
 
cmp [eax+6], word '00'
jne .check_01_header
 
mov ecx, [APP_HEADER_00.start]
mov [ebx+APP_HDR.eip], ecx
mov edx, [APP_HEADER_00.mem_size]
mov [ebx+APP_HDR._emem], edx
shr edx, 1
sub edx, 0x10
mov [ebx+APP_HDR.esp], edx
mov ecx, [APP_HEADER_00.i_param]
mov [ebx+APP_HDR.cmdline], ecx
mov [ebx+APP_HDR.path], 0
mov edx, [APP_HEADER_00.i_end]
mov [ebx+APP_HDR._edata], edx
ret
 
.check_01_header:
 
cmp [eax+6], word '01'
je @f
cmp [eax+6], word '02'
jne .fail
@@:
mov ecx, [APP_HEADER_01.start]
mov [ebx+0x08], ecx
mov edx, [APP_HEADER_01.mem_size]
 
; \begin{diamond}[20.08.2006]
; sanity check (functions 19,58 load app_i_end bytes and that must
; fit in allocated memory to prevent kernel faults)
cmp edx, [APP_HEADER_01.i_end]
jb .fail
; \end{diamond}[20.08.2006]
 
mov [ebx+APP_HDR._emem], edx
mov ecx, [APP_HEADER_01.stack_top]
mov [ebx+APP_HDR.esp], ecx
mov edx, [APP_HEADER_01.i_param]
mov [ebx+APP_HDR.cmdline], edx
mov ecx, [APP_HEADER_01.i_icon]
mov [ebx+APP_HDR.path], ecx
mov edx, [APP_HEADER_01.i_end]
mov [ebx+APP_HDR._edata], edx
ret
.fail:
xor eax, eax
ret
 
align 4
alloc_thread_slot:
;input:
; none
;result:
; eax=[new_thread_slot]<>0 - ok
; 0 - failed.
;This function find least empty slot.
;It doesn't increase [thread_count]!
 
 
mov edx, thr_slot_map
pushfd
cli
.l1:
bsf eax, [edx]
jnz .found
add edx, 4
cmp edx, thr_slot_map+32
jb .l1
 
popfd
xor eax, eax
ret
.found:
btr [edx], eax
sub edx, thr_slot_map
lea eax, [eax+edx*8]
popfd
ret
 
align 4
proc create_process stdcall, app_size:dword
locals
process dd ?
app_tabs dd ?
endl
 
push ebx
push esi
push edi
 
xor eax, eax
mov [process], eax
 
mov eax, [app_size]
add eax, 0x3FFFFF
shr eax, 22
mov [app_tabs], eax
 
stdcall kernel_alloc, 0x2000
test eax, eax
jz .fail
mov [process], eax
 
lea edi, [eax+PROC.heap_lock]
mov ecx, (PROC.ht_free-PROC.heap_lock)/4
 
list_init eax
add eax, PROC.thr_list
list_init eax
 
xor eax, eax
cld
rep stosd
 
mov [edi], dword (PROC.pdt_0 - PROC.htab)/4 - 3
mov [edi+4], dword 3 ;reserve handles for stdin stdout and stderr
mov ecx, (PROC.pdt_0 - PROC.htab)/4
add edi, 8
inc eax
@@:
stosd
inc eax
cmp eax, ecx
jbe @B
 
mov eax, edi
call get_pg_addr
mov [edi-4096+PROC.pdt_0_phys], eax
 
mov ecx, (OS_BASE shr 20)/4
xor eax, eax
rep stosd
 
mov ecx, (OS_BASE shr 20)/4
mov esi, sys_proc+PROC.pdt_0+(OS_BASE shr 20)
rep movsd
 
mov eax, [edi-8192+PROC.pdt_0_phys]
or eax, PG_SWR
mov [edi-4096+(page_tabs shr 20)], eax
 
lea edx, [edi-4096]
mov esi, [app_tabs]
 
.alloc_page_dir:
call alloc_page
test eax, eax
jz .fail
or eax, PG_UWR
mov [edx], eax
 
mov edi, [tmp_task_ptab]
stdcall map_page, edi, eax, PG_SWR
mov ecx, 1024
xor eax, eax
rep stosd
 
add edx, 4
dec esi
jnz .alloc_page_dir
 
stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP
mov eax, [process]
 
pop edi
pop esi
pop ebx
ret
.fail:
mov ecx, [process]
jcxz @F
 
call destroy_process
@@:
xor eax, eax
pop edi
pop esi
pop ebx
ret
endp
 
align 4
proc destroy_page_table stdcall, pg_tab:dword
 
push esi
 
mov esi, [pg_tab]
mov ecx, 1024
.free:
mov eax, [esi]
test eax, 1
jz .next
test eax, 2
jz .next
test eax, 1 shl 9
jnz .next ;skip shared pages
call free_page
.next:
add esi, 4
dec ecx
jnz .free
pop esi
ret
endp
 
align 4
destroy_process: ;fastcall ecx= ptr to process
 
lea eax, [ecx+PROC.thr_list]
cmp eax, [eax+LHEAD.next]
jne .exit
 
align 4
.internal:
push ecx
 
mov esi, ecx
list_del esi
 
mov esi, [esi+PROC.dlls_list_ptr]
call destroy_all_hdlls
 
mov esi, [esp]
add esi, PROC.pdt_0
mov edi, (0x80000000 shr 20)/4
.destroy:
mov eax, [esi]
test eax, 1
jz .next
and eax, not 0xFFF
stdcall map_page, [tmp_task_ptab], eax, PG_SWR
stdcall destroy_page_table, [tmp_task_ptab]
mov eax, [esi]
call free_page
.next:
add esi, 4
dec edi
jnz .destroy
 
call kernel_free ;ecx still in stack
stdcall map_page, [tmp_task_ptab], 0, PG_UNMAP
.exit:
ret
 
align 4
get_pid:
mov eax, [TASK_BASE]
mov eax, [eax+TASKDATA.pid]
ret
 
pid_to_slot:
;Input:
; eax - pid of process
;Output:
; eax - slot of process or 0 if process don't exists
;Search process by PID.
push ebx
push ecx
mov ebx, [thread_count]
shl ebx, BSF sizeof.TASKDATA ; multiply by size
; add 2*32 cause:
; [TASK_TABLE; TASK_TABLE + 32) isnt a task actually
; skip first process in the task table
mov ecx, 2*32
 
.loop:
;ecx = offset of current process info entry
;ebx = maximum permitted offset
cmp [TASK_TABLE+ecx+TASKDATA.state], TSTATE_FREE
jz .endloop ;skip empty slots
cmp [TASK_TABLE+ecx+TASKDATA.pid], eax;check PID
jz .pid_found
.endloop:
add ecx, sizeof.TASKDATA
cmp ecx, ebx
jle .loop
 
pop ecx
pop ebx
xor eax, eax
ret
 
.pid_found:
shr ecx, BSF sizeof.TASKDATA ; divide by size
mov eax, ecx ;convert offset to index of slot
pop ecx
pop ebx
ret
 
 
align 4
proc read_process_memory
;Input:
; eax - process slot
; ecx - buffer address
; edx - buffer size
; esi - start address in other process
;Output:
; eax - number of bytes read.
locals
slot dd ?
buff dd ?
r_count dd ?
offset dd ?
tmp_r_cnt dd ?
endl
 
mov [slot], eax
mov [buff], ecx
and [r_count], 0
mov [tmp_r_cnt], edx
mov [offset], esi
 
pushad
.read_mem:
mov edx, [offset]
mov ebx, [tmp_r_cnt]
 
mov ecx, 0x400000
and edx, 0x3FFFFF
sub ecx, edx
cmp ecx, ebx
jbe @f
mov ecx, ebx
@@:
cmp ecx, 0x8000
jna @F
mov ecx, 0x8000
@@:
mov ebx, [offset]
 
push ecx
stdcall map_memEx, [proc_mem_map], \
[slot], ebx, ecx, PG_READ
pop ecx
 
mov esi, [offset]
and esi, 0xfff
sub eax, esi
jbe .ret
cmp ecx, eax
jbe @f
mov ecx, eax
mov [tmp_r_cnt], eax
@@:
add esi, [proc_mem_map]
mov edi, [buff]
mov edx, ecx
rep movsb
add [r_count], edx
 
add [offset], edx
sub [tmp_r_cnt], edx
jnz .read_mem
.ret:
popad
mov eax, [r_count]
ret
endp
 
align 4
proc write_process_memory
;Input:
; eax - process slot
; ecx - buffer address
; edx - buffer size
; esi - start address in other process
;Output:
; eax - number of bytes written
 
locals
slot dd ?
buff dd ?
w_count dd ?
offset dd ?
tmp_w_cnt dd ?
endl
 
mov [slot], eax
mov [buff], ecx
and [w_count], 0
mov [tmp_w_cnt], edx
mov [offset], esi
 
pushad
.read_mem:
mov edx, [offset]
mov ebx, [tmp_w_cnt]
 
mov ecx, 0x400000
and edx, 0x3FFFFF
sub ecx, edx
cmp ecx, ebx
jbe @f
mov ecx, ebx
@@:
cmp ecx, 0x8000
jna @F
mov ecx, 0x8000
@@:
mov ebx, [offset]
push ecx
stdcall map_memEx, [proc_mem_map], \
[slot], ebx, ecx, PG_SWR
pop ecx
 
mov edi, [offset]
and edi, 0xfff
sub eax, edi
jbe .ret
cmp ecx, eax
jbe @f
mov ecx, eax
mov [tmp_w_cnt], eax
@@:
add edi, [proc_mem_map]
mov esi, [buff]
mov edx, ecx
rep movsb
 
add [w_count], edx
add [offset], edx
sub [tmp_w_cnt], edx
jnz .read_mem
.ret:
popad
mov eax, [w_count]
ret
endp
 
;ebx = 1 - kernel thread
;ecx=thread entry point
;edx=thread stack pointer
;creation flags 0x01 - debugged
; 0x02 - kernel
 
align 4
proc new_sys_threads
locals
slot dd ?
flags dd ?
app_cmdline dd ? ;0x00
app_path dd ? ;0x04
app_eip dd ? ;0x08
app_esp dd ? ;0x0C
app_mem dd ? ;0x10
endl
 
shl ebx, 1
mov [flags], ebx
 
xor eax, eax
mov [app_eip], ecx
mov [app_cmdline], eax
mov [app_esp], edx
mov [app_path], eax
 
call lock_application_table
 
call alloc_thread_slot
test eax, eax
jz .failed
 
mov [slot], eax
 
mov esi, [current_slot]
mov ebx, esi ;ebx=esi - pointer to extended information about current thread
 
mov edi, eax
shl edi, 8
add edi, SLOT_BASE
mov edx, edi ;edx=edi - pointer to extended infomation about new thread
mov ecx, sizeof.APPDATA/4
xor eax, eax
cld
rep stosd ;clean extended information about new thread
mov esi, ebx
mov edi, edx
mov ecx, 11
rep movsb ;copy process name
 
 
mov eax, [ebx+APPDATA.tls_base]
test eax, eax
jz @F
 
push edx
stdcall user_alloc, 4096
pop edx
test eax, eax
jz .failed1;eax=0
@@:
mov [edx+APPDATA.tls_base], eax
 
mov eax, [ebx+APPDATA.process]
mov [edx+APPDATA.process], eax
 
lea ebx, [edx+APPDATA.list]
lea ecx, [eax+PROC.thr_list]
list_add_tail ebx, ecx ;add thread to process child's list
 
lea eax, [app_cmdline]
stdcall set_app_params , [slot], eax, [flags]
 
mov eax, [process_number] ;set result
call unlock_application_table
ret
.failed:
xor eax, eax
.failed1:
call unlock_application_table
dec eax ;-1
ret
endp
 
proc map_process_image stdcall, img_size:dword, file_base:dword, file_size:dword
 
mov edx, [img_size]
mov esi, [file_base]
mov ecx, [file_size]
add edx, 4095
add ecx, 4095
shr edx, 12 ; total pages
shr ecx, 12 ; image pages
 
mov edi, page_tabs
shr esi, 10
add esi, edi
 
.map_image:
lodsd
and eax, -4096
or eax, PG_UWR
stosd
dec edx
loop .map_image
 
test edx, edx
jz .done
.map_bss:
call alloc_page
test eax, eax
jz .fail
 
or eax, PG_UWR
stosd
dec edx
jnz .map_bss
 
mov edi, [file_size]
mov ecx, [img_size]
add edi, 4095
and edi, -4096
add ecx, 4095
and ecx, -4096
sub ecx, edi
shr ecx, 2
xor eax, eax
rep stosd
.done:
.fail:
ret
endp
 
align 4
common_app_entry:
mov ebp, [current_slot]
mov ebp, [ebp+APPDATA.exec_params]
test ebp, ebp
jz .exit
; APPDATA.exec_params have first thread only,
; so second and next threads don't get here (they jump to .exit)
stdcall map_process_image, [ebp+APP_HDR._emem],\
[ebp+APP_HDR.img_base], [ebp+APP_HDR.img_size]
mov esi, [ebp+APP_HDR.path_string]
mov edi, [ebp+APP_HDR.path]
mov ecx, [ebp+APP_HDR.filename_size]
cmp ecx, 1023
jc @f
mov ecx, 1022
@@:
push esi
test edi, edi
jz @f
stdcall is_region_userspace, edi, [ebp+APP_HDR.filename_size]
jnz @f
mov al, '/'
stosb
rep movsb
mov byte [edi], 0
@@:
call kernel_free
mov edi, [ebp+APP_HDR.cmdline]
test edi, edi
jz .check_tls_header
lea esi, [ebp+sizeof.APP_HDR]
mov ecx, [ebp+APP_HDR.cmdline_size]
cmp ecx, 256
jb .copy_cmdline
mov edi, [ebp+APP_HDR._emem]
add edi, 4095
and edi, -4096
sub edi, ecx
dec edi
cmp word [6], '00'
jne @f
mov [APP_HEADER_00_.i_param], edi
jmp .copy_cmdline
@@:
mov [APP_HEADER_01_.i_param], edi
.copy_cmdline:
inc ecx ; keep in mind about 0 in the end
stdcall is_region_userspace, edi, ecx
jnz .check_tls_header
dec ecx
rep movsb
mov byte [edi], 0
.check_tls_header:
cmp word [6], '02'
jne .try_load_dll ;.cleanup
call init_heap
stdcall user_alloc, 4096
mov edx, [current_slot]
mov [edx+APPDATA.tls_base], eax
mov [tls_data_l+2], ax
shr eax, 16
mov [tls_data_l+4], al
mov [tls_data_l+7], ah
mov dx, app_tls
mov fs, dx
; { Patch by Coldy, For DLL autoload
.try_load_dll:
; Test app header version
mov ecx, dword[ebp+APP_HDR.img_base]
cmp dword[ecx+8], 2
jne .cleanup
;if APP_HEADER.version = 2 => load lib/dll.obj & change eip to APP_STARTUP_THUNK
DEBUGF 1, 'K : App header version 2\n'
stdcall load_library, dll_lib_path, 0
cmp eax, 0
jne @f
; Something went wrong (TODO: Next 2 line is code copy after .cleanup)
stdcall free_kernel_space, [ebp+APP_HDR.img_base]
stdcall kernel_free, ebp
DEBUGF 1, 'K : DLL.OBJ not found! Terminate application!\n'
mov ebx, dll_error_msg
mov ebp, notifyapp
call fs_execute_from_sysdir_param
; Terminate process (TODO: Need jump to .cleanup after sys_end ?)
call sys_end
@@:
; Find APP_STARTUP_THUNK in DLL.OBJ
sub eax, 4
mov eax, [eax]
;.change_eip:
mov ecx, [current_slot]
mov ecx, [ecx+APPDATA.pl0_stack]
mov [ecx+REG_EIP], eax
; } End patch by Coldy, For DLL autoload
.cleanup:
stdcall free_kernel_space, [ebp+APP_HDR.img_base]
stdcall kernel_free, ebp
mov ebx, [current_slot]
cmp [ebx+APPDATA.debugger_slot], 0
je .exit
mov eax, [TASK_BASE]
mov [eax+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task
.exit:
popad
iretd
 
EFL_IF = 0x0200
EFL_IOPL1 = 0x1000
EFL_IOPL2 = 0x2000
EFL_IOPL3 = 0x3000
 
align 4
proc set_app_params stdcall,slot:dword, params:dword, flags:dword
 
locals
pl0_stack dd ?
endl
 
mov eax, [xsave_area_size]
add eax, RING0_STACK_SIZE
stdcall kernel_alloc, eax
mov [pl0_stack], eax
 
lea edi, [eax+RING0_STACK_SIZE]
 
mov eax, [slot]
mov ebx, eax
 
shl eax, 8
mov [eax+SLOT_BASE+APPDATA.fpu_state], edi
mov [eax+SLOT_BASE+APPDATA.exc_handler], 0
mov [eax+SLOT_BASE+APPDATA.except_mask], 0
mov [eax+SLOT_BASE+APPDATA.terminate_protection], 80000001h
 
;set default io permission map
mov ecx, [SLOT_BASE+sizeof.APPDATA+APPDATA.io_map]
mov [eax+SLOT_BASE+APPDATA.io_map], ecx
mov ecx, [SLOT_BASE+sizeof.APPDATA+APPDATA.io_map+4]
mov [eax+SLOT_BASE+APPDATA.io_map+4], ecx
 
mov esi, fpu_data
mov ecx, [xsave_area_size]
add ecx, 3
shr ecx, 2
rep movsd
 
cmp [thread_count], ebx
adc [thread_count], 0 ; update number of processes
shl ebx, 8
lea edx, [ebx+SLOT_BASE+APP_EV_OFFSET]
mov [SLOT_BASE+APPDATA.fd_ev+ebx], edx
mov [SLOT_BASE+APPDATA.bk_ev+ebx], edx
 
add edx, APP_OBJ_OFFSET-APP_EV_OFFSET
mov [SLOT_BASE+APPDATA.fd_obj+ebx], edx
mov [SLOT_BASE+APPDATA.bk_obj+ebx], edx
 
mov ecx, [def_cursor]
mov [SLOT_BASE+APPDATA.cursor+ebx], ecx
mov eax, [pl0_stack]
mov [SLOT_BASE+APPDATA.pl0_stack+ebx], eax
add eax, RING0_STACK_SIZE
mov [SLOT_BASE+APPDATA.saved_esp0+ebx], eax
 
push ebx
stdcall kernel_alloc, maxPathLength
pop ebx
mov esi, [current_slot]
mov esi, [esi+APPDATA.cur_dir]
mov ecx, maxPathLength/4
mov edi, eax
mov [ebx+SLOT_BASE+APPDATA.cur_dir], eax
rep movsd
 
shr ebx, 3
mov dword [TASK_TABLE+ebx+TASKDATA.mem_start], 0
 
mov ebx, [slot]
mov eax, ebx
shl ebx, 5
lea ecx, [draw_data+ebx];ecx - pointer to draw data
 
; set window state to 'normal' (non-minimized/maximized/rolled-up) state
mov [ebx+window_data+WDATA.fl_wstate], WSTATE_NORMAL
mov [ebx+window_data+WDATA.fl_redraw], 1
add ebx, TASK_TABLE ;ebx - pointer to information about process
mov [ebx+TASKDATA.wnd_number], al;set window number on screen = process slot
 
mov [ebx+TASKDATA.event_mask], dword 1+2+4;set default event flags (see 40 function)
 
inc dword [process_number]
mov eax, [process_number]
mov [ebx+TASKDATA.pid], eax ;set PID
 
;set draw data to full screen
xor eax, eax
mov [ecx+0], dword eax
mov [ecx+4], dword eax
mov eax, [screen_workarea.right]
mov [ecx+8], eax
mov eax, [screen_workarea.bottom]
mov [ecx+12], eax
 
mov ebx, [pl0_stack]
mov esi, [params]
lea ecx, [ebx+REG_EIP]
xor eax, eax
 
mov [ebx+REG_RET], dword common_app_entry
mov [ebx+REG_EDI], eax
mov [ebx+REG_ESI], eax
mov [ebx+REG_EBP], eax
mov [ebx+REG_ESP], ecx;ebx+REG_EIP
mov [ebx+REG_EBX], eax
mov [ebx+REG_EDX], eax
mov [ebx+REG_ECX], eax
mov [ebx+REG_EAX], eax
 
mov eax, [esi+APP_HDR.eip]
mov [ebx+REG_EIP], eax
mov [ebx+REG_CS], dword app_code
mov ecx, USER_PRIORITY
 
test byte [flags], 2
jz @F
 
mov [ebx+REG_CS], dword os_code ; kernel thread
mov ecx, MAX_PRIORITY
@@:
mov [ebx+REG_EFLAGS], dword EFL_IOPL1+EFL_IF
 
mov eax, [esi+APP_HDR.esp]
mov [ebx+REG_APP_ESP], eax
mov [ebx+REG_SS], dword app_data
 
lea edx, [ebx+REG_RET]
mov ebx, [slot]
shl ebx, 5
mov [ebx*8+SLOT_BASE+APPDATA.saved_esp], edx
 
xor edx, edx; process state - running
; set if debuggee
test byte [flags], 1
jz .no_debug
mov eax, [current_slot_idx]
mov [SLOT_BASE+ebx*8+APPDATA.debugger_slot], eax
.no_debug:
mov [TASK_TABLE+ebx+TASKDATA.state], dl
lea edx, [SLOT_BASE+ebx*8]
call scheduler_add_thread
ret
endp
 
align 4
get_stack_base:
mov eax, [current_slot]
mov eax, [eax+APPDATA.pl0_stack]
ret
 
 
include "debug.inc"
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/dll.inc
0,0 → 1,1518
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
DRV_COMPAT = 5 ;minimal required drivers version
DRV_CURRENT = 6 ;current drivers model version
 
DRV_VERSION = (DRV_COMPAT shl 16) or DRV_CURRENT
PID_KERNEL = 1 ;os_idle thread
 
 
 
align 4
proc get_notify stdcall, p_ev:dword
 
.wait:
mov ebx, [current_slot]
test dword [ebx+APPDATA.event_mask], EVENT_NOTIFY
jz @f
and dword [ebx+APPDATA.event_mask], not EVENT_NOTIFY
mov edi, [p_ev]
mov dword [edi], EV_INTR
mov eax, [ebx+APPDATA.event]
mov dword [edi+4], eax
ret
@@:
call change_task
jmp .wait
endp
 
align 4
proc pci_read32 stdcall, bus:dword, devfn:dword, reg:dword
push ebx
xor eax, eax
xor ebx, ebx
mov ah, byte [bus]
mov al, 6
mov bh, byte [devfn]
mov bl, byte [reg]
call pci_read_reg
pop ebx
ret
endp
 
align 4
proc pci_read16 stdcall, bus:dword, devfn:dword, reg:dword
push ebx
xor eax, eax
xor ebx, ebx
mov ah, byte [bus]
mov al, 5
mov bh, byte [devfn]
mov bl, byte [reg]
call pci_read_reg
pop ebx
ret
endp
 
align 4
proc pci_read8 stdcall, bus:dword, devfn:dword, reg:dword
push ebx
xor eax, eax
xor ebx, ebx
mov ah, byte [bus]
mov al, 4
mov bh, byte [devfn]
mov bl, byte [reg]
call pci_read_reg
pop ebx
ret
endp
 
align 4
proc pci_write8 stdcall, bus:dword, devfn:dword, reg:dword, val:dword
push ebx
xor eax, eax
xor ebx, ebx
mov ah, byte [bus]
mov al, 8
mov bh, byte [devfn]
mov bl, byte [reg]
mov ecx, [val]
call pci_write_reg
pop ebx
ret
endp
 
align 4
proc pci_write16 stdcall, bus:dword, devfn:dword, reg:dword, val:dword
push ebx
xor eax, eax
xor ebx, ebx
mov ah, byte [bus]
mov al, 9
mov bh, byte [devfn]
mov bl, byte [reg]
mov ecx, [val]
call pci_write_reg
pop ebx
ret
endp
 
align 4
proc pci_write32 stdcall, bus:dword, devfn:dword, reg:dword, val:dword
push ebx
xor eax, eax
xor ebx, ebx
mov ah, byte [bus]
mov al, 10
mov bh, byte [devfn]
mov bl, byte [reg]
mov ecx, [val]
call pci_write_reg
pop ebx
ret
endp
 
handle equ IOCTL.handle
io_code equ IOCTL.io_code
input equ IOCTL.input
inp_size equ IOCTL.inp_size
output equ IOCTL.output
out_size equ IOCTL.out_size
 
 
align 4
proc srv_handler stdcall, ioctl:dword
mov esi, [ioctl]
test esi, esi
jz .err
 
mov edi, [esi+handle]
cmp [edi+SRV.magic], ' SRV'
jne .fail
 
cmp [edi+SRV.size], sizeof.SRV
jne .fail
 
; stdcall [edi+SRV.srv_proc], esi
mov eax, [edi+SRV.srv_proc]
test eax, eax
jz .fail
stdcall eax, esi
ret
.fail:
xor eax, eax
not eax
mov [esi+output], eax
mov [esi+out_size], 4
ret
.err:
xor eax, eax
not eax
ret
endp
 
; param
; ecx= io_control
;
; retval
; eax= error code
 
align 4
srv_handlerEx:
cmp ecx, OS_BASE
jae .fail
 
mov eax, [ecx+handle]
cmp [eax+SRV.magic], ' SRV'
jne .fail
 
cmp [eax+SRV.size], sizeof.SRV
jne .fail
 
; stdcall [eax+SRV.srv_proc], ecx
mov eax, [eax+SRV.srv_proc]
test eax, eax
jz .fail
stdcall eax, ecx
ret
.fail:
or eax, -1
ret
 
restore handle
restore io_code
restore input
restore inp_size
restore output
restore out_size
 
align 4
proc get_service stdcall, sz_name:dword
mov eax, [sz_name]
test eax, eax
jnz @F
ret
@@:
mov edx, [srv.fd]
@@:
cmp edx, srv.fd-SRV.fd
je .not_load
 
stdcall strncmp, edx, [sz_name], 16
test eax, eax
mov eax, edx
je .nothing
 
mov edx, [edx+SRV.fd]
jmp @B
.not_load:
mov eax, [sz_name]
push edi
sub esp, 36
mov edi, esp
mov dword [edi], '/sys'
mov dword [edi+4], '/dri'
mov dword [edi+8], 'vers'
mov byte [edi+12], '/'
@@:
mov dl, [eax]
mov [edi+13], dl
inc eax
inc edi
test dl, dl
jnz @b
mov dword [edi+12], '.sys'
mov byte [edi+16], 0
mov edi, esp
stdcall load_pe_driver, edi, 0
add esp, 36
pop edi
.nothing:
ret
endp
 
reg_service:
xor eax, eax
mov ecx, [esp+8]
jecxz .nothing
push sizeof.SRV
push ecx
pushd [esp+12]
call reg_service_ex
.nothing:
ret 8
 
reg_usb_driver:
push sizeof.USBSRV
pushd [esp+12]
pushd [esp+12]
call reg_service_ex
test eax, eax
jz .nothing
mov ecx, [esp+12]
mov [eax+USBSRV.usb_func], ecx
.nothing:
ret 12
 
proc reg_service_ex stdcall, name:dword, handler:dword, srvsize:dword
 
push ebx
 
xor eax, eax
 
cmp [name], eax
je .fail
 
; cmp [handler], eax
; je .fail
 
mov eax, [srvsize]
call malloc
test eax, eax
jz .fail
 
push esi
push edi
mov edi, eax
mov esi, [name]
movsd
movsd
movsd
movsd
pop edi
pop esi
 
mov [eax+SRV.magic], ' SRV'
mov [eax+SRV.size], sizeof.SRV
 
mov ebx, srv.fd-SRV.fd
mov edx, [ebx+SRV.fd]
mov [eax+SRV.fd], edx
mov [eax+SRV.bk], ebx
mov [ebx+SRV.fd], eax
mov [edx+SRV.bk], eax
 
mov ecx, [handler]
mov [eax+SRV.srv_proc], ecx
pop ebx
ret
.fail:
xor eax, eax
pop ebx
ret
endp
 
align 4
proc get_proc stdcall, exp:dword, sz_name:dword
 
mov edx, [exp]
.next:
mov eax, [edx]
test eax, eax
jz .end
 
push edx
stdcall strncmp, eax, [sz_name], 16
pop edx
test eax, eax
jz .ok
 
add edx, 8
jmp .next
.ok:
mov eax, [edx+4]
.end:
ret
endp
 
align 4
proc get_coff_sym stdcall, pSym:dword,count:dword, sz_sym:dword
 
@@:
stdcall strncmp, [pSym], [sz_sym], 8
test eax, eax
jz .ok
add [pSym], 18
dec [count]
jnz @b
xor eax, eax
ret
.ok:
mov eax, [pSym]
mov eax, [eax+8]
ret
endp
 
align 4
proc get_curr_task
mov eax, [current_slot_idx]
shl eax, 8
ret
endp
 
align 4
proc get_fileinfo stdcall, file_name:dword, info:dword
locals
cmd dd ?
offset dd ?
dd ?
count dd ?
buff dd ?
db ?
name dd ?
endl
 
xor eax, eax
mov ebx, [file_name]
mov ecx, [info]
 
mov [cmd], 5
mov [offset], eax
mov [offset+4], eax
mov [count], eax
mov [buff], ecx
mov byte [buff+4], al
mov [name], ebx
 
mov eax, 70
lea ebx, [cmd]
pushad
cld
call protect_from_terminate
call file_system_lfn
call unprotect_from_terminate
popad
ret
endp
 
align 4
proc read_file stdcall,file_name:dword, buffer:dword, off:dword,\
bytes:dword
locals
cmd dd ?
offset dd ?
dd ?
count dd ?
buff dd ?
db ?
name dd ?
endl
 
xor eax, eax
mov ebx, [file_name]
mov ecx, [off]
mov edx, [bytes]
mov esi, [buffer]
 
mov [cmd], eax
mov [offset], ecx
mov [offset+4], eax
mov [count], edx
mov [buff], esi
mov byte [buff+4], al
mov [name], ebx
 
pushad
lea ebx, [cmd]
call file_system_lfn_protected
popad
ret
endp
 
align 4
; @brief Allocate kernel memory and loads the specified file
;
; @param file_name Path to file
;
; @returns File image in kernel memory in `eax` and size of file in `ebx`
;
; @warning You must call kernel_free() to delete each file loaded by the
; load_file() function
proc load_file stdcall, file_name:dword
locals
attr dd ?
flags dd ?
cr_time dd ?
cr_date dd ?
acc_time dd ?
acc_date dd ?
mod_time dd ?
mod_date dd ?
file_size dd ?
 
file dd ?
file2 dd ?
endl
 
push esi
push edi
 
lea eax, [attr]
stdcall get_fileinfo, [file_name], eax
test eax, eax
jnz .fail
 
mov eax, [file_size]
cmp eax, 1024*1024*16
ja .fail
 
stdcall kernel_alloc, [file_size]
mov [file], eax
test eax, eax
jz .fail
 
stdcall read_file, [file_name], eax, dword 0, [file_size]
cmp ebx, [file_size]
jne .cleanup
 
mov eax, [file]
cmp dword [eax], 'KPCK'
jne .exit
mov ebx, [eax+4]
mov [file_size], ebx
stdcall kernel_alloc, ebx
 
test eax, eax
jz .cleanup
 
mov [file2], eax
 
pushad
mov ecx, unpack_mutex
call mutex_lock
popad
 
stdcall unpack, [file], eax
 
pushad
mov ecx, unpack_mutex
call mutex_unlock
popad
 
stdcall kernel_free, [file]
mov eax, [file2]
mov ebx, [file_size]
.exit:
push eax
lea edi, [eax+ebx] ;cleanup remain space
mov ecx, 4096 ;from file end
and ebx, 4095
jz @f
sub ecx, ebx
xor eax, eax
cld
rep stosb
@@:
mov ebx, [file_size]
pop eax
pop edi
pop esi
ret
.cleanup:
stdcall kernel_free, [file]
.fail:
xor eax, eax
xor ebx, ebx
pop edi
pop esi
ret
endp
 
; description
; allocate user memory and loads the specified file
;
; param
; file_name= path to file
;
; retval
; eax= file image in user memory
; ebx= size of file
;
; warging
; You mast call kernel_free() to delete each file
; loaded by the load_file() function
 
align 4
proc load_file_umode stdcall, file_name:dword
locals
attr dd ?
flags dd ?
cr_time dd ?
cr_date dd ?
acc_time dd ?
acc_date dd ?
mod_time dd ?
mod_date dd ?
file_size dd ?
 
km_file dd ?
um_file dd ?
endl
 
push esi
push edi
push ebx
 
lea eax, [attr]
stdcall get_fileinfo, [file_name], eax ;find file and get info
test eax, eax
jnz .err_1
 
mov eax, [file_size]
cmp eax, 1024*1024*16 ;to be enough for anybody (c)
ja .err_1
;it is very likely that the file is packed
stdcall kernel_alloc, [file_size] ;with kpack, so allocate memory from kernel heap
mov [km_file], eax
test eax, eax
jz .err_1
 
stdcall read_file, [file_name], eax, dword 0, [file_size]
cmp ebx, [file_size]
 
jne .err_2
 
mov eax, [km_file]
cmp dword [eax], 'KPCK' ; check kpack signature
jne .raw_file
 
mov ebx, [eax+4] ;get real size of file
mov [file_size], ebx
stdcall user_alloc, ebx ;and allocate space from user heap
mov [um_file], eax
test eax, eax
jz .err_2
 
mov edx, [file_size] ;preallocate page memory
shr eax, 10
lea edi, [page_tabs+eax]
add edx, 4095
shr edx, 12
@@:
call alloc_page
test eax, eax
jz .err_3
 
or eax, PG_UWR
stosd
dec edx
jnz @B
 
pushad
mov ecx, unpack_mutex
call mutex_lock
 
stdcall unpack, [km_file], [um_file]
 
mov ecx, unpack_mutex
call mutex_unlock
popad
 
stdcall kernel_free, [km_file] ;we don't need packed file anymore
.exit:
 
mov edi, [um_file]
mov esi, [um_file]
mov eax, [file_size]
mov edx, eax
 
add edi, eax ;cleanup remain space
mov ecx, 4096 ;from file end
and eax, 4095
jz @f
sub ecx, eax
xor eax, eax
cld
rep stosb
@@:
mov eax, [um_file]
 
pop ebx
pop edi
pop esi
ret
 
.raw_file: ; sometimes we load unpacked file
stdcall user_alloc, ebx ; allocate space from user heap
mov [um_file], eax
 
test eax, eax
jz .err_2
 
shr eax, 10 ; and remap pages.
 
mov ecx, [file_size]
add ecx, 4095
shr ecx, 12
 
mov esi, [km_file]
shr esi, 10
add esi, page_tabs
 
lea edi, [page_tabs+eax]
 
cld
@@:
lodsd
and eax, 0xFFFFF000
or eax, PG_UWR
stosd
loop @B
 
stdcall free_kernel_space, [km_file] ; release allocated kernel space
jmp .exit ; physical pages still in use
.err_3:
stdcall user_free, [um_file]
.err_2:
stdcall kernel_free, [km_file]
.err_1:
xor eax, eax
xor edx, edx
 
pop ebx
pop edi
pop esi
ret
endp
 
 
uglobal
align 4
unpack_mutex MUTEX
endg
 
align 4
proc get_proc_ex stdcall uses ebx esi, proc_name:dword, imports:dword
mov ebx, [imports]
test ebx, ebx
jz .end
xor esi, esi
.look_up:
 
mov eax, [ebx+32]
mov eax, [OS_BASE+eax+esi*4]
add eax, OS_BASE
stdcall strncmp, eax, [proc_name], 256
test eax, eax
jz .ok
 
inc esi
cmp esi, [ebx+24]
jb .look_up
.end:
xor eax, eax
ret
.ok:
mov eax, [ebx+28]
mov eax, [OS_BASE+eax+esi*4]
add eax, OS_BASE
ret
endp
 
align 4
proc fix_coff_symbols stdcall uses ebx esi, sec:dword, symbols:dword,\
sym_count:dword, strings:dword, imports:dword
locals
retval dd ?
endl
 
mov edi, [symbols]
mov [retval], 1
.fix:
movzx ebx, [edi+COFF_SYM.SectionNumber]
test ebx, ebx
jnz .internal
mov eax, dword [edi+COFF_SYM.Name]
test eax, eax
jnz @F
 
mov edi, [edi+4]
add edi, [strings]
@@:
push edi
stdcall get_proc_ex, edi, [imports]
pop edi
 
xor ebx, ebx
test eax, eax
jnz @F
 
; disable debug msg
;mov esi, msg_unresolved
;call sys_msg_board_str
;mov esi, edi
;call sys_msg_board_str
;mov esi, msg_CR
;call sys_msg_board_str
 
mov [retval], 0
@@:
mov edi, [symbols]
mov [edi+COFF_SYM.Value], eax
jmp .next
.internal:
cmp bx, -1
je .next
cmp bx, -2
je .next
 
dec ebx
shl ebx, 3
lea ebx, [ebx+ebx*4]
add ebx, [sec]
 
mov eax, [ebx+COFF_SECTION.VirtualAddress]
add [edi+COFF_SYM.Value], eax
.next:
add edi, sizeof.COFF_SYM
mov [symbols], edi
dec [sym_count]
jnz .fix
mov eax, [retval]
ret
endp
 
align 4
proc fix_coff_relocs stdcall uses ebx esi, coff:dword, sym:dword, \
delta:dword
locals
n_sec dd ?
endl
 
mov eax, [coff]
movzx ebx, [eax+COFF_HEADER.nSections]
mov [n_sec], ebx
lea esi, [eax+20]
.fix_sec:
mov edi, [esi+COFF_SECTION.PtrReloc]
add edi, [coff]
 
movzx ecx, [esi+COFF_SECTION.NumReloc]
test ecx, ecx
jz .next
.reloc_loop:
mov ebx, [edi+COFF_RELOC.SymIndex]
add ebx, ebx
lea ebx, [ebx+ebx*8]
add ebx, [sym]
 
mov edx, [ebx+COFF_SYM.Value]
 
cmp [edi+COFF_RELOC.Type], 6
je .dir_32
 
cmp [edi+COFF_RELOC.Type], 20
jne .next_reloc
.rel_32:
mov eax, [edi+COFF_RELOC.VirtualAddress]
add eax, [esi+COFF_SECTION.VirtualAddress]
sub edx, eax
sub edx, 4
jmp .fix
.dir_32:
mov eax, [edi+COFF_RELOC.VirtualAddress]
add eax, [esi+COFF_SECTION.VirtualAddress]
.fix:
add eax, [delta]
add [eax], edx
.next_reloc:
add edi, 10
dec ecx
jnz .reloc_loop
.next:
add esi, sizeof.COFF_SECTION
dec [n_sec]
jnz .fix_sec
.exit:
ret
endp
 
align 4
proc rebase_coff stdcall uses ebx esi, coff:dword, sym:dword, \
delta:dword
locals
n_sec dd ?
endl
 
mov eax, [coff]
movzx ebx, [eax+COFF_HEADER.nSections]
mov [n_sec], ebx
lea esi, [eax+20]
mov edx, [delta]
.fix_sec:
mov edi, [esi+COFF_SECTION.PtrReloc]
add edi, [coff]
 
movzx ecx, [esi+COFF_SECTION.NumReloc]
test ecx, ecx
jz .next
.reloc_loop:
cmp [edi+COFF_RELOC.Type], 6
jne .next_reloc
.dir_32:
mov eax, [edi+COFF_RELOC.VirtualAddress]
add eax, [esi+COFF_SECTION.VirtualAddress]
add [eax+edx], edx
.next_reloc:
add edi, 10
dec ecx
jnz .reloc_loop
.next:
add esi, sizeof.COFF_SECTION
dec [n_sec]
jnz .fix_sec
.exit:
ret
endp
 
; in: edx -> COFF_SECTION struct
; out: eax = alignment as mask for bits to drop
coff_get_align:
; Rules:
; - if alignment is not given, use default = 4K;
; - if alignment is given and is no more than 4K, use it;
; - if alignment is more than 4K, revert to 4K.
push ecx
mov cl, byte [edx+COFF_SECTION.Characteristics+2]
mov eax, 1
shr cl, 4
dec cl
js .default
cmp cl, 12
jbe @f
.default:
mov cl, 12
@@:
shl eax, cl
pop ecx
dec eax
ret
 
align 4
proc load_library stdcall, file_name:dword, encoding:dword
locals
fullname dd ?
fileinfo rb 40
coff dd ?
img_base dd ?
endl
 
; resolve file name
stdcall kernel_alloc, maxPathLength
mov [fullname], eax
mov edi, eax
mov esi, [file_name]
mov eax, [encoding]
push ebp
call getFullPath
pop ebp
test eax, eax
jz .fail
; scan for required DLL in list of already loaded for this process,
; ignore timestamp
cli
mov esi, [current_process]
mov edi, [fullname]
mov ebx, [esi+PROC.dlls_list_ptr]
test ebx, ebx
jz .not_in_process
mov esi, [ebx+HDLL.fd]
.scan_in_process:
cmp esi, ebx
jz .not_in_process
mov eax, [esi+HDLL.parent]
add eax, DLLDESCR.name
stdcall strncmp, eax, edi, -1
test eax, eax
jnz .next_in_process
; simple variant: load DLL which is already loaded in this process
; just increment reference counters and return address of exports table
inc [esi+HDLL.refcount]
mov ecx, [esi+HDLL.parent]
inc [ecx+DLLDESCR.refcount]
mov eax, [ecx+DLLDESCR.exports]
sub eax, [ecx+DLLDESCR.defaultbase]
add eax, [esi+HDLL.base]
sti
push eax
stdcall kernel_free, [fullname]
pop eax
ret
 
.next_in_process:
mov esi, [esi+HDLL.fd]
jmp .scan_in_process
 
.not_in_process:
; scan in full list, compare timestamp
sti
lea eax, [fileinfo]
stdcall get_fileinfo, edi, eax
test eax, eax
jnz .fail
cli
mov esi, [dll_list.fd]
.scan_for_dlls:
cmp esi, dll_list
jz .load_new
lea eax, [esi+DLLDESCR.name]
stdcall strncmp, eax, edi, -1
test eax, eax
jnz .continue_scan
.test_prev_dll:
mov eax, dword [fileinfo+24]; last modified time
mov edx, dword [fileinfo+28]; last modified date
cmp dword [esi+DLLDESCR.timestamp], eax
jnz .continue_scan
cmp dword [esi+DLLDESCR.timestamp+4], edx
jz .dll_already_loaded
.continue_scan:
mov esi, [esi+DLLDESCR.fd]
jmp .scan_for_dlls
 
; new DLL
.load_new:
sti
; load file
stdcall load_file, edi
test eax, eax
jz .fail
mov [coff], eax
mov dword [fileinfo+32], ebx
 
; allocate DLLDESCR struct; size is DLLDESCR.sizeof plus size of DLL name
mov esi, edi
mov ecx, -1
xor eax, eax
repnz scasb
not ecx
lea eax, [ecx+sizeof.DLLDESCR]
push ecx
call malloc
pop ecx
test eax, eax
jz .fail_and_free_coff
; save timestamp
lea edi, [eax+DLLDESCR.name]
rep movsb
mov esi, eax
mov eax, dword [fileinfo+24]
mov dword [esi+DLLDESCR.timestamp], eax
mov eax, dword [fileinfo+28]
mov dword [esi+DLLDESCR.timestamp+4], eax
 
; calculate size of loaded DLL
mov edx, [coff]
movzx ecx, [edx+COFF_HEADER.nSections]
xor ebx, ebx
 
add edx, 20
@@:
call coff_get_align
add ebx, eax
not eax
and ebx, eax
add ebx, [edx+COFF_SECTION.SizeOfRawData]
add edx, sizeof.COFF_SECTION
dec ecx
jnz @B
; it must be nonzero and not too big
mov [esi+DLLDESCR.size], ebx
test ebx, ebx
jz .fail_and_free_dll
cmp ebx, MAX_DEFAULT_DLL_ADDR-MIN_DEFAULT_DLL_ADDR
ja .fail_and_free_dll
; allocate memory for kernel-side image
stdcall kernel_alloc, ebx
test eax, eax
jz .fail_and_free_dll
mov [esi+DLLDESCR.data], eax
; calculate preferred base address
add ebx, 0x1FFF
and ebx, not 0xFFF
mov ecx, [dll_cur_addr]
lea edx, [ecx+ebx]
cmp edx, MAX_DEFAULT_DLL_ADDR
jb @f
mov ecx, MIN_DEFAULT_DLL_ADDR
lea edx, [ecx+ebx]
@@:
mov [esi+DLLDESCR.defaultbase], ecx
mov [dll_cur_addr], edx
 
; copy sections and set correct values for VirtualAddress'es in headers
push esi
mov edx, [coff]
movzx ebx, [edx+COFF_HEADER.nSections]
mov edi, eax
add edx, 20
cld
@@:
call coff_get_align
add ecx, eax
add edi, eax
not eax
and ecx, eax
and edi, eax
mov [edx+COFF_SECTION.VirtualAddress], ecx
add ecx, [edx+COFF_SECTION.SizeOfRawData]
mov esi, [edx+COFF_SECTION.PtrRawData]
push ecx
mov ecx, [edx+COFF_SECTION.SizeOfRawData]
test esi, esi
jnz .copy
xor eax, eax
rep stosb
jmp .next
.copy:
add esi, [coff]
rep movsb
.next:
pop ecx
add edx, sizeof.COFF_SECTION
dec ebx
jnz @B
pop esi
 
; save some additional data from COFF file
; later we will use COFF header, headers for sections and symbol table
; and also relocations table for all sections
mov edx, [coff]
mov ebx, [edx+COFF_HEADER.pSymTable]
mov edi, dword [fileinfo+32]
sub edi, ebx
jc .fail_and_free_data
mov [esi+DLLDESCR.symbols_lim], edi
add ebx, edx
movzx ecx, [edx+COFF_HEADER.nSections]
lea ecx, [ecx*5]
lea edi, [edi+ecx*8+20]
add edx, 20
@@:
movzx eax, [edx+COFF_SECTION.NumReloc]
lea eax, [eax*5]
lea edi, [edi+eax*2]
add edx, sizeof.COFF_SECTION
sub ecx, 5
jnz @b
stdcall kernel_alloc, edi
test eax, eax
jz .fail_and_free_data
mov edx, [coff]
movzx ecx, [edx+COFF_HEADER.nSections]
lea ecx, [ecx*5]
lea ecx, [ecx*2+5]
mov [esi+DLLDESCR.coff_hdr], eax
push esi
mov esi, edx
mov edi, eax
rep movsd
pop esi
mov [esi+DLLDESCR.symbols_ptr], edi
push esi
mov ecx, [edx+COFF_HEADER.nSymbols]
mov [esi+DLLDESCR.symbols_num], ecx
mov ecx, [esi+DLLDESCR.symbols_lim]
mov esi, ebx
rep movsb
pop esi
mov ebx, [esi+DLLDESCR.coff_hdr]
push esi
movzx eax, [edx+COFF_HEADER.nSections]
lea edx, [ebx+20]
@@:
movzx ecx, [edx+COFF_SECTION.NumReloc]
lea ecx, [ecx*5]
mov esi, [edx+COFF_SECTION.PtrReloc]
mov [edx+COFF_SECTION.PtrReloc], edi
sub [edx+COFF_SECTION.PtrReloc], ebx
add esi, [coff]
shr ecx, 1
rep movsd
adc ecx, ecx
rep movsw
add edx, sizeof.COFF_SECTION
dec eax
jnz @b
pop esi
 
; fixup symbols
mov edx, ebx
mov eax, [ebx+COFF_HEADER.nSymbols]
add edx, 20
mov ecx, [esi+DLLDESCR.symbols_num]
lea ecx, [ecx*9]
add ecx, ecx
add ecx, [esi+DLLDESCR.symbols_ptr]
 
stdcall fix_coff_symbols, edx, [esi+DLLDESCR.symbols_ptr], eax, \
ecx, 0
; test eax, eax
; jnz @F
;
;@@:
 
stdcall get_coff_sym, [esi+DLLDESCR.symbols_ptr], [ebx+COFF_HEADER.nSymbols], szEXPORTS
test eax, eax
jnz @F
 
stdcall get_coff_sym, [esi+DLLDESCR.symbols_ptr], [ebx+COFF_HEADER.nSymbols], sz_EXPORTS
@@:
mov [esi+DLLDESCR.exports], eax
 
; fix relocs in the hidden copy in kernel memory to default address
; it is first fix; usually this will be enough, but second fix
; can be necessary if real load address will not equal assumption
mov eax, [esi+DLLDESCR.data]
sub eax, [esi+DLLDESCR.defaultbase]
stdcall fix_coff_relocs, ebx, [esi+DLLDESCR.symbols_ptr], eax
 
stdcall kernel_free, [coff]
 
cli
; initialize DLLDESCR struct
and dword [esi+DLLDESCR.refcount], 0; no HDLLs yet; later it will be incremented
mov [esi+DLLDESCR.fd], dll_list
mov eax, [dll_list.bk]
mov [dll_list.bk], esi
mov [esi+DLLDESCR.bk], eax
mov [eax+DLLDESCR.fd], esi
.dll_already_loaded:
stdcall kernel_free, [fullname]
inc [esi+DLLDESCR.refcount]
push esi
call init_heap
pop esi
mov edi, [esi+DLLDESCR.size]
stdcall user_alloc_at, [esi+DLLDESCR.defaultbase], edi
test eax, eax
jnz @f
stdcall user_alloc, edi
test eax, eax
jz .fail_and_dereference
@@:
mov [img_base], eax
mov eax, sizeof.HDLL
call malloc
test eax, eax
jz .fail_and_free_user
mov ebx, [current_slot_idx]
shl ebx, 5
mov edx, [TASK_TABLE+ebx+TASKDATA.pid]
mov [eax+HDLL.pid], edx
push eax
call init_dlls_in_thread
pop ebx
test eax, eax
jz .fail_and_free_user
mov edx, [eax+HDLL.fd]
mov [ebx+HDLL.fd], edx
mov [ebx+HDLL.bk], eax
mov [eax+HDLL.fd], ebx
mov [edx+HDLL.bk], ebx
mov eax, ebx
mov ebx, [img_base]
mov [eax+HDLL.base], ebx
mov [eax+HDLL.size], edi
mov [eax+HDLL.refcount], 1
mov [eax+HDLL.parent], esi
mov edx, ebx
shr edx, 12
or dword [page_tabs+(edx-1)*4], MEM_BLOCK_DONT_FREE
; copy entries of page table from kernel-side image to usermode
; use copy-on-write for user-mode image, so map as readonly
xor edi, edi
mov ecx, [esi+DLLDESCR.data]
shr ecx, 12
.map_pages_loop:
mov eax, [page_tabs+ecx*4]
and eax, not 0xFFF
or al, PG_UR
xchg eax, [page_tabs+edx*4]
test al, 1
jz @f
call free_page
@@:
invlpg [ebx+edi]
inc ecx
inc edx
add edi, 0x1000
cmp edi, [esi+DLLDESCR.size]
jb .map_pages_loop
 
; if real user-mode base is not equal to preferred base, relocate image
sub ebx, [esi+DLLDESCR.defaultbase]
jz @f
stdcall rebase_coff, [esi+DLLDESCR.coff_hdr], [esi+DLLDESCR.symbols_ptr], ebx
@@:
 
mov eax, [esi+DLLDESCR.exports]
sub eax, [esi+DLLDESCR.defaultbase]
add eax, [img_base]
sti
ret
 
.fail_and_free_data:
stdcall kernel_free, [esi+DLLDESCR.data]
.fail_and_free_dll:
mov eax, esi
call free
.fail_and_free_coff:
stdcall kernel_free, [coff]
.fail:
stdcall kernel_free, [fullname]
xor eax, eax
ret
 
.fail_and_free_user:
stdcall user_free, [img_base]
.fail_and_dereference:
mov eax, 1 ; delete 1 reference
call dereference_dll
sti
xor eax, eax
ret
endp
 
; initialize [APPDATA.dlls_list_ptr] for given thread
; DLL is per-process object, so APPDATA.dlls_list_ptr must be
; kept in sync for all threads of one process.
; out: eax = APPDATA.dlls_list_ptr if all is OK,
; NULL if memory allocation failed
init_dlls_in_thread:
mov ebx, [current_process]
mov eax, [ebx+PROC.dlls_list_ptr]
test eax, eax
jnz .ret
 
mov eax, 8
call malloc ; FIXME
test eax, eax
jz .ret
 
mov [eax], eax
mov [eax+4], eax
 
mov ebx, [current_process]
mov [ebx+PROC.dlls_list_ptr], eax
.ret:
ret
 
; in: eax = number of references to delete, esi -> DLLDESCR struc
dereference_dll:
sub [esi+DLLDESCR.refcount], eax
jnz .ret
mov eax, [esi+DLLDESCR.fd]
mov edx, [esi+DLLDESCR.bk]
mov [eax+DLLDESCR.bk], edx
mov [edx+DLLDESCR.fd], eax
stdcall kernel_free, [esi+DLLDESCR.coff_hdr]
stdcall kernel_free, [esi+DLLDESCR.data]
mov eax, esi
call free
.ret:
ret
 
destroy_hdll:
push ebx ecx esi edi
mov ebx, [eax+HDLL.base]
mov esi, [eax+HDLL.parent]
mov edx, [esi+DLLDESCR.size]
 
push eax
mov esi, [eax+HDLL.parent]
mov eax, [eax+HDLL.refcount]
call dereference_dll
pop eax
mov edx, [eax+HDLL.bk]
mov ebx, [eax+HDLL.fd]
mov [ebx+HDLL.bk], edx
mov [edx+HDLL.fd], ebx
call free
pop edi esi ecx ebx
ret
 
; ecx -> APPDATA for slot, esi = dlls_list_ptr
destroy_all_hdlls:
test esi, esi
jz .ret
.loop:
mov eax, [esi+HDLL.fd]
cmp eax, esi
jz free
call destroy_hdll
jmp .loop
.ret:
ret
 
align 4
stop_all_services:
push ebp
mov edx, [srv.fd]
.next:
cmp edx, srv.fd-SRV.fd
je .done
cmp [edx+SRV.magic], ' SRV'
jne .next
cmp [edx+SRV.size], sizeof.SRV
jne .next
 
mov ebx, [edx+SRV.entry]
mov edx, [edx+SRV.fd]
test ebx, ebx
jz .next
 
push edx
mov ebp, esp
push 0
push -1
call ebx
mov esp, ebp
pop edx
jmp .next
.done:
pop ebp
ret
 
; param
; eax= size
; ebx= pid
 
align 4
create_kernel_object:
 
push ebx
call malloc
pop ebx
test eax, eax
jz .fail
 
mov ecx, [current_slot]
add ecx, APP_OBJ_OFFSET
 
pushfd
cli
mov edx, [ecx+APPOBJ.fd]
mov [eax+APPOBJ.fd], edx
mov [eax+APPOBJ.bk], ecx
mov [eax+APPOBJ.pid], ebx
 
mov [ecx+APPOBJ.fd], eax
mov [edx+APPOBJ.bk], eax
popfd
.fail:
ret
 
; param
; eax= object
 
align 4
destroy_kernel_object:
 
pushfd
cli
mov ebx, [eax+APPOBJ.fd]
mov ecx, [eax+APPOBJ.bk]
mov [ebx+APPOBJ.bk], ecx
mov [ecx+APPOBJ.fd], ebx
popfd
 
xor edx, edx ;clear common header
mov [eax], edx
mov [eax+4], edx
mov [eax+8], edx
mov [eax+12], edx
mov [eax+16], edx
 
call free ;release object memory
ret
 
 
;void* __fastcall create_object(size_t size)
; param
; ecx= size
 
align 4
create_object:
 
push esi
push edi
pushfd
cli
 
mov esi, [current_process]
mov eax, [esi+PROC.ht_free]
mov edi, [esi+PROC.ht_next]
dec eax
js .err0
 
mov [esi+PROC.ht_free], eax
mov eax, [esi+PROC.htab+edi*4]
mov [esi+PROC.ht_next], eax
popfd
 
mov eax, ecx
call malloc
test eax, eax
jz .err1
 
mov [eax+FUTEX.handle], edi
mov [esi+PROC.htab+edi*4], eax
pop edi
pop esi
ret
 
.err1:
pushfd
cli
 
mov eax, [esi+PROC.ht_next]
mov [esi+PROC.htab+edi*4], eax
mov [esi+PROC.ht_next], edi
inc [esi+PROC.ht_free]
.err0:
popfd
pop edi
pop esi
xor eax, eax
ret
 
 
;int __fastcall destroy_object(struct object *obj)
 
align 4
destroy_object:
push esi
mov esi, [current_process]
mov edx, [ecx+FUTEX.handle]
 
pushfd
cli
 
mov eax, [esi+PROC.ht_next]
mov [esi+PROC.htab+edx*4], eax
mov [esi+PROC.ht_next], edx
inc [esi+PROC.ht_free]
 
popfd
pop esi
 
mov eax, ecx
call free
xor eax, eax
ret
.fail:
popfd
pop esi
mov eax, -1
ret
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/syscall.inc
0,0 → 1,186
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; SYSENTER ENTRY ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
align 32
sysenter_entry:
; Setting up the stack
mov esp, [ss:tss._esp0]
sti
push ebp ; save app esp + 4
mov ebp, [ebp] ; ebp - original ebp
;------------------
pushad
cld
 
call protect_from_terminate
 
movzx eax, byte [esp+28]
mov edx, dword [esp+20]
call dword [servetable2 + eax * 4]
 
call unprotect_from_terminate
popad
;------------------
xchg ecx, [ss:esp] ; in the stack top - app ecx, ecx - app esp + 4
sub ecx, 4
xchg edx, [ecx] ; edx - return point, & save original edx
push edx
mov edx, [ss:esp + 4]
mov [ecx + 4], edx ; save original ecx
pop edx
sysexit
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; SYSTEM CALL ENTRY ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
align 16
i40:
pushad
cld
call protect_from_terminate
movzx eax, byte [esp+28]
mov edx, dword [esp+20]
call dword [servetable2 + eax * 4]
call unprotect_from_terminate
popad
iretd
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; SYSCALL ENTRY ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 32
syscall_entry:
; cli syscall clear IF
xchg esp, [ss:tss._esp0]
push ecx
lea ecx, [esp+4]
xchg ecx, [ss:tss._esp0]
sti
push ecx
mov ecx, [ecx]
;------------------
pushad
cld
call protect_from_terminate
 
movzx eax, byte [esp+28]
mov edx, dword [esp+20]
call dword [servetable2 + eax * 4]
 
call unprotect_from_terminate
popad
;------------------
mov ecx, [ss:esp+4]
pop esp
sysret
 
iglobal
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; SYSTEM FUNCTIONS TABLE ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 4
servetable2:
 
dd syscall_draw_window ; 0-DrawWindow
dd syscall_setpixel ; 1-SetPixel
dd sys_getkey ; 2-GetKey
dd sys_clock ; 3-GetTime
dd syscall_writetext ; 4-WriteText
dd delay_hs_unprotected ; 5-DelayHs
dd undefined_syscall ; 6-deprecated OpenRamdiskFile
dd syscall_putimage ; 7-PutImage
dd syscall_button ; 8-DefineButton
dd sys_cpuusage ; 9-GetProcessInfo
dd sys_waitforevent ; 10-WaitForEvent
dd sys_getevent ; 11-CheckForEvent
dd sys_redrawstat ; 12-BeginDraw and EndDraw
dd syscall_drawrect ; 13-DrawRect
dd syscall_getscreensize ; 14-GetScreenSize
dd sys_background ; 15-bgr
dd sys_cachetodiskette ; 16-FlushFloppyCache
dd sys_getbutton ; 17-GetButton
dd sys_system ; 18-System Services
dd paleholder ; 19-reserved
dd sys_midi ; 20-ResetMidi and OutputMidi
dd sys_setup ; 21-SetMidiBase,SetKeymap,SetShiftKeymap,.
dd sys_settime ; 22-setting date,time,clock and alarm-clock
dd sys_wait_event_timeout ; 23-TimeOutWaitForEvent
dd syscall_cdaudio ; 24-PlayCdTrack,StopCd and GetCdPlaylist
dd syscall_putarea_backgr ; 25-Put Area to background
dd sys_getsetup ; 26-GetMidiBase,GetKeymap,GetShiftKeymap,.
dd undefined_syscall ; 27-reserved
dd undefined_syscall ; 28-reserved
dd sys_date ; 29-GetDate
dd sys_current_directory ; 30-Get/SetCurrentDirectory
dd undefined_syscall ; 31-reserved
dd undefined_syscall ; 32-reserved
dd undefined_syscall ; 33-reserved
dd syscall_getpixel_WinMap ; 34-GetPixel WinMap
dd syscall_getpixel ; 35-GetPixel
dd syscall_getarea ; 36-GetArea
dd readmousepos ; 37-GetMousePosition_ScreenRelative,.
dd syscall_drawline ; 38-DrawLine
dd sys_getbackground ; 39-GetBackgroundSize,ReadBgrData,.
dd set_app_param ; 40-WantEvents
dd undefined_syscall ; 41- deprecated GetIrqOwner
dd undefined_syscall ; 42- deprecated ReadIrqData
dd sys_outport ; 43-SendDeviceData
dd undefined_syscall ; 44- deprecated ProgramIrqs
dd undefined_syscall ; 45- deprecated ReserveIrq and FreeIrq
dd syscall_reserveportarea ; 46-ReservePortArea and FreePortArea
dd display_number ; 47-WriteNum
dd syscall_display_settings ; 48-SetRedrawType and SetButtonType
dd sys_apm ; 49-Advanced Power Management (APM)
dd syscall_set_window_shape ; 50-Window shape & scale
dd syscall_threads ; 51-Threads
dd undefined_syscall ; 52- deprecated Stack driver status
dd undefined_syscall ; 53- deprecated Socket interface
dd sys_clipboard ; 54-Custom clipboard
dd sound_interface ; 55-Sound interface
dd undefined_syscall ; 56-reserved
dd sys_pcibios ; 57-PCI BIOS32
dd undefined_syscall ; 58-deprecated Common file system interface
dd undefined_syscall ; 59-reserved
dd sys_IPC ; 60-Inter Process Communication
dd sys_gs ; 61-Direct graphics access
dd pci_api ; 62-PCI functions
dd sys_msg_board ; 63-System message board
dd sys_resize_app_memory ; 64-Resize application memory usage
dd sys_putimage_palette ; 65-PutImagePalette
dd sys_process_def ; 66-Process definitions - keyboard
dd syscall_move_window ; 67-Window move or resize
dd f68 ; 68-Some internal services
dd sys_debug_services ; 69-Debug
dd file_system_lfn ; 70-Common file system interface, version 2
dd syscall_window_settings ; 71-Window settings
dd sys_sendwindowmsg ; 72-Send window message
dd blit_32 ; 73-blitter;
dd sys_network ; 74-reserved for new stack
dd sys_socket ; 75-reserved for new stack
dd sys_protocols ; 76-reserved for new stack
dd sys_posix ; posix support
dd undefined_syscall ; 78-free
dd undefined_syscall ; 79-free
dd fileSystemUnicode ; 80-File system interface for different encodings
 
times 255 - ( ($-servetable2) /4 ) dd undefined_syscall
dd sys_end ; -1-end application
 
endg
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/debug.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/memory.inc
0,0 → 1,1364
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
align 4
proc alloc_page
 
pushfd
cli
push ebx
 
cmp [pg_data.pages_free], 1
jle .out_of_memory
 
 
mov ebx, [page_start]
mov ecx, [page_end]
.l1:
bsf eax, [ebx];
jnz .found
add ebx, 4
cmp ebx, ecx
jb .l1
pop ebx
popfd
xor eax, eax
ret
.found:
 
dec [pg_data.pages_free]
jz .out_of_memory
 
btr [ebx], eax
mov [page_start], ebx
sub ebx, sys_pgmap
lea eax, [eax+ebx*8]
shl eax, 12
; dec [pg_data.pages_free]
pop ebx
popfd
ret
 
.out_of_memory:
mov [pg_data.pages_free], 1
xor eax, eax
pop ebx
popfd
ret
 
endp
 
align 4
proc alloc_pages stdcall, count:dword
pushfd
push ebx
push edi
cli
mov eax, [count]
add eax, 7
shr eax, 3
mov [count], eax
 
mov ebx, [pg_data.pages_free]
sub ebx, 9
js .out_of_memory
shr ebx, 3
cmp eax, ebx
jg .out_of_memory
 
mov ecx, [page_start]
mov ebx, [page_end]
.find:
mov edx, [count]
mov edi, ecx
.match:
cmp byte [ecx], 0xFF
jne .next
dec edx
jz .ok
inc ecx
cmp ecx, ebx
jb .match
.out_of_memory:
.fail:
xor eax, eax
pop edi
pop ebx
popfd
ret
.next:
inc ecx
cmp ecx, ebx
jb .find
pop edi
pop ebx
popfd
xor eax, eax
ret
.ok:
sub ecx, edi
inc ecx
push esi
mov esi, edi
xor eax, eax
rep stosb
sub esi, sys_pgmap
shl esi, 3+12
mov eax, esi
mov ebx, [count]
shl ebx, 3
sub [pg_data.pages_free], ebx
pop esi
pop edi
pop ebx
popfd
ret
endp
 
align 4
;proc map_page stdcall,lin_addr:dword,phis_addr:dword,flags:dword
map_page:
push ebx
mov eax, [esp+12] ; phis_addr
or eax, [esp+16] ; flags
and eax, [pte_valid_mask]
mov ebx, [esp+8] ; lin_addr
shr ebx, 12
mov [page_tabs+ebx*4], eax
mov eax, [esp+8] ; lin_addr
pop ebx
invlpg [eax]
ret 12
 
align 4
map_space: ;not implemented
 
 
ret
 
 
align 4
proc free_page
;arg: eax page address
pushfd
cli
shr eax, 12 ;page index
bts dword [sys_pgmap], eax ;that's all!
cmc
adc [pg_data.pages_free], 0
shr eax, 3
and eax, not 3 ;dword offset from page_map
add eax, sys_pgmap
cmp [page_start], eax
ja @f
popfd
ret
@@:
mov [page_start], eax
popfd
ret
endp
 
align 4
proc map_io_mem stdcall, base:dword, size:dword, flags:dword
 
push ebx
push edi
mov eax, [size]
add eax, [base]
add eax, 4095
and eax, -4096
mov ecx, [base]
and ecx, -4096
sub eax, ecx
mov [size], eax
 
stdcall alloc_kernel_space, eax
test eax, eax
jz .fail
push eax
 
mov edi, 0x1000
mov ebx, eax
mov ecx, [size]
mov edx, [base]
shr eax, 12
shr ecx, 12
or edx, [flags]
and edx, [pte_valid_mask]
@@:
mov [page_tabs+eax*4], edx
invlpg [ebx]
inc eax
add ebx, edi
add edx, edi
loop @B
 
pop eax
mov edx, [base]
and edx, 4095
add eax, edx
.fail:
pop edi
pop ebx
ret
endp
 
; param
; eax= page base + page flags
; ebx= linear address
; ecx= count
 
align 4
commit_pages:
test ecx, ecx
jz .fail
 
push edi
push eax
push ecx
mov ecx, pg_data.mutex
call mutex_lock
pop ecx
pop eax
 
and eax, [pte_valid_mask ]
mov edi, ebx
shr edi, 12
lea edi, [page_tabs+edi*4]
@@:
stosd
invlpg [ebx]
add eax, 0x1000
add ebx, 0x1000
loop @B
 
pop edi
 
mov ecx, pg_data.mutex
call mutex_unlock
.fail:
ret
 
 
; param
; eax= base
; ecx= count
 
align 4
release_pages:
 
push ebp
push esi
push edi
push ebx
 
mov esi, eax
mov edi, eax
 
shr esi, 12
lea esi, [page_tabs+esi*4]
 
push ecx
mov ecx, pg_data.mutex
call mutex_lock
pop ecx
 
mov ebp, [pg_data.pages_free]
mov ebx, [page_start]
mov edx, sys_pgmap
@@:
xor eax, eax
xchg eax, [esi]
invlpg [edi]
 
test eax, 1
jz .next
 
shr eax, 12
bts [edx], eax
cmc
adc ebp, 0
shr eax, 3
and eax, -4
add eax, edx
cmp eax, ebx
jae .next
 
mov ebx, eax
.next:
add edi, 0x1000
add esi, 4
loop @B
 
mov [pg_data.pages_free], ebp
mov ecx, pg_data.mutex
call mutex_unlock
 
pop ebx
pop edi
pop esi
pop ebp
ret
 
; param
; eax= base
; ecx= count
 
align 4
unmap_pages:
 
push edi
 
mov edi, eax
mov edx, eax
 
shr edi, 10
add edi, page_tabs
 
xor eax, eax
@@:
stosd
invlpg [edx]
add edx, 0x1000
loop @b
 
pop edi
ret
 
 
align 4
proc map_page_table stdcall, lin_addr:dword, phis_addr:dword
push ebx
mov ebx, [lin_addr]
shr ebx, 22
mov eax, [phis_addr]
and eax, not 0xFFF
or eax, PG_UWR
mov dword [master_tab+ebx*4], eax
mov eax, [lin_addr]
shr eax, 10
add eax, page_tabs
invlpg [eax]
pop ebx
ret
endp
 
uglobal
sb16_buffer_allocated db 0
endg
 
; Allocates [.size] bytes so that the target memory block
; is inside one 64K page for 24-bit DMA controller,
; that is, somewhere between 00xx0000h and 00xxFFFFh.
proc alloc_dma24
; Implementation note.
; The only user of that function is SB16 driver,
; so just return a statically allocated buffer.
virtual at esp
dd ? ; return address
.size dd ?
end virtual
cmp [sb16_buffer_allocated], 0
jnz .fail
inc [sb16_buffer_allocated]
mov eax, SB16Buffer
ret 4
.fail:
xor eax, eax
ret 4
endp
 
; Allocates a physical page for master page table
; that duplicates first Mb of OS_BASE at address 0;
; used for starting APs and for shutting down,
; where it is important to execute code in trivial-mapped pages.
; Returns eax = allocated physical page.
proc create_trampoline_pgmap
; The only non-trivial moment:
; we need a linear address to fill information,
; but we don't need it outside of this function,
; so we're returning physical address.
; Therefore, allocate memory with kernel_alloc,
; this will allocate physical page and a linear address somewhere,
; and deallocate only linear address with free_kernel_space.
stdcall kernel_alloc, 0x1000
mov edi, eax
mov esi, master_tab
mov ecx, 1024
rep movsd
mov ecx, [master_tab+(OS_BASE shr 20)]
mov [eax], ecx
mov edi, eax
call get_pg_addr
push eax
stdcall free_kernel_space, edi
pop eax
ret
endp
 
align 4
proc new_mem_resize stdcall, new_size:dword
 
push ebx
push esi
push edi
 
mov edx, [current_slot]
mov ebx, [edx+APPDATA.process]
 
cmp [ebx+PROC.heap_base], 0
jne .exit
 
mov edi, [new_size]
add edi, 4095
and edi, not 4095
mov [new_size], edi
 
mov esi, [ebx+PROC.mem_used]
add esi, 4095
and esi, not 4095
 
cmp edi, esi
ja .expand
je .exit
 
mov ebx, edi
shr edi, 12
shr esi, 12
 
mov ecx, pg_data.mutex
call mutex_lock
@@:
mov eax, [app_page_tabs+edi*4]
test eax, 1
jz .next
 
mov dword [app_page_tabs+edi*4], 0
invlpg [ebx]
call free_page
 
.next:
inc edi
add ebx, 0x1000
cmp edi, esi
jb @B
 
mov ecx, pg_data.mutex
call mutex_unlock
 
.update_size:
mov edx, [current_slot]
mov ebx, [new_size]
mov edx, [edx+APPDATA.process]
mov [edx+PROC.mem_used], ebx
.exit:
pop edi
pop esi
pop ebx
xor eax, eax
ret
 
.expand:
 
mov ecx, pg_data.mutex
call mutex_lock
 
xchg esi, edi
 
push esi ;new size
push edi ;old size
 
add edi, 0x3FFFFF
and edi, not(0x3FFFFF)
add esi, 0x3FFFFF
and esi, not(0x3FFFFF)
 
cmp edi, esi
jae .grow
@@:
call alloc_page
test eax, eax
jz .exit_fail
 
stdcall map_page_table, edi, eax
 
push edi
shr edi, 10
add edi, page_tabs
mov ecx, 1024
xor eax, eax
cld
rep stosd
pop edi
 
add edi, 0x00400000
cmp edi, esi
jb @B
.grow:
pop edi ;old size
pop ecx ;new size
 
shr edi, 10
shr ecx, 10
sub ecx, edi
shr ecx, 2 ;pages count
mov eax, 2
 
add edi, app_page_tabs
rep stosd
 
mov ecx, pg_data.mutex
call mutex_unlock
 
jmp .update_size
 
.exit_fail:
mov ecx, pg_data.mutex
call mutex_unlock
 
add esp, 8
pop edi
pop esi
pop ebx
xor eax, eax
inc eax
ret
endp
 
 
; param
; eax= linear address
;
; retval
; eax= physical page address
 
align 4
get_pg_addr:
sub eax, OS_BASE
cmp eax, 0x400000
jb @f
shr eax, 12
mov eax, [page_tabs+(eax+(OS_BASE shr 12))*4]
@@:
and eax, 0xFFFFF000
ret
 
 
align 4
; Now it is called from core/sys32::exc_c (see stack frame there)
proc page_fault_handler
 
.err_addr equ ebp-4
 
push ebx ;save exception number (#PF)
mov ebp, esp
mov ebx, cr2
push ebx ;that is locals: .err_addr = cr2
inc [pg_data.pages_faults]
 
mov eax, [pf_err_code]
 
cmp ebx, OS_BASE ;ebx == .err_addr
jb .user_space ;page in application memory
 
cmp ebx, page_tabs
jb .kernel_space ;page in kernel memory
 
cmp ebx, kernel_tabs
jb .alloc;.app_tabs ;page tables of application ;
;simply create one
.core_tabs:
.fail: ;simply return to caller
mov esp, ebp
pop ebx ;restore exception number (#PF)
ret
 
.user_space:
test eax, PG_READ
jnz .err_access ;Page presents
;Access error ?
 
shr ebx, 12
mov ecx, ebx
shr ecx, 10
mov edx, [master_tab+ecx*4]
test edx, PG_READ
jz .fail ;page table is not created
;incorrect address in program
 
mov eax, [page_tabs+ebx*4]
test eax, 2
jz .fail ;address is not reserved for usage. Error
.alloc:
call alloc_page
test eax, eax
jz .fail
 
stdcall map_page, [.err_addr], eax, PG_UWR
 
mov edi, [.err_addr]
and edi, 0xFFFFF000
mov ecx, 1024
xor eax, eax
;cld ;caller is duty for this
rep stosd
.exit: ;iret with repeat fault instruction
add esp, 12;clear in stack: locals(.err_addr) + #PF + ret_to_caller
restore_ring3_context
iretd
 
.err_access:
; access denied? this may be a result of copy-on-write protection for DLL
; check list of HDLLs
and ebx, not 0xFFF
mov eax, [current_process]
mov eax, [eax+PROC.dlls_list_ptr]
test eax, eax
jz .fail
mov esi, [eax+HDLL.fd]
.scan_hdll:
cmp esi, eax
jz .fail
mov edx, ebx
sub edx, [esi+HDLL.base]
cmp edx, [esi+HDLL.size]
jb .fault_in_hdll
.scan_hdll.next:
mov esi, [esi+HDLL.fd]
jmp .scan_hdll
.fault_in_hdll:
; allocate new page, map it as rw and copy data
call alloc_page
test eax, eax
jz .fail
stdcall map_page, ebx, eax, PG_UWR
mov edi, ebx
mov ecx, 1024
sub ebx, [esi+HDLL.base]
mov esi, [esi+HDLL.parent]
mov esi, [esi+DLLDESCR.data]
add esi, ebx
rep movsd
jmp .exit
 
.kernel_space:
test eax, PG_READ
jz .fail ;page does not present
 
test eax, 12 ;U/S (+below)
jnz .fail ;application requested kernel memory
;test eax, 8
;jnz .fail ;the reserved bit is set in page tables. Added in P4/Xeon
 
;an attempt to write to a protected kernel page
 
cmp ebx, tss._io_map_0
jb .fail
 
cmp ebx, tss._io_map_0+8192
jae .fail
 
; io permission map
; copy-on-write protection
 
call alloc_page
test eax, eax
jz .fail
 
push eax
stdcall map_page, [.err_addr], eax, dword PG_SWR
pop eax
mov edi, [.err_addr]
and edi, -4096
lea esi, [edi+(not tss._io_map_0)+1]; -tss._io_map_0
 
mov ebx, esi
shr ebx, 12
mov edx, [current_slot]
or eax, PG_SWR
mov [edx+APPDATA.io_map+ebx*4], eax
 
add esi, [default_io_map]
mov ecx, 4096/4
;cld ;caller is duty for this
rep movsd
jmp .exit
endp
 
; returns number of mapped bytes
proc map_mem_ipc stdcall, lin_addr:dword,slot:dword,\
ofs:dword,buf_size:dword,req_access:dword
locals
count dd ?
process dd ?
endl
 
mov [count], 0
cmp [buf_size], 0
jz .exit
 
mov eax, [slot]
shl eax, 8
mov eax, [SLOT_BASE+eax+APPDATA.process]
test eax, eax
jz .exit
 
mov [process], eax
mov ebx, [ofs]
shr ebx, 22
mov eax, [eax+PROC.pdt_0+ebx*4] ;get page table
mov esi, [ipc_ptab]
and eax, 0xFFFFF000
jz .exit
stdcall map_page, esi, eax, PG_SWR
@@:
mov edi, [lin_addr]
and edi, 0xFFFFF000
mov ecx, [buf_size]
add ecx, 4095
shr ecx, 12
inc ecx ; ???????????
 
mov edx, [ofs]
shr edx, 12
and edx, 0x3FF
.map:
stdcall safe_map_page, [slot], [req_access], [ofs]
jnc .exit
add [count], PAGE_SIZE
add [ofs], PAGE_SIZE
dec ecx
jz .exit
 
add edi, PAGE_SIZE
inc edx
cmp edx, 1024
jnz .map
 
inc ebx
mov eax, [process]
mov eax, [eax+PROC.pdt_0+ebx*4]
and eax, 0xFFFFF000
jz .exit
 
stdcall map_page, esi, eax, PG_SWR
xor edx, edx
jmp .map
.exit:
mov eax, [count]
ret
endp
 
proc map_memEx stdcall, lin_addr:dword,slot:dword,\
ofs:dword,buf_size:dword,req_access:dword
locals
count dd ?
process dd ?
endl
 
mov [count], 0
cmp [buf_size], 0
jz .exit
 
mov eax, [slot]
shl eax, 8
mov eax, [SLOT_BASE+eax+APPDATA.process]
test eax, eax
jz .exit
 
mov [process], eax
mov ebx, [ofs]
shr ebx, 22
mov eax, [eax+PROC.pdt_0+ebx*4] ;get page table
mov esi, [proc_mem_tab]
and eax, 0xFFFFF000
jz .exit
stdcall map_page, esi, eax, PG_SWR
@@:
mov edi, [lin_addr]
and edi, 0xFFFFF000
mov ecx, [buf_size]
add ecx, 4095
shr ecx, 12
inc ecx ; ???????????
 
mov edx, [ofs]
shr edx, 12
and edx, 0x3FF
.map:
stdcall safe_map_page, [slot], [req_access], [ofs]
jnc .exit
add [count], PAGE_SIZE
add [ofs], PAGE_SIZE
dec ecx
jz .exit
 
add edi, PAGE_SIZE
inc edx
cmp edx, 1024
jnz .map
 
inc ebx
mov eax, [process]
mov eax, [eax+PROC.pdt_0+ebx*4]
and eax, 0xFFFFF000
jz .exit
 
stdcall map_page, esi, eax, PG_SWR
xor edx, edx
jmp .map
.exit:
mov eax, [count]
ret
endp
 
; in: esi+edx*4 = pointer to page table entry
; in: [slot], [req_access], [ofs] on the stack
; in: edi = linear address to map
; out: CF cleared <=> failed
; destroys: only eax
proc safe_map_page stdcall, slot:dword, req_access:dword, ofs:dword
mov eax, [esi+edx*4]
test al, PG_READ
jz .not_present
test al, PG_WRITE
jz .resolve_readonly
; normal case: writable page, just map with requested access
.map:
stdcall map_page, edi, eax, [req_access]
stc
.fail:
ret
.not_present:
; check for alloc-on-demand page
test al, 2
jz .fail
; allocate new page, save it to source page table
push ecx
call alloc_page
pop ecx
test eax, eax
jz .fail
or al, PG_UWR
mov [esi+edx*4], eax
jmp .map
.resolve_readonly:
; readonly page, probably copy-on-write
; check: readonly request of readonly page is ok
test [req_access], PG_WRITE
jz .map
; find control structure for this page
pushf
cli
cld
push ebx ecx
mov eax, [slot]
shl eax, 8
mov eax, [SLOT_BASE+eax+APPDATA.process]
mov eax, [eax+PROC.dlls_list_ptr]
test eax, eax
jz .no_hdll
mov ecx, [eax+HDLL.fd]
.scan_hdll:
cmp ecx, eax
jz .no_hdll
mov ebx, [ofs]
and ebx, not 0xFFF
sub ebx, [ecx+HDLL.base]
cmp ebx, [ecx+HDLL.size]
jb .hdll_found
mov ecx, [ecx+HDLL.fd]
jmp .scan_hdll
.no_hdll:
pop ecx ebx
popf
clc
ret
.hdll_found:
; allocate page, save it in page table, map it, copy contents from base
mov eax, [ecx+HDLL.parent]
add ebx, [eax+DLLDESCR.data]
call alloc_page
test eax, eax
jz .no_hdll
or al, PG_UWR
mov [esi+edx*4], eax
stdcall map_page, edi, eax, [req_access]
push esi edi
mov esi, ebx
mov ecx, 4096/4
rep movsd
pop edi esi
pop ecx ebx
popf
stc
ret
endp
 
sys_IPC:
;input:
; ebx=1 - set ipc buffer area
; ecx=address of buffer
; edx=size of buffer
; eax=2 - send message
; ebx=PID
; ecx=address of message
; edx=size of message
 
dec ebx
jnz @f
 
mov eax, [current_slot]
pushf
cli
mov [eax+APPDATA.ipc_start], ecx ;set fields in extended information area
mov [eax+APPDATA.ipc_size], edx
 
add edx, ecx
add edx, 4095
and edx, not 4095
 
.touch:
mov eax, [ecx]
add ecx, 0x1000
cmp ecx, edx
jb .touch
 
popf
mov [esp+32], ebx ;ebx=0
ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;2
@@:
dec ebx
jnz @f
 
stdcall sys_ipc_send, ecx, edx, esi
mov [esp+32], eax
ret
@@:
or eax, -1
mov [esp+32], eax
ret
 
proc sys_ipc_send stdcall, PID:dword, msg_addr:dword, msg_size:dword
locals
dst_slot dd ?
dst_offset dd ?
buf_size dd ?
used_buf dd ?
endl
 
pushf
cli
 
mov eax, [PID]
call pid_to_slot
test eax, eax
jz .no_pid
 
mov [dst_slot], eax
shl eax, 8
mov edi, [eax+SLOT_BASE+APPDATA.ipc_start] ;is ipc area defined?
test edi, edi
jz .no_ipc_area
 
mov ebx, edi
and ebx, 0xFFF
mov [dst_offset], ebx
 
mov esi, [eax+SLOT_BASE+APPDATA.ipc_size]
mov [buf_size], esi
 
mov ecx, [ipc_tmp]
cmp esi, 0x40000-0x1000; size of [ipc_tmp] minus one page
jbe @f
push esi edi
add esi, 0x1000
stdcall alloc_kernel_space, esi
mov ecx, eax
pop edi esi
@@:
mov [used_buf], ecx
stdcall map_mem_ipc, ecx, [dst_slot], \
edi, esi, PG_SWR
 
mov edi, [dst_offset]
add edi, [used_buf]
cmp dword [edi], 0
jnz .ipc_blocked ;if dword [buffer]<>0 - ipc blocked now
 
mov edx, dword [edi+4]
lea ebx, [edx+8]
add ebx, [msg_size]
cmp ebx, [buf_size]
ja .buffer_overflow ;esi<0 - not enough memory in buffer
 
mov dword [edi+4], ebx
mov eax, [TASK_BASE]
mov eax, [eax+TASKDATA.pid] ;eax - our PID
add edi, edx
mov [edi], eax
mov ecx, [msg_size]
 
mov [edi+4], ecx
add edi, 8
mov esi, [msg_addr]
; add esi, new_app_base
cld
rep movsb
 
mov ebx, [ipc_tmp]
mov edx, ebx
shr ebx, 12
xor eax, eax
mov [page_tabs+ebx*4], eax
invlpg [edx]
 
mov ebx, [ipc_pdir]
mov edx, ebx
shr ebx, 12
xor eax, eax
mov [page_tabs+ebx*4], eax
invlpg [edx]
 
mov ebx, [ipc_ptab]
mov edx, ebx
shr ebx, 12
xor eax, eax
mov [page_tabs+ebx*4], eax
invlpg [edx]
 
mov eax, [dst_slot]
shl eax, BSF sizeof.APPDATA
or [eax+SLOT_BASE+APPDATA.occurred_events], EVENT_IPC
push 0
jmp .ret
.no_pid:
popf
mov eax, 4
ret
.no_ipc_area:
popf
xor eax, eax
inc eax
ret
.ipc_blocked:
push 2
jmp .ret
.buffer_overflow:
push 3
.ret:
mov eax, [used_buf]
cmp eax, [ipc_tmp]
je @f
stdcall free_kernel_space, eax
@@:
pop eax
popf
ret
endp
 
align 4
sysfn_meminfo:
cmp ecx, OS_BASE
jae .fail
 
mov eax, [pg_data.pages_count]
mov [ecx], eax
shl eax, 12
mov [esp+32], eax
mov eax, [pg_data.pages_free]
mov [ecx+4], eax
mov eax, [pg_data.pages_faults]
mov [ecx+8], eax
mov eax, [heap_size]
mov [ecx+12], eax
mov eax, [heap_free]
mov [ecx+16], eax
mov eax, [heap_blocks]
mov [ecx+20], eax
mov eax, [free_blocks]
mov [ecx+24], eax
ret
.fail:
or dword [esp+32], -1
ret
 
align 4
f68:
cmp ebx, 4
jbe sys_sheduler
cmp ebx, 11
jb undefined_syscall
cmp ebx, 29
ja undefined_syscall
xor eax, eax
jmp dword [f68call+ebx*4-11*4]
.11:
call init_heap
mov [esp+SYSCALL_STACK._eax], eax
ret
.12:
stdcall user_alloc, ecx
mov [esp+SYSCALL_STACK._eax], eax
ret
.13:
stdcall user_free, ecx
mov [esp+SYSCALL_STACK._eax], eax
ret
.14:
cmp ecx, OS_BASE
jae .fail
mov edi, ecx
call get_event_ex
mov [esp+SYSCALL_STACK._eax], eax
ret
.16:
test ecx, ecx
jz .fail
cmp ecx, OS_BASE
jae .fail
stdcall get_service, ecx
mov [esp+SYSCALL_STACK._eax], eax
ret
.17:
call srv_handlerEx ;ecx
mov [esp+SYSCALL_STACK._eax], eax
ret
.18:
mov eax, edx
.19:
cmp ecx, OS_BASE
jae .fail
stdcall load_library, ecx, eax
mov [esp+SYSCALL_STACK._eax], eax
ret
.20:
mov eax, edx
mov ebx, ecx
call user_realloc ;in: eax = pointer, ebx = new size
mov [esp+SYSCALL_STACK._eax], eax
ret
.21:
cmp ecx, OS_BASE
jae .fail
cmp edx, OS_BASE
jae .fail
stdcall load_pe_driver, ecx, edx
mov [esp+SYSCALL_STACK._eax], eax
ret
.22:
cmp ecx, OS_BASE
jae .fail
stdcall shmem_open, ecx, edx, esi
mov [esp+SYSCALL_STACK._edx], edx
mov [esp+SYSCALL_STACK._eax], eax
ret
.23:
cmp ecx, OS_BASE
jae .fail
stdcall shmem_close, ecx
mov [esp+SYSCALL_STACK._eax], eax
ret
.24:
mov eax, [current_slot]
xchg ecx, [eax+APPDATA.exc_handler]
xchg edx, [eax+APPDATA.except_mask]
mov [esp+SYSCALL_STACK._ebx], edx
mov [esp+SYSCALL_STACK._eax], ecx
ret
.25:
cmp ecx, 32
jae .fail
mov eax, [current_slot]
btr [eax+APPDATA.except_mask], ecx
setc byte[esp+SYSCALL_STACK._eax]
jecxz @f
bts [eax+APPDATA.except_mask], ecx
@@:
ret
.26:
stdcall user_unmap, ecx, edx, esi
mov [esp+SYSCALL_STACK._eax], eax
ret
.27:
cmp ecx, OS_BASE
jae .fail
stdcall load_file_umode, ecx
mov [esp+SYSCALL_STACK._edx], edx
mov [esp+SYSCALL_STACK._eax], eax
ret
.28:
cmp ecx, OS_BASE
jae .fail
push ecx edx
stdcall kernel_alloc, maxPathLength
mov edi, eax
pop eax esi
push edi
call getFullPath
pop ebp
test eax, eax
jz @f
stdcall load_file_umode, ebp
mov [esp+SYSCALL_STACK._edx], edx
@@:
mov [esp+SYSCALL_STACK._eax], eax
stdcall kernel_free, ebp
ret
 
.29:
stdcall user_ring, ecx
mov [esp+SYSCALL_STACK._eax], eax
ret
 
.fail:
mov [esp+SYSCALL_STACK._eax], eax
ret
 
align 4
f68call: ; keep this table closer to main code
 
dd f68.11 ; init_heap
dd f68.12 ; user_alloc
dd f68.13 ; user_free
dd f68.14 ; get_event_ex
dd f68.fail ; moved to f68.24
dd f68.16 ; get_service
dd f68.17 ; call_service
dd f68.18 ; loadLibUnicode
dd f68.19 ; load_dll
dd f68.20 ; user_realloc
dd f68.21 ; load_driver
dd f68.22 ; shmem_open
dd f68.23 ; shmem_close
dd f68.24 ; set exception handler
dd f68.25 ; unmask exception
dd f68.26 ; user_unmap
dd f68.27 ; load_file_umode
dd f68.28 ; loadFileUnicode
dd f68.29 ; user_ring
 
align 4
proc load_pe_driver stdcall, file:dword, cmdline:dword
push esi
 
stdcall load_PE, [file]
test eax, eax
jz .fail
 
mov esi, eax
push [cmdline]
push DRV_ENTRY
call eax
pop ecx
pop ecx
test eax, eax
jz .fail
 
mov [eax+SRV.entry], esi
pop esi
ret
 
.fail:
xor eax, eax
pop esi
ret
endp
 
align 4
proc create_ring_buffer stdcall, size:dword, flags:dword
locals
buf_ptr dd ?
endl
 
mov eax, [size]
test eax, eax
jz .fail
 
add eax, eax
stdcall alloc_kernel_space, eax
test eax, eax
jz .fail
 
push ebx
 
mov [buf_ptr], eax
 
mov ebx, [size]
shr ebx, 12
push ebx
 
stdcall alloc_pages, ebx
pop ecx
 
test eax, eax
jz .mm_fail
 
push edi
 
or eax, [flags]
mov edi, [buf_ptr]
mov ebx, [buf_ptr]
mov edx, ecx
shl edx, 2
shr edi, 10
@@:
mov [page_tabs+edi], eax
mov [page_tabs+edi+edx], eax
invlpg [ebx]
invlpg [ebx+0x10000]
add eax, 0x1000
add ebx, 0x1000
add edi, 4
dec ecx
jnz @B
 
mov eax, [buf_ptr]
pop edi
pop ebx
ret
.mm_fail:
stdcall free_kernel_space, [buf_ptr]
xor eax, eax
pop ebx
.fail:
ret
endp
 
 
align 4
proc print_mem
mov edi, BOOT.memmap_blocks
mov ecx, [edi-4]
test ecx, ecx
jz .done
 
@@:
mov eax, [edi]
mov edx, [edi+4]
add eax, [edi+8]
adc edx, [edi+12]
 
DEBUGF 1, "K : E820 %x%x - %x%x type %d\n", \
[edi+4], [edi],\
edx, eax, [edi+16]
add edi, 20
dec ecx
jnz @b
.done:
ret
endp
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/sys32.inc
0,0 → 1,840
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
align 4 ;3A08
build_interrupt_table:
mov edi, idts
mov esi, sys_int
mov ecx, 0x40
mov eax, (10001110b shl 24) + os_code
@@:
movsw ; low word of code-entry
stosd ; interrupt gate type : os_code selector
movsw ; high word of code-entry
loop @b
movsd ; copy low dword of trap gate for int 0x40
movsd ; copy high dword of trap gate for int 0x40
mov ecx, 23
mov eax, (10001110b shl 24) + os_code
@@:
movsw ; low word of code-entry
stosd ; interrupt gate type : os_code selector
movsw ; high word of code-entry
loop @b
lidt [esi]
ret
 
iglobal
align 4
sys_int:
; exception handlers addresses (for interrupt gate construction)
dd e0,e1,e2,e3,e4,e5,e6,except_7 ; SEE: core/fpu.inc
dd e8,e9,e10,e11,e12,e13,page_fault_exc,e15
dd e16, e17,e18, e19
times 12 dd unknown_interrupt ;int_20..int_31
 
; interrupt handlers addresses (for interrupt gate construction)
; 0x20+ are IRQ handlers
dd irq0
rept 12 irqn:1 \{dd irq_serv.irq_\#irqn\}
dd irqD
rept 18 irqn:14 \{dd irq_serv.irq_\#irqn\}
 
; int_0x40 gate trap (for directly copied)
dw i40 and 0xFFFF, os_code, 11101111b shl 8, i40 shr 16
 
rept 23 irqn:33 \{dd irq_serv.irq_\#irqn\}
 
idtreg: ; data for LIDT instruction (!!! must be immediately below sys_int data)
dw 2*($-sys_int-4)-1
dd idts ; 0x8000B100
dw 0 ; alignment
 
msg_fault_sel dd msg_exc_8,msg_exc_u,msg_exc_a,msg_exc_b
dd msg_exc_c,msg_exc_d,msg_exc_e,msg_exc_u
dd msg_exc_u,msg_exc_11
 
msg_exc_8 db "Double fault", 0
msg_exc_u db "Undefined Exception", 0
msg_exc_a db "Invalid TSS", 0
msg_exc_b db "Segment not present", 0
msg_exc_c db "Stack fault", 0
msg_exc_d db "General protection fault", 0
msg_exc_e db "Page fault", 0
msg_exc_11 db "Alignment Check", 0
 
if lang eq sp
include 'core/sys32-sp.inc'
else
msg_sel_ker db "kernel", 0
msg_sel_app db "application", 0
end if
 
endg
 
macro save_ring3_context {
pushad
}
macro restore_ring3_context {
popad
}
macro exc_wo_code [num] {
e#num :
save_ring3_context
mov bl, num
jmp exc_c
} exc_wo_code 0,1,2,3,4,5,6,15,16,19
 
macro exc_w_code [num] {
e#num :
add esp, 4
save_ring3_context
mov bl, num
jmp exc_c
} exc_w_code 8,9,10,11,12,13,17,18
 
 
uglobal
pf_err_code dd ?
endg
 
page_fault_exc: ; foolproof: selectors are clobbered ...
pop [ss:pf_err_code] ; actually, until the next #PF
save_ring3_context
mov bl, 14
 
exc_c: ; exceptions (all but 7th - #NM)
; stack frame when exception/interrupt from ring3 + pushad (i.e right here)
reg_ss equ esp+0x30
reg_esp3 equ esp+0x2C
reg_eflags equ esp+0x28
reg_cs3 equ esp+0x24
reg_eip equ esp+0x20
; this if frame from pushad
reg_eax equ esp+0x1C
reg_ecx equ esp+0x18
reg_edx equ esp+0x14
reg_ebx equ esp+0x10
reg_esp0 equ esp+0x0C
reg_ebp equ esp+0x08
reg_esi equ esp+0x04
reg_edi equ esp+0x00
 
mov ax, app_data ; exception
mov ds, ax ; load proper values
mov es, ax ; to registers
cld ; clear the direction flag
movzx ebx, bl
; redirect to V86 manager? (EFLAGS & 0x20000) != 0?
test byte[reg_eflags+2], 2
jnz v86_exc_c
cmp bl, 14 ; #PF
jne @f
call page_fault_handler ; SEE: core/memory.inc
@@:
mov esi, [current_slot]
btr [esi+APPDATA.except_mask], ebx
jnc @f
mov eax, [esi+APPDATA.exc_handler]
test eax, eax
jnz IRetToUserHook
@@:
cli
mov eax, [esi+APPDATA.debugger_slot]
test eax, eax
jnz .debug
; not debuggee => say error and terminate
call show_error_parameters
sti
mov [edx + TASKDATA.state], TSTATE_TERMINATING
call wakeup_osloop
call change_task
; If we're here, then the main OS thread has crashed before initializing IDLE thread.
; Or they both have crashed. Anyway, things are hopelessly broken.
hlt
jmp $-1
.debug:
; we are debugged process, notify debugger and suspend ourself
; eax=debugger PID
mov ecx, 1 ; debug_message code=other_exception
cmp bl, 1 ; #DB
jne .notify ; notify debugger and suspend ourself
mov ebx, dr6 ; debug_message data=DR6_image
xor edx, edx
mov dr6, edx
mov edx, dr7
mov cl, not 8
.l1:
shl dl, 2
jc @f
and bl, cl
@@:
sar cl, 1
jc .l1
mov cl, 3 ; debug_message code=debug_exception
.notify:
push ebx ; debug_message data
mov ebx, [TASK_BASE]
push [ebx+TASKDATA.pid] ; PID
push ecx ; debug_message code ((here: ecx==1/3))
mov cl, 12 ; debug_message size
call debugger_notify ;; only ONE using, inline ??? SEE: core/debug.inc
add esp, 12
mov edx, [TASK_BASE]
mov [edx+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task ; SEE: core/shed.inc
restore_ring3_context
iretd
 
IRetToUserHook:
xchg eax, [reg_eip]
sub dword[reg_esp3], 8
mov edi, [reg_esp3]
stosd
mov [edi], ebx
restore_ring3_context
; simply return control to interrupted process
unknown_interrupt:
iretd
 
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
; bl - error vector
show_error_parameters:
cmp bl, 0x06
jnz .no_ud
push ebx
mov ebx, ud_user_message
mov ebp, notifyapp
call fs_execute_from_sysdir_param
pop ebx
.no_ud:
mov edx, [TASK_BASE];not scratched below
if lang eq sp
DEBUGF 1, "K : Proceso - terminado forzado PID: %x [%s]\n", [edx+TASKDATA.pid], [current_slot]
else
DEBUGF 1, "K : Process - forced terminate PID: %x [%s]\n", [edx+TASKDATA.pid], [current_slot]
end if
cmp bl, 0x08
jb .l0
cmp bl, 0x11
jbe .l1
.l0:
mov bl, 0x09
.l1:
mov eax, [msg_fault_sel+ebx*4 - 0x08*4]
DEBUGF 1, "K : %s\n", eax
mov eax, [reg_cs3+4]
mov edi, msg_sel_app
mov ebx, [reg_esp3+4]
cmp eax, app_code
je @f
mov edi, msg_sel_ker
mov ebx, [reg_esp0+4]
@@:
DEBUGF 1, "K : EAX : %x EBX : %x ECX : %x\n", [reg_eax+4], [reg_ebx+4], [reg_ecx+4]
DEBUGF 1, "K : EDX : %x ESI : %x EDI : %x\n", [reg_edx+4], [reg_esi+4], [reg_edi+4]
DEBUGF 1, "K : EBP : %x EIP : %x ESP : %x\n", [reg_ebp+4], [reg_eip+4], ebx
DEBUGF 1, "K : Flags : %x CS : %x (%s)\n", [reg_eflags+4], eax, edi
 
DEBUGF 1, "K : Stack dump:\n"
push eax ebx ecx edx
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, "K : [ESP+00]: %x",[ebx]
add ebx, 4
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, " [ESP+04]: %x",[ebx]
add ebx, 4
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, " [ESP+08]: %x\n",[ebx]
add ebx, 4
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, "K : [ESP+12]: %x",[ebx]
add ebx, 4
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, " [ESP+16]: %x",[ebx]
add ebx, 4
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, " [ESP+20]: %x\n",[ebx]
add ebx, 4
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, "K : [ESP+24]: %x",[ebx]
add ebx, 4
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, " [ESP+28]: %x",[ebx]
add ebx, 4
call .check_ESP
test eax, eax
jnz .error_ESP
DEBUGF 1, " [ESP+32]: %x\n",[ebx]
pop edx ecx ebx eax
ret
.error_ESP:
pop edx ecx ebx eax
DEBUGF 1, "\n"
DEBUGF 1, "K : Unexpected end of the stack\n"
ret
;--------------------------------------
.check_ESP:
push ebx
shr ebx, 12
mov ecx, ebx
shr ecx, 10
mov edx, [master_tab+ecx*4]
test edx, PG_READ
jz .fail ; page table is not created
; incorrect address in the program
 
mov eax, [page_tabs+ebx*4]
test eax, 2
jz .fail ; address not reserved for use. error
 
pop ebx
xor eax, eax
ret
 
.fail:
pop ebx
xor eax, eax
dec eax
ret
;-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 
restore reg_ss
restore reg_esp3
restore reg_eflags
restore reg_cs
restore reg_eip
restore reg_eax
restore reg_ecx
restore reg_edx
restore reg_ebx
restore reg_esp0
restore reg_ebp
restore reg_esi
restore reg_edi
 
 
align 4
lock_application_table:
push eax ecx edx
mov ecx, application_table_mutex
call mutex_lock
 
mov eax, [current_slot_idx]
shl eax, BSF sizeof.TASKDATA
add eax, TASK_TABLE+TASKDATA.pid
mov eax, [eax]
 
mov [application_table_owner], eax
 
pop edx ecx eax
 
ret
 
align 4
unlock_application_table:
push eax ecx edx
 
mov [application_table_owner], 0
mov ecx, application_table_mutex
call mutex_unlock
 
pop edx ecx eax
 
ret
 
; sysfn 64 implementation
align 4
sys_resize_app_memory:
; in: eax = 64 - function number
; ebx = 1 - number of its only subfunction
; ecx = new amount of memory
; out:
; eax = 0 - success
; eax = 1 - out of memory
 
; cmp eax,1
dec ebx
jnz .no_application_mem_resize
 
mov eax, [pg_data.pages_free]
shl eax, 12
cmp eax, ecx
jae @f
 
xor eax, eax
inc eax
jmp .store_result
@@:
stdcall new_mem_resize, ecx
.store_result:
mov [esp+32], eax
.no_application_mem_resize:
ret
 
iglobal
; process_terminating db 'K : Process - terminating',13,10,0
; process_terminated db 'K : Process - done',13,10,0
msg_obj_destroy db 'K : destroy app object',13,10,0
endg
 
; param
; esi= slot
 
align 4
terminate: ; terminate application
destroy_thread:
 
.slot equ esp+4 ;locals
.process equ esp ;ptr to parent process
 
 
push esi ;save .slot
 
shl esi, 8
mov edx, [SLOT_BASE+esi+APPDATA.process]
test edx, edx
jnz @F
pop esi
shl esi, BSF sizeof.TASKDATA
mov [TASK_TABLE+esi+TASKDATA.state], TSTATE_FREE
ret
@@:
push edx ;save .process
lea edx, [SLOT_BASE+esi]
call scheduler_remove_thread
call lock_application_table
 
; if the process is in V86 mode...
mov eax, [.slot]
shl eax, 8
mov esi, [eax+SLOT_BASE+APPDATA.pl0_stack]
add esi, RING0_STACK_SIZE
cmp [eax+SLOT_BASE+APPDATA.saved_esp0], esi
jz .nov86
; ...it has page directory for V86 mode
mov esi, [eax+SLOT_BASE+APPDATA.saved_esp0]
mov ecx, [esi+4]
mov [eax+SLOT_BASE+APPDATA.process], ecx
; ...and I/O permission map for V86 mode
mov ecx, [esi+12]
mov [eax+SLOT_BASE+APPDATA.io_map], ecx
mov ecx, [esi+8]
mov [eax+SLOT_BASE+APPDATA.io_map+4], ecx
.nov86:
; destroy per-thread kernel objects
mov esi, [.slot]
shl esi, 8
add esi, SLOT_BASE+APP_OBJ_OFFSET
@@:
mov eax, [esi+APPOBJ.fd]
test eax, eax
jz @F
 
cmp eax, esi
je @F
 
push esi
call [eax+APPOBJ.destroy]
DEBUGF 1,"%s",msg_obj_destroy
pop esi
jmp @B
@@:
mov esi, [.slot]
cmp [fpu_owner], esi ; if user fpu last -> fpu user = 2
jne @F
 
mov [fpu_owner], 2
mov eax, [sizeof.APPDATA*2+SLOT_BASE+APPDATA.fpu_state]
clts
bt [cpu_caps], CAPS_SSE
jnc .no_SSE
fxrstor [eax]
jmp @F
.no_SSE:
fnclex
frstor [eax]
@@:
 
mov [KEY_COUNT], byte 0 ; empty keyboard buffer
mov [BTN_COUNT], byte 0 ; empty button buffer
 
 
; remove defined hotkeys
mov eax, hotkey_list
.loop:
cmp [eax+8], esi
jnz .cont
mov ecx, [eax]
jecxz @f
push dword [eax+12]
pop dword [ecx+12]
@@:
mov ecx, [eax+12]
push dword [eax]
pop dword [ecx]
xor ecx, ecx
mov [eax], ecx
mov [eax+4], ecx
mov [eax+8], ecx
mov [eax+12], ecx
.cont:
add eax, 16
cmp eax, hotkey_list+256*16
jb .loop
; get process PID
mov eax, esi
shl eax, BSF sizeof.TASKDATA
mov eax, [eax+TASK_TABLE+TASKDATA.pid]
; compare current lock input with process PID
cmp eax, [PID_lock_input]
jne @f
 
xor eax, eax
mov [PID_lock_input], eax
@@:
; remove hotkeys in buffer
mov eax, hotkey_buffer
.loop2:
cmp [eax], esi
jnz .cont2
and dword [eax+4], 0
and dword [eax], 0
.cont2:
add eax, 8
cmp eax, hotkey_buffer+120*8
jb .loop2
 
mov ecx, esi ; remove buttons
bnewba2:
mov edi, [BTN_ADDR]
mov eax, edi
cld
movzx ebx, word [edi]
inc bx
bnewba:
dec bx
jz bnmba
add eax, 0x10
cmp cx, [eax]
jnz bnewba
pusha
mov ecx, ebx
inc ecx
shl ecx, 4
mov ebx, eax
add eax, 0x10
call memmove
dec dword [edi]
popa
jmp bnewba2
bnmba:
 
pusha ; save window coordinates for window restoring
cld
shl esi, BSF sizeof.WDATA
add esi, window_data
mov eax, [esi+WDATA.box.left]
mov [draw_limits.left], eax
add eax, [esi+WDATA.box.width]
mov [draw_limits.right], eax
mov eax, [esi+WDATA.box.top]
mov [draw_limits.top], eax
add eax, [esi+WDATA.box.height]
mov [draw_limits.bottom], eax
 
xor eax, eax
mov edi, esi
mov ecx, sizeof.WDATA/4
rep stosd
 
lea edi, [esi-window_data+draw_data]
mov ecx, sizeof.WDATA/4
rep stosd
popa
 
; debuggee test
pushad
mov edi, esi
shl edi, BSF sizeof.TASKDATA
mov eax, [SLOT_BASE+edi*8+APPDATA.debugger_slot]
test eax, eax
jz .nodebug
movi ecx, 8
push dword [TASK_TABLE+edi+TASKDATA.pid]; PID
push 2
call debugger_notify
pop ecx
pop ecx
.nodebug:
popad
 
mov ebx, [.slot]
shl ebx, 8
push ebx
mov ebx, [SLOT_BASE+ebx+APPDATA.pl0_stack]
 
stdcall kernel_free, ebx
 
pop ebx
mov ebx, [SLOT_BASE+ebx+APPDATA.cur_dir]
stdcall kernel_free, ebx
 
mov edi, [.slot]
shl edi, 8
add edi, SLOT_BASE
 
mov eax, [edi+APPDATA.io_map]
cmp eax, [SLOT_BASE+sizeof.APPDATA+APPDATA.io_map]
je @F
call free_page
@@:
mov eax, [edi+APPDATA.io_map+4]
cmp eax, [SLOT_BASE+sizeof.APPDATA+APPDATA.io_map+4]
je @F
call free_page
@@:
lea ebx, [edi+APPDATA.list]
list_del ebx ;destroys edx, ecx
 
mov eax, 0x20202020
stosd
stosd
stosd
mov ecx, 244/4
xor eax, eax
rep stosd
 
; activate window
movzx eax, word [WIN_STACK + esi*2]
cmp eax, [thread_count]
jne .dont_activate
pushad
.check_next_window:
dec eax
cmp eax, 1
jbe .nothing_to_activate
lea esi, [WIN_POS+eax*2]
movzx edi, word [esi] ; edi = process
shl edi, BSF sizeof.TASKDATA
cmp [TASK_TABLE + edi + TASKDATA.state], TSTATE_FREE ; skip free slots
je .check_next_window
add edi, window_data
; \begin{diamond}[19.09.2006]
; skip minimized windows
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jnz .check_next_window
; \end{diamond}
call waredraw
.nothing_to_activate:
popad
.dont_activate:
 
push esi ; remove hd1 & cd & flp reservation
shl esi, BSF sizeof.TASKDATA
mov esi, [esi+TASK_TABLE+TASKDATA.pid]
cmp [cd_status], esi
jnz @f
call free_cd_channel
and [cd_status], 0
@@:
pop esi
cmp [bgrlockpid], esi
jnz @f
and [bgrlockpid], 0
and [bgrlock], 0
@@:
 
pusha ; remove all port reservations
mov edx, esi
shl edx, BSF sizeof.TASKDATA
add edx, TASK_TABLE
mov edx, [edx+TASKDATA.pid]
 
rmpr0:
 
mov esi, [RESERVED_PORTS]
 
test esi, esi
jz rmpr9
 
rmpr3:
 
mov edi, esi
shl edi, 4
add edi, RESERVED_PORTS
 
cmp edx, [edi]
je rmpr4
 
dec esi
jnz rmpr3
 
jmp rmpr9
 
rmpr4:
 
mov ecx, 256
sub ecx, esi
shl ecx, 4
 
mov esi, edi
add esi, 16
cld
rep movsb
 
dec dword [RESERVED_PORTS]
 
jmp rmpr0
 
rmpr9:
 
popa
mov edi, esi ; do not run this process slot
shl edi, BSF sizeof.TASKDATA
mov [edi+TASK_TABLE + TASKDATA.state], TSTATE_FREE
; debugger test - terminate all debuggees
mov eax, 2
mov ecx, SLOT_BASE+2*0x100+APPDATA.debugger_slot
.xd0:
cmp eax, [thread_count]
ja .xd1
cmp dword [ecx], esi
jnz @f
and dword [ecx], 0
pushad
xchg eax, ecx
mov ebx, 2
call sys_system
popad
@@:
inc eax
add ecx, 0x100
jmp .xd0
.xd1:
;release slot
 
bts [thr_slot_map], esi
 
mov ecx, [.process]
lea eax, [ecx+PROC.thr_list]
cmp eax, [eax+LHEAD.next]
jne @F
 
call destroy_process.internal
@@:
sti ; .. and life goes on
 
mov eax, [draw_limits.left]
mov ebx, [draw_limits.top]
mov ecx, [draw_limits.right]
mov edx, [draw_limits.bottom]
call calculatescreen
xor eax, eax
xor esi, esi
call redrawscreen
 
call unlock_application_table
;mov esi,process_terminated
;call sys_msg_board_str
add esp, 8
ret
restore .slot
restore .process
 
; Three following procedures are used to guarantee that
; some part of kernel code will not be terminated from outside
; while it is running.
; Note: they do not protect a thread from terminating due to errors inside
; the thread; accessing a nonexisting memory would still terminate it.
 
; First two procedures must be used in pair by thread-to-be-protected
; to signal the beginning and the end of an important part.
; It is OK to have nested areas.
 
; The last procedure must be used by outside wanna-be-terminators;
; if it is safe to terminate the given thread immediately, it returns eax=1;
; otherwise, it returns eax=0 and notifies the target thread that it should
; terminate itself when leaving a critical area (the last critical area if
; they are nested).
 
; Implementation. Those procedures use one dword in APPDATA for the thread,
; APPDATA.terminate_protection.
; * The upper bit is 1 during normal operations and 0 when terminate is requested.
; * Other bits form a number = depth of critical regions,
; plus 1 if the upper bit is 1.
; * When this dword goes to zero, the thread should be destructed,
; and the procedure in which it happened becomes responsible for destruction.
 
; Enter critical area. Called by thread which wants to be protected.
proc protect_from_terminate
mov edx, [current_slot]
; Atomically increment depth of critical areas and get the old value.
mov eax, 1
lock xadd [edx+APPDATA.terminate_protection], eax
; If the old value was zero, somebody has started to terminate us,
; so we are destructing and cannot do anything protected.
; Otherwise, return to the caller.
test eax, eax
jz @f
ret
@@:
; Wait for somebody to finish us.
call change_task
jmp @b
endp
 
; Leave critical area. Called by thread which wants to be protected.
proc unprotect_from_terminate
mov edx, [current_slot]
; Atomically decrement depth of critical areas.
lock dec [edx+APPDATA.terminate_protection]
; If the result of decrement is zero, somebody has requested termination,
; but at that moment we were inside a critical area; terminate now.
jz sys_end
; Otherwise, return to the caller.
ret
endp
 
; Request termination of thread identified by edx = SLOT_BASE + slot*sizeof.APPDATA.
; Called by anyone.
proc request_terminate
xor eax, eax ; set return value
; Atomically clear the upper bit. If it was already zero, then
; somebody has requested termination before us, so just exit.
lock btr [edx+APPDATA.terminate_protection], 31
jnc .unsafe
; Atomically decrement depth of critical areas.
lock dec [edx+APPDATA.terminate_protection]
; If the result of decrement is nonzero, the target thread is inside a
; critical area; leave termination to leaving that area.
jnz .unsafe
; Otherwise, it is safe to kill the target now and the caller is responsible
; for this. Return eax=1.
inc eax
.unsafe:
ret
endp
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/sched.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/sync.inc
0,0 → 1,355
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Synhronization for MenuetOS. ;;
;; Author: Halyavin Andrey, halyavin@land.ru ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
 
RWSEM_WAITING_FOR_WRITE = 0
RWSEM_WAITING_FOR_READ = 1
 
;void __fastcall mutex_init(struct mutex *lock)
 
align 4
mutex_init:
mov [ecx+MUTEX.wait_list.next], ecx
mov [ecx+MUTEX.wait_list.prev], ecx
mov [ecx+MUTEX.count], 1
ret
 
;void __fastcall mutex_lock(struct mutex *lock)
 
align 4
mutex_lock:
 
dec [ecx+MUTEX.count]
jns .done
 
pushfd
cli
 
sub esp, sizeof.MUTEX_WAITER
 
list_add_tail esp, ecx ;esp= new waiter, ecx= list head
 
mov edx, [TASK_BASE]
mov [esp+MUTEX_WAITER.task], edx
 
.forever:
 
mov eax, -1
xchg eax, [ecx+MUTEX.count]
dec eax
jz @F
 
mov [edx+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task
jmp .forever
@@:
mov eax, ecx
list_del esp
 
cmp [eax+MUTEX.wait_list.next], eax
jne @F
 
mov [eax+MUTEX.count], 0
@@:
add esp, sizeof.MUTEX_WAITER
 
popfd
.done:
ret
 
;void __fastcall mutex_unlock(struct mutex *lock)
 
align 4
mutex_unlock:
 
pushfd
cli
 
mov eax, [ecx+MUTEX.wait_list.next]
cmp eax, ecx
mov [ecx+MUTEX.count], 1
je @F
 
mov eax, [eax+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], TSTATE_RUNNING
@@:
popfd
ret
 
 
;void __fastcall init_rwsem(struct rw_semaphore *sem)
 
align 4
init_rwsem:
mov [ecx+RWSEM.wait_list.next], ecx
mov [ecx+RWSEM.wait_list.prev], ecx
mov [ecx+RWSEM.count], 0
ret
 
;void __fastcall down_read(struct rw_semaphore *sem)
 
align 4
down_read:
pushfd
cli
 
mov eax, [ecx+RWSEM.count]
test eax, eax
js @F
 
cmp ecx, [ecx+RWSEM.wait_list.next]
je .ok
@@:
sub esp, sizeof.MUTEX_WAITER
 
mov eax, [TASK_BASE]
mov [esp+MUTEX_WAITER.task], eax
mov [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
mov [eax+TASKDATA.state], TSTATE_RUN_SUSPENDED
 
list_add_tail esp, ecx ;esp= new waiter, ecx= list head
 
call change_task
 
add esp, sizeof.MUTEX_WAITER
popfd
ret
.ok:
inc eax
mov [ecx+RWSEM.count], eax
 
popfd
ret
 
;void __fastcall down_write(struct rw_semaphore *sem)
 
align 4
down_write:
pushfd
cli
sub esp, sizeof.MUTEX_WAITER
 
mov edx, [TASK_BASE]
mov [esp+MUTEX_WAITER.task], edx
mov [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
mov [edx+TASKDATA.state], TSTATE_RUN_SUSPENDED
 
list_add_tail esp, ecx ;esp= new waiter, ecx= list head
 
xor eax, eax
not eax
 
.forever:
test eax, [ecx+RWSEM.count]
jz @F
 
mov [edx+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task
jmp .forever
@@:
mov [ecx+RWSEM.count], eax
list_del esp
 
add esp, sizeof.MUTEX_WAITER
popfd
ret
 
;void __fastcall up_read(struct rw_semaphore *sem)
 
align 4
up_read:
pushfd
cli
 
dec [ecx+RWSEM.count]
jnz @F
 
mov eax, [ecx+RWSEM.wait_list.next]
cmp eax, ecx
je @F
 
mov eax, [eax+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], TSTATE_RUNNING
@@:
popfd
ret
 
;void __fastcall up_write(struct rw_semaphore *sem)
 
align 4
up_write:
 
pushfd
cli
 
mov eax, [ecx+RWSEM.wait_list.next]
mov [ecx+RWSEM.count], 0
 
cmp ecx, eax
je .done
 
mov edx, [eax+MUTEX_WAITER.type]
test edx, edx
jnz .wake
 
mov eax, [eax+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], TSTATE_RUNNING
.done:
popfd
ret
 
.wake:
push ebx
push esi
push edi
 
xor esi, esi
mov edi, ecx
 
.wake_list:
 
mov ebx, [eax+MUTEX_WAITER.list.next]
list_del eax
mov edx, [eax+MUTEX_WAITER.task]
mov [edx+TASKDATA.state], TSTATE_RUNNING
inc esi
cmp edi, ebx
je .wake_done
 
mov ecx, [ebx+MUTEX_WAITER.type]
test ecx, ecx
jz .wake_done
 
mov eax, ebx
jmp .wake_list
 
.wake_done:
add [edi+RWSEM.count], esi
 
pop edi
pop esi
pop ebx
popfd
ret
 
 
purge RWSEM_WAITING_FOR_WRITE
purge RWSEM_WAITING_FOR_READ
 
 
if ~defined sync_inc
sync_inc_fix:
sync_inc fix sync_inc_fix
 
;simplest mutex.
macro SimpleMutex name
{
; iglobal
name dd 0
name#.type = 1
; endg
}
macro WaitSimpleMutex name
{
local start_wait,ok
start_wait=$
cli
cmp [name], dword 0
jz ok
sti
call change_task
jmp start_wait
ok=$
push eax
mov eax, dword [TASK_BASE+second_base_address]
mov eax, [eax+TASKDATA.pid]
mov [name], eax
pop eax
sti
}
macro ReleaseSimpleMutex name
{
mov [name], dword 0
}
macro TryWaitSimpleMutex name ;result in eax and in flags
{
local ok,try_end
cmp [name], dword 0
jz ok
xor eax, eax
jmp try_end
ok=$
xor eax, eax
inc eax
try_end=$
}
macro SimpleCriticalSection name
{
; iglobal
name dd 0
dd 0
name#.type=2
; endg
}
macro WaitSimpleCriticalSection name
{
local start_wait,first_wait,inc_counter,end_wait
push eax
mov eax, [TASK_BASE+second_base_address]
mov eax, [eax+TASKDATA.pid]
start_wait=$
cli
cmp [name], dword 0
jz first_wait
cmp [name], eax
jz inc_counter
sti
call change_task
jmp start_wait
first_wait=$
mov [name], eax
mov [name+4], dword 1
jmp end_wait
inc_counter=$
inc dword [name+4]
end_wait=$
sti
pop eax
}
macro ReleaseSimpleCriticalSection name
{
local release_end
dec dword [name+4]
jnz release_end
mov [name], dword 0
release_end=$
}
macro TryWaitSimpleCriticalSection name ;result in eax and in flags
{
local ok,try_end
mov eax, [CURRENT_TASK+second_base_address]
mov eax, [eax+TASKDATA.pid]
cmp [name], eax
jz ok
cmp [name], 0
jz ok
xor eax, eax
jmp try_end
ok=$
xor eax, eax
inc eax
try_end=$
}
_cli equ call MEM_HeapLock
_sti equ call MEM_HeapUnLock
end if
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/fpu.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/heap.inc
0,0 → 1,1589
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
struct MEM_BLOCK
list LHEAD
next_block dd ? ;+8
prev_block dd ? ;+4
base dd ? ;+16
size dd ? ;+20
flags dd ? ;+24
handle dd ? ;+28
ends
 
MEM_BLOCK_RESERVED = 0x02 ; Will be allocated on first access (lazy allocation)
MEM_BLOCK_FREE = 0x04
MEM_BLOCK_USED = 0x08
MEM_BLOCK_DONT_FREE = 0x10
 
macro calc_index op
{ shr op, 12
dec op
cmp op, 63
jna @f
mov op, 63
@@:
}
 
align 4
md:
.add_to_used:
mov eax, [esi + MEM_BLOCK.base]
mov ebx, [esi + MEM_BLOCK.base]
shr ebx, 6
add eax, ebx
shr ebx, 6
add eax, ebx
shr eax, 12
and eax, 63
inc [mem_hash_cnt + eax*4]
 
lea ecx, [mem_used_list + eax*8]
list_add esi, ecx
mov [esi + MEM_BLOCK.flags], MEM_BLOCK_USED
mov eax, [esi + MEM_BLOCK.size]
sub [heap_free], eax
ret
align 4
.find_used:
mov ecx, eax
mov ebx, eax
shr ebx, 6
add ecx, ebx
shr ebx, 6
add ecx, ebx
shr ecx, 12
and ecx, 63
 
lea ebx, [mem_used_list + ecx*8]
mov esi, ebx
.next:
mov esi, [esi + MEM_BLOCK.list.next]
cmp esi, ebx
je .fail
 
cmp eax, [esi + MEM_BLOCK.base]
jne .next
 
ret
.fail:
xor esi, esi
ret
 
align 4
.del_from_used:
call .find_used
test esi, esi
jz .done
 
cmp [esi + MEM_BLOCK.flags], MEM_BLOCK_USED
jne .fatal
 
dec [mem_hash_cnt + ecx*4]
list_del esi
.done:
ret
.fatal: ;FIXME panic here
xor esi, esi
ret
 
;Initial heap state
;
; + heap_size terminator MEM_BLOCK_USED
; + 4096*MEM_BLOCK.sizeof free space MEM_BLOCK_FREE
;HEAP_BASE heap_descriptors MEM_BLOCK_USED
;
 
align 4
proc init_kernel_heap
 
mov ecx, 64
mov edi, mem_block_list
@@:
mov eax, edi
stosd
stosd
loop @B
 
mov ecx, 64
mov edi, mem_used_list
@@:
mov eax, edi
stosd
stosd
loop @B
 
stdcall alloc_pages, dword 32
 
or eax, PG_SWR
mov ebx, HEAP_BASE
mov ecx, 32
call commit_pages
 
mov edi, HEAP_BASE ;descriptors
mov ebx, HEAP_BASE + sizeof.MEM_BLOCK ;free space
mov ecx, HEAP_BASE + sizeof.MEM_BLOCK*2 ;terminator
 
xor eax, eax
mov [edi + MEM_BLOCK.next_block], ebx
mov [edi + MEM_BLOCK.prev_block], eax
mov [edi + MEM_BLOCK.list.next], eax
mov [edi + MEM_BLOCK.list.prev], eax
mov [edi + MEM_BLOCK.base], HEAP_BASE
mov [edi + MEM_BLOCK.size], 4096*sizeof.MEM_BLOCK
mov [edi + MEM_BLOCK.flags], MEM_BLOCK_USED
 
mov [ecx + MEM_BLOCK.next_block], eax
mov [ecx + MEM_BLOCK.prev_block], ebx
mov [ecx + MEM_BLOCK.list.next], eax
mov [ecx + MEM_BLOCK.list.prev], eax
mov [ecx + MEM_BLOCK.base], eax
mov [ecx + MEM_BLOCK.size], eax
mov [ecx + MEM_BLOCK.flags], MEM_BLOCK_USED
 
mov [ebx + MEM_BLOCK.next_block], ecx
mov [ebx + MEM_BLOCK.prev_block], edi
mov [ebx + MEM_BLOCK.base], HEAP_BASE + 4096*sizeof.MEM_BLOCK
 
mov ecx, [pg_data.kernel_pages]
shl ecx, 12
sub ecx, HEAP_BASE-OS_BASE + 4096*sizeof.MEM_BLOCK
mov [heap_size], ecx
mov [heap_free], ecx
mov [ebx + MEM_BLOCK.size], ecx
mov [ebx + MEM_BLOCK.flags], MEM_BLOCK_FREE
 
mov [mem_block_mask], eax
mov [mem_block_mask + 4], 0x80000000
 
mov ecx, mem_block_list + 63*8
list_add ebx, ecx
 
mov ecx, 4096-3-1
mov eax, HEAP_BASE + sizeof.MEM_BLOCK*4
 
mov [next_memblock], HEAP_BASE + sizeof.MEM_BLOCK *3
@@:
mov [eax-sizeof.MEM_BLOCK], eax
add eax, sizeof.MEM_BLOCK
loop @B
 
mov dword[eax-sizeof.MEM_BLOCK], 0
 
mov ecx, heap_mutex
call mutex_init
mov [heap_blocks], 4094
mov [free_blocks], 4093
ret
endp
 
; param
; eax= required size
;
; retval
; edi= memory block descriptor
; ebx= descriptor index
 
align 4
get_small_block:
mov ecx, eax
shr ecx, 12
dec ecx
cmp ecx, 63
jle .get_index
mov ecx, 63
.get_index:
lea esi, [mem_block_mask]
xor ebx, ebx
or edx, -1
 
cmp ecx, 32
jb .bit_test
 
sub ecx, 32
add ebx, 32
add esi, 4
.bit_test:
shl edx, cl
and edx, [esi]
.find:
bsf edi, edx
jz .high_mask
add ebx, edi
lea ecx, [mem_block_list + ebx*8]
mov edi, ecx
.next:
mov edi, [edi + MEM_BLOCK.list.next]
cmp edi, ecx
je .err
cmp eax, [edi + MEM_BLOCK.size]
ja .next
ret
.err:
xor edi, edi
ret
 
.high_mask:
add esi, 4
cmp esi, mem_block_mask + 8
jae .err
add ebx, 32
mov edx, [esi]
jmp .find
 
 
align 4
free_mem_block:
 
mov ebx, [next_memblock]
mov [eax], ebx
mov [next_memblock], eax
 
xor ebx, ebx
mov dword[eax + 4], ebx
mov dword[eax + 8], ebx
mov dword[eax + 12], ebx
mov dword[eax + 16], ebx
; mov dword[eax + 20], 0 ;don't clear block size
mov dword[eax + 24], ebx
mov dword[eax + 28], ebx
 
inc [free_blocks]
 
ret
 
align 4
proc alloc_kernel_space stdcall, size:dword
local block_ind:DWORD
 
push ebx
push esi
push edi
 
mov eax, [size]
add eax, 4095
and eax, not 4095
mov [size], eax
 
cmp eax, [heap_free]
ja .error
 
spin_lock_irqsave heap_mutex
 
mov eax, [size]
 
call get_small_block ; eax
test edi, edi
jz .error_unlock
 
cmp [edi + MEM_BLOCK.flags], MEM_BLOCK_FREE
jne .error_unlock
 
mov [block_ind], ebx ;index of allocated block
 
mov eax, [edi + MEM_BLOCK.size]
cmp eax, [size]
je .m_eq_size
 
mov esi, [next_memblock] ;new memory block
test esi, esi
jz .error_unlock
 
dec [free_blocks]
mov eax, [esi]
mov [next_memblock], eax
 
mov [esi + MEM_BLOCK.next_block], edi
mov eax, [edi + MEM_BLOCK.prev_block]
mov [esi + MEM_BLOCK.prev_block], eax
mov [edi + MEM_BLOCK.prev_block], esi
mov [esi + MEM_BLOCK.list.next], 0
mov [esi + MEM_BLOCK.list.prev], 0
mov [eax + MEM_BLOCK.next_block], esi
 
mov ebx, [edi + MEM_BLOCK.base]
mov [esi + MEM_BLOCK.base], ebx
mov edx, [size]
mov [esi + MEM_BLOCK.size], edx
add [edi + MEM_BLOCK.base], edx
sub [edi + MEM_BLOCK.size], edx
 
mov eax, [edi + MEM_BLOCK.size]
calc_index eax
cmp eax, [block_ind]
je .add_used
 
list_del edi
 
mov ecx, [block_ind]
lea edx, [mem_block_list + ecx*8]
cmp edx, [edx]
jnz @f
btr [mem_block_mask], ecx
@@:
bts [mem_block_mask], eax
lea edx, [mem_block_list + eax*8] ;edx= list head
list_add edi, edx
.add_used:
 
call md.add_to_used
 
spin_unlock_irqrestore heap_mutex
mov eax, [esi + MEM_BLOCK.base]
pop edi
pop esi
pop ebx
ret
 
.m_eq_size:
list_del edi
lea edx, [mem_block_list + ebx*8]
cmp edx, [edx]
jnz @f
btr [mem_block_mask], ebx
@@:
mov esi, edi
jmp .add_used
 
.error_unlock:
spin_unlock_irqrestore heap_mutex
.error:
xor eax, eax
pop edi
pop esi
pop ebx
ret
endp
 
align 4
proc free_kernel_space stdcall uses ebx ecx edx esi edi, base:dword
 
spin_lock_irqsave heap_mutex
 
mov eax, [base]
 
call md.del_from_used
test esi, esi
jz .fail
 
mov eax, [esi + MEM_BLOCK.size]
add [heap_free], eax
 
mov edi, [esi + MEM_BLOCK.next_block]
cmp [edi + MEM_BLOCK.flags], MEM_BLOCK_FREE
jne .prev
 
list_del edi
 
mov edx, [edi + MEM_BLOCK.next_block]
mov [esi + MEM_BLOCK.next_block], edx
mov [edx + MEM_BLOCK.prev_block], esi
mov ecx, [edi + MEM_BLOCK.size]
add [esi + MEM_BLOCK.size], ecx
 
calc_index ecx
 
lea edx, [mem_block_list + ecx*8]
cmp edx, [edx]
jne @F
btr [mem_block_mask], ecx
@@:
mov eax, edi
call free_mem_block
.prev:
mov edi, [esi + MEM_BLOCK.prev_block]
cmp [edi + MEM_BLOCK.flags], MEM_BLOCK_FREE
jne .insert
 
mov edx, [esi + MEM_BLOCK.next_block]
mov [edi + MEM_BLOCK.next_block], edx
mov [edx + MEM_BLOCK.prev_block], edi
 
mov eax, esi
call free_mem_block
 
mov ecx, [edi + MEM_BLOCK.size]
mov eax, [esi + MEM_BLOCK.size]
add eax, ecx
mov [edi + MEM_BLOCK.size], eax
 
calc_index eax ;new index
calc_index ecx ;old index
cmp eax, ecx
je .m_eq
 
push ecx
list_del edi
pop ecx
 
lea edx, [mem_block_list + ecx*8]
cmp edx, [edx]
jne .add_block
btr [mem_block_mask], ecx
 
.add_block:
bts [mem_block_mask], eax
lea edx, [mem_block_list + eax*8]
list_add edi, edx
.m_eq:
spin_unlock_irqrestore heap_mutex
xor eax, eax
not eax
ret
.insert:
mov [esi + MEM_BLOCK.flags], MEM_BLOCK_FREE
mov eax, [esi + MEM_BLOCK.size]
calc_index eax
mov edi, esi
jmp .add_block
 
.fail:
spin_unlock_irqrestore heap_mutex
xor eax, eax
ret
endp
 
align 4
proc kernel_alloc stdcall, size:dword
locals
lin_addr dd ?
pages_count dd ?
endl
 
push ebx
push edi
 
mov eax, [size]
add eax, 4095
and eax, not 4095;
mov [size], eax
and eax, eax
jz .err
mov ebx, eax
shr ebx, 12
mov [pages_count], ebx
 
stdcall alloc_kernel_space, eax
mov [lin_addr], eax
mov ebx, [pages_count]
test eax, eax
jz .err
 
mov edx, eax
 
shr ebx, 3
jz .tail
 
shl ebx, 3
stdcall alloc_pages, ebx
test eax, eax
jz .err
 
mov ecx, ebx
or eax, PG_GLOBAL + PG_SWR
mov ebx, [lin_addr]
call commit_pages
 
mov edx, ebx ; this dirty hack
.tail:
mov ebx, [pages_count]
and ebx, 7
jz .end
@@:
call alloc_page
test eax, eax
jz .err
 
stdcall map_page, edx, eax, dword (PG_GLOBAL + PG_SWR)
add edx, 0x1000
dec ebx
jnz @B
.end:
mov eax, [lin_addr]
pop edi
pop ebx
ret
.err:
xor eax, eax
pop edi
pop ebx
ret
endp
 
align 4
proc kernel_free stdcall, base:dword
 
push ebx esi
 
spin_lock_irqsave heap_mutex
 
mov eax, [base]
call md.find_used
 
cmp [esi + MEM_BLOCK.flags], MEM_BLOCK_USED
jne .fail
 
spin_unlock_irqrestore heap_mutex
 
mov eax, [esi + MEM_BLOCK.base]
mov ecx, [esi + MEM_BLOCK.size]
shr ecx, 12
call release_pages ;eax, ecx
stdcall free_kernel_space, [base]
pop esi ebx
ret
.fail:
spin_unlock_irqrestore heap_mutex
xor eax, eax
pop esi ebx
ret
endp
 
;;;;;;;;;;;;;; USER HEAP ;;;;;;;;;;;;;;;;;
 
HEAP_TOP = 0x80000000
 
align 4
proc init_heap
 
mov ebx, [current_process]
mov eax, [ebx + PROC.heap_top]
test eax, eax
jz @F
sub eax, [ebx + PROC.heap_base]
sub eax, PAGE_SIZE
ret
@@:
lea ecx, [ebx + PROC.heap_lock]
call mutex_init
 
mov esi, [ebx + PROC.mem_used]
add esi, 4095
and esi, not 4095
mov [ebx + PROC.mem_used], esi
mov eax, HEAP_TOP
mov [ebx + PROC.heap_base], esi
mov [ebx + PROC.heap_top], eax
 
sub eax, esi
shr esi, 10
mov ecx, eax
sub eax, PAGE_SIZE
or ecx, MEM_BLOCK_FREE
mov [page_tabs + esi], ecx
ret
endp
 
align 4
proc user_alloc stdcall, alloc_size:dword
 
push ebx esi edi
 
mov ebx, [current_process]
lea ecx, [ebx + PROC.heap_lock]
call mutex_lock
 
mov ecx, [alloc_size]
add ecx, (4095 + PAGE_SIZE)
and ecx, not 4095
mov esi, [ebx + PROC.heap_base]
mov edi, [ebx + PROC.heap_top]
.scan:
cmp esi, edi
jae .m_exit
 
mov ebx, esi
shr ebx, 12
mov eax, [page_tabs + ebx*4]
test al, MEM_BLOCK_FREE
jz .test_used
and eax, 0xFFFFF000
cmp eax, ecx ;alloc_size
jb .m_next
jz @f
 
lea edx, [esi + ecx]
sub eax, ecx
or al, MEM_BLOCK_FREE
shr edx, 12
mov [page_tabs + edx*4], eax
@@:
or ecx, MEM_BLOCK_USED
mov [page_tabs + ebx*4], ecx
shr ecx, 12
inc ebx
dec ecx
jz .no
@@:
mov dword [page_tabs + ebx*4], MEM_BLOCK_RESERVED
inc ebx
dec ecx
jnz @B
.no:
 
mov edx, [current_process]
mov ebx, [alloc_size]
add ebx, 0xFFF
and ebx, not 0xFFF
add [edx + PROC.mem_used], ebx
 
lea ecx, [edx + PROC.heap_lock]
call mutex_unlock
 
lea eax, [esi + 4096]
 
pop edi
pop esi
pop ebx
ret
.test_used:
test al, MEM_BLOCK_USED
jz .m_exit
 
and eax, 0xFFFFF000 ; not PAGESIZE
.m_next:
add esi, eax
jmp .scan
.m_exit:
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_unlock
 
xor eax, eax
pop edi
pop esi
pop ebx
ret
endp
 
align 4
proc user_alloc_at stdcall, address:dword, alloc_size:dword
 
push ebx
push esi
push edi
 
mov ebx, [current_process]
lea ecx, [ebx + PROC.heap_lock]
call mutex_lock
 
mov edx, [address]
and edx, not 0xFFF
mov [address], edx
sub edx, 0x1000
jb .error
mov esi, [ebx + PROC.heap_base]
mov edi, [ebx + PROC.heap_top]
cmp edx, esi
jb .error
.scan:
cmp esi, edi
jae .error
mov ebx, esi
shr ebx, 12
mov eax, [page_tabs + ebx*4]
mov ecx, eax
and ecx, 0xFFFFF000
add ecx, esi
cmp edx, ecx
jb .found
mov esi, ecx
jmp .scan
.error:
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_unlock
 
xor eax, eax
pop edi
pop esi
pop ebx
ret
.found:
test al, MEM_BLOCK_FREE
jz .error
mov eax, ecx
sub eax, edx
sub eax, 0x1000
cmp eax, [alloc_size]
jb .error
 
; Here we have 1 big free block which includes requested area.
; In general, 3 other blocks must be created instead:
; free at [esi, edx);
; busy at [edx, edx + 0x1000 + ALIGN_UP(alloc_size,0x1000));
; free at [edx + 0x1000 + ALIGN_UP(alloc_size,0x1000), ecx)
; First or third block (or both) may be absent.
mov eax, edx
sub eax, esi
jz .nofirst
or al, MEM_BLOCK_FREE
mov [page_tabs + ebx*4], eax
.nofirst:
mov eax, [alloc_size]
add eax, 0x1FFF
and eax, not 0xFFF
mov ebx, edx
add edx, eax
shr ebx, 12
or al, MEM_BLOCK_USED
mov [page_tabs + ebx*4], eax
shr eax, 12
dec eax
jz .second_nofill
inc ebx
.fill:
mov dword [page_tabs + ebx*4], MEM_BLOCK_RESERVED
inc ebx
dec eax
jnz .fill
 
.second_nofill:
sub ecx, edx
jz .nothird
or cl, MEM_BLOCK_FREE
mov [page_tabs + ebx*4], ecx
 
.nothird:
mov edx, [current_process]
mov ebx, [alloc_size]
add ebx, 0xFFF
and ebx, not 0xFFF
add [edx + PROC.mem_used], ebx
 
lea ecx, [edx + PROC.heap_lock]
call mutex_unlock
 
mov eax, [address]
 
pop edi
pop esi
pop ebx
ret
endp
 
align 4
proc user_free stdcall, base:dword
 
push esi
 
mov esi, [base]
test esi, esi
jz .fail
 
push ebx
 
mov ebx, [current_process]
lea ecx, [ebx + PROC.heap_lock]
call mutex_lock
 
xor ebx, ebx
shr esi, 12
mov eax, [page_tabs + (esi-1)*4]
test al, MEM_BLOCK_USED
jz .cantfree
test al, MEM_BLOCK_DONT_FREE
jnz .cantfree
 
and eax, not 4095
mov ecx, eax
or al, MEM_BLOCK_FREE
mov [page_tabs + (esi-1)*4], eax
sub ecx, 4096
mov ebx, ecx
shr ecx, 12
jz .released
.release:
xor eax, eax
xchg eax, [page_tabs + esi*4]
test al, 1
jz @F
test eax, PG_SHARED
jnz @F
call free_page
mov eax, esi
shl eax, 12
invlpg [eax]
@@:
inc esi
dec ecx
jnz .release
 
.released:
push edi
 
mov edx, [current_process]
lea ecx, [edx + PROC.heap_lock]
mov esi, dword [edx + PROC.heap_base]
mov edi, dword [edx + PROC.heap_top]
sub ebx, [edx + PROC.mem_used]
neg ebx
mov [edx + PROC.mem_used], ebx
call user_normalize
pop edi
.exit:
call mutex_unlock
 
xor eax, eax
inc eax
pop ebx
pop esi
ret
 
.cantfree:
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
jmp .exit
.fail:
xor eax, eax
pop esi
ret
endp
 
 
align 4
proc user_unmap stdcall, base:dword, offset:dword, size:dword
 
push ebx
 
mov ebx, [base] ; must be valid pointer
test ebx, ebx
jz .error
 
mov edx, [offset] ; check offset
add edx, ebx ; must be below 2Gb app limit
js .error
 
shr ebx, 12 ; chek block attributes
lea ebx, [page_tabs + ebx*4]
mov eax, [ebx-4] ; block attributes
test al, MEM_BLOCK_USED
jz .error
test al, MEM_BLOCK_DONT_FREE
jnz .error
 
shr edx, 12
lea edx, [page_tabs + edx*4] ; unmap offset
 
mov ecx, [size]
add ecx, 4095
shr ecx, 12 ; unmap size in pages
 
shr eax, 12 ; block size + 1 page
lea ebx, [ebx + eax*4-4] ; block end ptr
lea eax, [edx + ecx*4] ; unmap end ptr
 
cmp eax, ebx ; check for overflow
ja .error
 
mov ebx, [offset]
and ebx, not 4095 ; is it required ?
add ebx, [base]
 
.unmap:
mov eax, [edx] ; get page addres
test al, 1 ; page mapped ?
jz @F
test eax, PG_SHARED ; page shared ?
jnz @F
mov dword[edx], MEM_BLOCK_RESERVED
; mark page as reserved
invlpg [ebx] ; when we start using
call free_page ; empty c-o-w page instead this ?
@@:
add ebx, 4096 ; PAGESIZE?
add edx, 4
dec ecx
jnz .unmap
 
pop ebx
or al, 1 ; return non zero on success
ret
.error:
pop ebx
xor eax, eax ; something wrong
ret
endp
 
align 4
user_normalize:
; in: esi=heap_base, edi=heap_top
; out: eax=0 <=> OK
; destroys: ebx,edx,esi,edi
shr esi, 12
shr edi, 12
@@:
mov eax, [page_tabs + esi*4]
test al, MEM_BLOCK_USED
jz .test_free
shr eax, 12
add esi, eax
jmp @B
.test_free:
test al, MEM_BLOCK_FREE
jz .err
mov edx, eax
shr edx, 12
add edx, esi
cmp edx, edi
jae .exit
 
mov ebx, [page_tabs + edx*4]
test bl, MEM_BLOCK_USED
jz .next_free
 
shr ebx, 12
add edx, ebx
mov esi, edx
jmp @B
.next_free:
test bl, MEM_BLOCK_FREE
jz .err
and dword[page_tabs + edx*4], 0
add eax, ebx
and eax, not 4095 ; not (PAGESIZE - 1) ?
or eax, MEM_BLOCK_FREE
mov [page_tabs + esi*4], eax
jmp @B
.exit:
xor eax, eax
inc eax
ret
.err:
xor eax, eax
ret
 
user_realloc:
; in: eax = pointer, ebx = new size
; out: eax = new pointer or NULL
test eax, eax
jnz @f
; realloc(NULL,sz) - same as malloc(sz)
push ebx
call user_alloc
ret
@@:
push ecx edx
 
push eax
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_lock
pop eax
 
lea ecx, [eax - 0x1000]
shr ecx, 12
mov edx, [page_tabs + ecx*4]
test dl, MEM_BLOCK_USED
jnz @f
; attempt to realloc invalid pointer
.ret0:
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_unlock
 
pop edx ecx
xor eax, eax
ret
@@:
test dl, MEM_BLOCK_DONT_FREE
jnz .ret0
add ebx, 0x1FFF
shr edx, 12
shr ebx, 12
; edx = allocated size, ebx = new size
add edx, ecx
add ebx, ecx
cmp edx, ebx
jb .realloc_add
; release part of allocated memory
.loop:
cmp edx, ebx
jz .release_done
dec edx
xor eax, eax
xchg eax, [page_tabs + edx*4]
test al, 1
jz .loop
call free_page
mov eax, edx
shl eax, 12
invlpg [eax]
jmp .loop
.release_done:
sub ebx, ecx
cmp ebx, 1
jnz .nofreeall
mov eax, [page_tabs + ecx*4]
and eax, not 0xFFF
mov edx, [current_process]
mov ebx, [edx + PROC.mem_used]
sub ebx, eax
add ebx, 0x1000
or al, MEM_BLOCK_FREE
mov [page_tabs + ecx*4], eax
push esi edi
mov esi, [edx + PROC.heap_base]
mov edi, [edx + PROC.heap_top]
mov [edx + PROC.mem_used], ebx
call user_normalize
pop edi esi
jmp .ret0 ; all freed
.nofreeall:
sub edx, ecx
shl ebx, 12
or ebx, MEM_BLOCK_USED
xchg [page_tabs + ecx*4], ebx
shr ebx, 12
sub ebx, edx
push ebx ecx edx
mov edx, [current_process]
shl ebx, 12
sub ebx, [edx + PROC.mem_used]
neg ebx
mov [edx + PROC.mem_used], ebx
pop edx ecx ebx
lea eax, [ecx + 1]
shl eax, 12
push eax
add ecx, edx
lea edx, [ecx + ebx]
shl ebx, 12
jz .ret
push esi
mov esi, [current_process]
mov esi, [esi + PROC.heap_top]
shr esi, 12
@@:
cmp edx, esi
jae .merge_done
mov eax, [page_tabs + edx*4]
test al, MEM_BLOCK_USED
jnz .merge_done
and dword [page_tabs + edx*4], 0
shr eax, 12
add edx, eax
shl eax, 12
add ebx, eax
jmp @b
.merge_done:
pop esi
or ebx, MEM_BLOCK_FREE
mov [page_tabs + ecx*4], ebx
.ret:
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_unlock
pop eax edx ecx
ret
 
.realloc_add:
; get some additional memory
mov eax, [current_process]
mov eax, [eax + PROC.heap_top]
shr eax, 12
cmp edx, eax
jae .cant_inplace
mov eax, [page_tabs + edx*4]
test al, MEM_BLOCK_FREE
jz .cant_inplace
shr eax, 12
add eax, edx
sub eax, ebx
jb .cant_inplace
jz @f
shl eax, 12
or al, MEM_BLOCK_FREE
mov [page_tabs + ebx*4], eax
@@:
mov eax, ebx
sub eax, ecx
shl eax, 12
or al, MEM_BLOCK_USED
mov [page_tabs + ecx*4], eax
lea eax, [ecx + 1]
shl eax, 12
push eax
push edi
lea edi, [page_tabs + edx*4]
mov eax, 2
sub ebx, edx
mov ecx, ebx
cld
rep stosd
pop edi
mov edx, [current_process]
shl ebx, 12
add [edx + PROC.mem_used], ebx
 
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_unlock
pop eax edx ecx
ret
 
.cant_inplace:
push esi edi
mov eax, [current_process]
mov esi, [eax + PROC.heap_base]
mov edi, [eax + PROC.heap_top]
shr esi, 12
shr edi, 12
sub ebx, ecx
.find_place:
cmp esi, edi
jae .place_not_found
mov eax, [page_tabs + esi*4]
test al, MEM_BLOCK_FREE
jz .next_place
shr eax, 12
cmp eax, ebx
jae .place_found
add esi, eax
jmp .find_place
.next_place:
shr eax, 12
add esi, eax
jmp .find_place
.place_not_found:
pop edi esi
jmp .ret0
.place_found:
sub eax, ebx
jz @f
push esi
add esi, ebx
shl eax, 12
or al, MEM_BLOCK_FREE
mov [page_tabs + esi*4], eax
pop esi
@@:
mov eax, ebx
shl eax, 12
or al, MEM_BLOCK_USED
mov [page_tabs + esi*4], eax
inc esi
mov eax, esi
shl eax, 12
push eax
mov eax, [page_tabs + ecx*4]
and eax, not 0xFFF
or al, MEM_BLOCK_FREE
sub edx, ecx
mov [page_tabs + ecx*4], eax
inc ecx
dec ebx
dec edx
jz .no
@@:
xor eax, eax
xchg eax, [page_tabs + ecx*4]
mov [page_tabs + esi*4], eax
mov eax, ecx
shl eax, 12
invlpg [eax]
inc esi
inc ecx
dec ebx
dec edx
jnz @b
.no:
push ebx
mov edx, [current_process]
shl ebx, 12
add [edx + PROC.mem_used], ebx
pop ebx
@@:
mov dword [page_tabs + esi*4], MEM_BLOCK_RESERVED
inc esi
dec ebx
jnz @b
 
mov ecx, [current_process]
lea ecx, [ecx + PROC.heap_lock]
call mutex_unlock
pop eax edi esi edx ecx
ret
 
 
 
;;;;;;;;;;;;;; SHARED MEMORY ;;;;;;;;;;;;;;;;;
 
 
; param
; eax= shm_map object
 
align 4
destroy_smap:
 
pushfd
cli
 
push esi
push edi
 
mov edi, eax
mov esi, [eax + SMAP.parent]
test esi, esi
jz .done
 
lock dec [esi + SMEM.refcount]
jnz .done
 
mov ecx, [esi + SMEM.bk]
mov edx, [esi + SMEM.fd]
 
mov [ecx + SMEM.fd], edx
mov [edx + SMEM.bk], ecx
 
stdcall kernel_free, [esi + SMEM.base]
mov eax, esi
call free
.done:
mov eax, edi
call destroy_kernel_object
 
pop edi
pop esi
popfd
 
ret
 
E_NOTFOUND = 5
E_ACCESS = 10
E_NOMEM = 30
E_PARAM = 33
 
SHM_READ = 0
SHM_WRITE = 1
 
SHM_ACCESS_MASK = 3
 
SHM_OPEN = 0 shl 2
SHM_OPEN_ALWAYS = 1 shl 2
SHM_CREATE = 2 shl 2
 
SHM_OPEN_MASK = 3 shl 2
 
align 4
proc shmem_open stdcall name:dword, size:dword, access:dword
locals
action dd ?
owner_access dd ?
mapped dd ?
endl
 
push ebx
push esi
push edi
 
mov [mapped], 0
mov [owner_access], 0
 
pushfd ;mutex required
cli
 
mov eax, [access]
and eax, SHM_OPEN_MASK
mov [action], eax
 
mov ebx, [name]
test ebx, ebx
mov edx, E_PARAM
jz .fail
 
mov esi, [shmem_list.fd]
align 4
@@:
cmp esi, shmem_list
je .not_found
 
lea edx, [esi + SMEM.name]; link , base, size
stdcall strncmp, edx, ebx, 32
test eax, eax
je .found
 
mov esi, [esi + SMEM.fd]
jmp @B
 
.not_found:
mov eax, [action]
 
cmp eax, SHM_OPEN
mov edx, E_NOTFOUND
je .fail
 
cmp eax, SHM_CREATE
mov edx, E_PARAM
je .create_shm
 
cmp eax, SHM_OPEN_ALWAYS
jne .fail
 
.create_shm:
 
mov ecx, [size]
test ecx, ecx
jz .fail
 
add ecx, 4095
and ecx, -4096
mov [size], ecx
 
mov eax, sizeof.SMEM
call malloc
test eax, eax
mov esi, eax
mov edx, E_NOMEM
jz .fail
 
stdcall kernel_alloc, [size]
test eax, eax
mov [mapped], eax
mov edx, E_NOMEM
jz .cleanup
 
mov ecx, [size]
mov edx, [access]
and edx, SHM_ACCESS_MASK
 
mov [esi + SMEM.base], eax
mov [esi + SMEM.size], ecx
mov [esi + SMEM.access], edx
mov [esi + SMEM.refcount], 0
mov [esi + SMEM.name + 28], 0
 
lea eax, [esi + SMEM.name]
stdcall strncpy, eax, [name], 31
 
mov eax, [shmem_list.fd]
mov [esi + SMEM.bk], shmem_list
mov [esi + SMEM.fd], eax
 
mov [eax + SMEM.bk], esi
mov [shmem_list.fd], esi
 
mov [action], SHM_OPEN
mov [owner_access], SHM_WRITE
 
.found:
mov eax, [action]
 
cmp eax, SHM_CREATE
mov edx, E_ACCESS
je .exit
 
cmp eax, SHM_OPEN
mov edx, E_PARAM
je .create_map
 
cmp eax, SHM_OPEN_ALWAYS
jne .fail
 
.create_map:
 
mov eax, [access]
and eax, SHM_ACCESS_MASK
cmp eax, [esi + SMEM.access]
mov [access], eax
mov edx, E_ACCESS
ja .fail
 
mov ebx, [current_slot_idx]
shl ebx, BSF sizeof.TASKDATA
mov ebx, [TASK_TABLE + ebx + TASKDATA.pid]
mov eax, sizeof.SMAP
 
call create_kernel_object
test eax, eax
mov edi, eax
mov edx, E_NOMEM
jz .fail
 
inc [esi + SMEM.refcount]
 
mov [edi + SMAP.magic], 'SMAP'
mov [edi + SMAP.destroy], destroy_smap
mov [edi + SMAP.parent], esi
mov [edi + SMAP.base], 0
 
stdcall user_alloc, [esi + SMEM.size]
test eax, eax
mov [mapped], eax
mov edx, E_NOMEM
jz .cleanup2
 
mov [edi + SMAP.base], eax
 
mov ecx, [esi + SMEM.size]
mov [size], ecx
 
shr ecx, 12
shr eax, 10
 
mov esi, [esi + SMEM.base]
shr esi, 10
lea edi, [page_tabs + eax]
add esi, page_tabs
 
mov edx, [access]
or edx, [owner_access]
shl edx, 1
or edx, PG_SHARED + PG_UR
@@:
lodsd
and eax, 0xFFFFF000
or eax, edx
stosd
loop @B
 
xor edx, edx
 
cmp [owner_access], 0
jne .fail
.exit:
mov edx, [size]
.fail:
mov eax, [mapped]
 
popfd
pop edi
pop esi
pop ebx
ret
.cleanup:
mov [size], edx
mov eax, esi
call free
jmp .exit
 
.cleanup2:
mov [size], edx
mov eax, edi
call destroy_smap
jmp .exit
endp
 
align 4
proc shmem_close stdcall, name:dword
 
mov eax, [name]
test eax, eax
jz .fail
 
push esi
push edi
pushfd
cli
 
mov esi, [current_slot]
add esi, APP_OBJ_OFFSET
.next:
mov eax, [esi + APPOBJ.fd]
test eax, eax
jz @F
 
cmp eax, esi
mov esi, eax
je @F
 
cmp [eax + SMAP.magic], 'SMAP'
jne .next
 
mov edi, [eax + SMAP.parent]
test edi, edi
jz .next
 
lea edi, [edi + SMEM.name]
stdcall strncmp, [name], edi, 32
test eax, eax
jne .next
 
stdcall user_free, [esi + SMAP.base]
 
mov eax, esi
call [esi + APPOBJ.destroy]
@@:
popfd
pop edi
pop esi
.fail:
ret
endp
 
 
 
proc user_ring stdcall, size:dword
 
locals
virt_ptr dd ?
phys_ptr dd ?
num_pages dd ?
endl
 
; Size must be an exact multiple of pagesize
mov eax, [size]
test eax, PAGE_SIZE-1
jnz .exit
 
; We must have at least one complete page
shr eax, 12
jz .exit
mov [num_pages], eax
 
; Allocate double the virtual memory
mov eax, [size]
shl eax, 1
jz .exit
stdcall user_alloc, eax
test eax, eax
jz .exit
mov [virt_ptr], eax
 
; Now allocate physical memory
stdcall alloc_pages, [num_pages]
test eax, eax
jz .exit_free_virt
mov [phys_ptr], eax
 
; Map first half of virtual memory to physical memory
push ecx esi edi
mov ecx, [num_pages]
mov esi, [virt_ptr]
mov edi, [phys_ptr]
.loop1:
stdcall map_page, esi, edi, PG_UWR
add esi, PAGE_SIZE
add edi, PAGE_SIZE
dec ecx
jnz .loop1
 
; Map second half of virtual memory to same physical memory
mov ecx, [num_pages]
mov edi, [phys_ptr]
.loop2:
stdcall map_page, esi, edi, PG_UWR
add esi, PAGE_SIZE
add edi, PAGE_SIZE
dec ecx
jnz .loop2
pop edi esi ecx
 
mov eax, [virt_ptr]
ret
 
.exit_free_virt:
stdcall user_free, [virt_ptr]
 
.exit:
xor eax, eax
ret
 
endp
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/timers.inc
0,0 → 1,229
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2012-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; Simple implementation of timers. All timers are organized in a double-linked
; list, and the OS loop after every timer tick processes the list.
 
; This structure describes a timer for the kernel.
struct TIMER
Next dd ?
Prev dd ?
; These fields organize a double-linked list of all timers.
TimerFunc dd ?
; Function to be called when the timer is activated.
UserData dd ?
; The value that is passed as is to .TimerFunc.
Time dd ?
; Time at which the timer should be activated.
Interval dd ?
; Interval between activations of the timer, in 0.01s.
ends
 
iglobal
align 4
; The head of timer list.
timer_list:
dd timer_list
dd timer_list
endg
uglobal
; These two variables are used to synchronize access to the global list.
; Logically, they form an recursive mutex. Physically, the first variable holds
; the slot number of the current owner or 0, the second variable holds the
; recursion count.
; The mutex should be recursive to allow a timer function to add/delete other
; timers or itself.
timer_list_owner dd 0
timer_list_numlocks dd 0
; A timer function can delete any timer, including itself and the next timer in
; the chain. To handle such situation correctly, we keep the next timer in a
; global variable, so the removing operation can update it.
timer_next dd 0
endg
 
; This internal function acquires the lock for the global list.
lock_timer_list:
mov edx, [current_slot_idx]
@@:
xor eax, eax
lock cmpxchg [timer_list_owner], edx
jz @f
cmp eax, edx
jz @f
call change_task
jmp @b
@@:
inc [timer_list_numlocks]
ret
 
; This internal function releases the lock for the global list.
unlock_timer_list:
dec [timer_list_numlocks]
jnz .nothing
mov [timer_list_owner], 0
.nothing:
ret
 
; This function adds a timer.
; If deltaStart is nonzero, the timer is activated after deltaStart hundredths
; of seconds starting from the current time. If interval is nonzero, the timer
; is activated every deltaWork hundredths of seconds starting from the first
; activation. The activated timer calls timerFunc as stdcall function with one
; argument userData.
; Return value is NULL if something has failed or some value which is opaque
; for the caller. Later this value can be used for cancel_timer_hs.
proc timer_hs stdcall uses ebx, deltaStart:dword, interval:dword, \
timerFunc:dword, userData:dword
; 1. Allocate memory for the TIMER structure.
; 1a. Call the allocator.
movi eax, sizeof.TIMER
call malloc
; 1b. If allocation failed, return (go to 5) with eax = 0.
test eax, eax
jz .nothing
; 2. Setup the TIMER structure.
xchg ebx, eax
; 2a. Copy values from the arguments.
mov ecx, [interval]
mov [ebx+TIMER.Interval], ecx
mov ecx, [timerFunc]
mov [ebx+TIMER.TimerFunc], ecx
mov ecx, [userData]
mov [ebx+TIMER.UserData], ecx
; 2b. Get time of the next activation.
mov ecx, [deltaStart]
test ecx, ecx
jnz @f
mov ecx, [interval]
@@:
add ecx, [timer_ticks]
mov [ebx+TIMER.Time], ecx
; 3. Insert the TIMER structure to the global list.
; 3a. Acquire the lock.
call lock_timer_list
; 3b. Insert an item at ebx to the tail of the timer_list.
mov eax, timer_list
mov ecx, [eax+TIMER.Prev]
mov [ebx+TIMER.Next], eax
mov [ebx+TIMER.Prev], ecx
mov [eax+TIMER.Prev], ebx
mov [ecx+TIMER.Next], ebx
; 3c. Release the lock.
call unlock_timer_list
; 4. Return with eax = pointer to TIMER structure.
xchg ebx, eax
.nothing:
; 5. Returning.
ret
endp
 
; This function removes a timer.
; The only argument is [esp+4] = the value which was returned from timer_hs.
cancel_timer_hs:
push ebx ; save used register to be stdcall
; 1. Remove the TIMER structure from the global list.
; 1a. Acquire the lock.
call lock_timer_list
mov ebx, [esp+4+4]
; 1b. Delete an item at ebx from the double-linked list.
mov eax, [ebx+TIMER.Next]
mov ecx, [ebx+TIMER.Prev]
mov [eax+TIMER.Prev], ecx
mov [ecx+TIMER.Next], eax
; 1c. If we are removing the next timer in currently processing chain,
; the next timer for this timer becomes new next timer.
cmp ebx, [timer_next]
jnz @f
mov [timer_next], eax
@@:
; 1d. Release the lock.
call unlock_timer_list
; 2. Free the TIMER structure.
xchg eax, ebx
call free
; 3. Return.
pop ebx ; restore used register to be stdcall
ret 4 ; purge one dword argument to be stdcall
 
; This function is regularly called from osloop. It processes the global list
; and activates the corresponding timers.
check_timers:
; 1. Acquire the lock.
call lock_timer_list
; 2. Loop over all registered timers, checking time.
; 2a. Get the first item.
mov eax, [timer_list+TIMER.Next]
mov [timer_next], eax
.loop:
; 2b. Check for end of list.
cmp eax, timer_list
jz .done
; 2c. Get and store the next timer.
mov edx, [eax+TIMER.Next]
mov [timer_next], edx
; 2d. Check time for timer activation.
; We can't just compare [timer_ticks] and [TIMER.Time], since overflows are
; possible: if the current time is 0FFFFFFFFh ticks and timer should be
; activated in 3 ticks, the simple comparison will produce incorrect result.
; So we calculate the difference [timer_ticks] - [TIMER.Time]; if it is
; non-negative, the time is over; if it is negative, then either the time is
; not over or we have not processed this timer for 2^31 ticks, what is very
; unlikely.
mov edx, [timer_ticks]
sub edx, [eax+TIMER.Time]
js .next
; The timer should be activated now.
; 2e. Store the timer data in the stack. This is required since 2f can delete
; the timer, invalidating the content.
push [eax+TIMER.UserData] ; parameter for TimerFunc
push [eax+TIMER.TimerFunc] ; to be restored in 2g
; 2f. Calculate time of next activation or delete the timer if it is one-shot.
mov ecx, [eax+TIMER.Interval]
add [eax+TIMER.Time], ecx
test ecx, ecx
jnz .nodelete
stdcall cancel_timer_hs, eax
.nodelete:
; 2g. Activate timer, using data from the stack.
pop eax
call eax
.next:
; 2h. Advance to the next timer and continue the loop.
mov eax, [timer_next]
jmp .loop
.done:
; 3. Release the lock.
call unlock_timer_list
; 4. Return.
ret
 
; This is a simplified version of check_timers that does not call anything,
; just checks whether check_timers should do something.
proc check_timers_has_work?
pushf
cli
mov eax, [timer_list+TIMER.Next]
.loop:
cmp eax, timer_list
jz .done_nowork
mov edx, [timer_ticks]
sub edx, [eax+TIMER.Time]
jns .done_haswork
mov eax, [eax+TIMER.Next]
jmp .loop
.done_nowork:
popf
xor eax, eax
ret
.done_haswork:
popf
xor eax, eax
inc eax
ret
endp
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/v86.inc
0,0 → 1,907
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2007-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; Virtual-8086 mode manager
; diamond, 2007, 2008
 
DEBUG_SHOW_IO = 0
 
struct V86_machine
; page directory
process dd ?
; mutex to protect all data from writing by multiple threads at one time
mutex dd ?
; i/o permission map
iopm dd ?
ends
 
; Create V86 machine
; in: nothing
; out: eax = handle (pointer to struc V86_machine)
; eax = NULL => failure
; destroys: ebx, ecx, edx (due to malloc)
v86_create:
; allocate V86_machine structure
mov eax, sizeof.V86_machine
call malloc
test eax, eax
jz .fail
; initialize mutex
and dword [eax+V86_machine.mutex], 0
; allocate tables
mov ebx, eax
 
stdcall create_process, 4096
test eax, eax
jz .fail2
 
mov [eax+PROC.mem_used], 4096
mov [ebx+V86_machine.process], eax
 
push 2000h
call kernel_alloc
test eax, eax
jz .fail2
 
mov [ebx+V86_machine.iopm], eax
 
; initialize tables
push edi
mov edi, eax
mov eax, -1
mov ecx, 2000h/4
rep stosd
 
mov eax, [ebx+V86_machine.process]
mov eax, [eax+PROC.pdt_0_phys]
 
pushfd
cli
mov cr3, eax
 
; now V86 specific: initialize known addresses in first Mb
 
; first page - BIOS data (shared between all machines!)
; physical address = 0
; linear address = OS_BASE
; page before 0xA0000 - Extended BIOS Data Area (shared between all machines!)
; physical address = 0x9C000
; linear address = 0x8009C000
; (I have seen one computer with EBDA segment = 0x9D80,
; all other computers use less memory)
 
mov eax, PG_UWR
mov [page_tabs], eax
invlpg [eax]
 
mov byte [0x500], 0xCD
mov byte [0x501], 0x13
mov byte [0x502], 0xF4
mov byte [0x503], 0xCD
mov byte [0x504], 0x10
mov byte [0x505], 0xF4
 
mov eax, 0x98000+PG_UWR
mov edi, page_tabs+0x98*4
mov edx, 0x1000
mov ecx, 8
@@:
stosd
add eax, edx
loop @b
 
; addresses 0xC0000 - 0xFFFFF - BIOS code (shared between all machines!)
; physical address = 0xC0000
 
mov eax, 0xC0000+PG_UWR
mov edi, page_tabs+0xC0*4
mov ecx, 64
@@:
stosd
add eax, edx
loop @b
 
mov eax, [sys_proc+PROC.pdt_0_phys]
mov cr3, eax
popfd
 
pop edi
 
mov eax, ebx
ret
.fail2:
mov eax, ebx
call free
.fail:
xor eax, eax
ret
 
;not used
; Destroy V86 machine
; in: eax = handle
; out: nothing
; destroys: eax, ebx, ecx, edx (due to free)
;v86_destroy:
; push eax
; stdcall kernel_free, [eax+V86_machine.pagedir]
; pop eax
; jmp free
 
; Translate V86-address to linear address
; in: eax=V86 address
; esi=handle
; out: eax=linear address
; destroys: nothing
v86_get_lin_addr:
push ecx edx
mov ecx, eax
shr ecx, 12
mov edx, [page_tabs+ecx*4]
and eax, 0xFFF
and edx, 0xFFFFF000
or eax, edx
pop edx ecx
ret
 
;not used
; Sets linear address for V86-page
; in: eax=linear address (must be page-aligned)
; ecx=V86 page (NOT address!)
; esi=handle
; out: nothing
; destroys: nothing
;v86_set_page:
; push eax ebx
; mov ebx, [esi+V86_machine.pagedir]
; mov [ebx+ecx*4+0x1800], eax
; call get_pg_addr
; or al, 111b
; mov [ebx+ecx*4+0x1000], eax
; pop ebx eax
; ret
 
; Allocate memory in V86 machine
; in: eax=size (in bytes)
; esi=handle
; out: eax=V86 address, para-aligned (0x10 multiple)
; destroys: nothing
; недописана!!!
;v86_alloc:
; push ebx ecx edx edi
; lea ebx, [esi+V86_machine.mutex]
; call wait_mutex
; add eax, 0x1F
; shr eax, 4
; mov ebx, 0x1000 ; start with address 0x1000 (second page)
; mov edi, [esi+V86_machine.tables]
;.l:
; mov ecx, ebx
; shr ecx, 12
; mov edx, [edi+0x1000+ecx*4] ; get linear address
; test edx, edx ; page allocated?
; jz .unalloc
; mov ecx, ebx
; and ecx, 0xFFF
; add edx, ecx
; cmp dword [edx], 0 ; free block?
; jnz .n
; cmp dword [edx+4],
; and [esi+V86_machine.mutex], 0
; pop edi edx ecx ebx
; ret
 
uglobal
sys_v86_machine dd ?
endg
 
; Called from kernel.asm at first stages of loading
; Initialize system V86 machine (used to simulate BIOS int 13h)
init_sys_v86:
call v86_create
mov [sys_v86_machine], eax
test eax, eax
jz .ret
mov esi, eax
if ~DEBUG_SHOW_IO
; allow access to all ports
mov ecx, [esi+V86_machine.iopm]
xor eax, eax
mov edi, ecx
mov ecx, 10000h/8/4
rep stosd
end if
.ret:
ret
 
struct v86_regs
; don't change the order, it is important
edi dd ?
esi dd ?
ebp dd ?
dd ? ; ignored
ebx dd ?
edx dd ?
ecx dd ?
eax dd ?
eip dd ?
cs dd ?
eflags dd ? ; VM flag must be set!
esp dd ?
ss dd ?
es dd ?
ds dd ?
fs dd ?
gs dd ?
ends
 
; Run V86 machine
; in: ebx -> registers for V86 (two structures: in and out)
; esi = handle
; ecx = expected end address (CS:IP)
; edx = IRQ to hook or -1 if not required
; out: structure pointed to by ebx is filled with new values
; eax = 1 - exception has occured, cl contains code
; eax = 2 - access to disabled i/o port, ecx contains port address
; eax = 3 - IRQ is already hooked by another VM
; destroys: nothing
v86_start:
 
pushad
 
cli
 
mov ecx, [current_slot]
 
push dword [ecx+APPDATA.io_map]
push dword [ecx+APPDATA.io_map+4]
push [ecx+APPDATA.process]
push [ecx+APPDATA.saved_esp0]
mov [ecx+APPDATA.saved_esp0], esp
mov [tss._esp0], esp
 
mov eax, [esi+V86_machine.iopm]
call get_pg_addr
inc eax
mov dword [ecx+APPDATA.io_map], eax
mov dword [page_tabs + (tss._io_map_0 shr 10)], eax
 
mov eax, [esi+V86_machine.iopm]
add eax, 0x1000
call get_pg_addr
inc eax
mov dword [ecx+APPDATA.io_map+4], eax
mov dword [page_tabs + (tss._io_map_1 shr 10)], eax
 
mov eax, [esi+V86_machine.process]
mov [ecx+APPDATA.process], eax
mov [current_process], eax
mov eax, [eax+PROC.pdt_0_phys]
mov cr3, eax
 
; We do not enable interrupts, because V86 IRQ redirector assumes that
; machine is running
; They will be enabled by IRET.
; sti
 
mov eax, esi
sub esp, sizeof.v86_regs
mov esi, ebx
mov edi, esp
mov ecx, sizeof.v86_regs/4
rep movsd
 
cmp edx, -1
jz .noirqhook
uglobal
v86_irqhooks rd IRQ_RESERVED * 2
endg
cmp [v86_irqhooks+edx*8], 0
jz @f
cmp [v86_irqhooks+edx*8], eax
jz @f
mov esi, v86_irqerr
call sys_msg_board_str
inc [v86_irqhooks+edx*8+4]
mov eax, 3
jmp v86_exc_c.exit
@@:
mov [v86_irqhooks+edx*8], eax
inc [v86_irqhooks+edx*8+4]
.noirqhook:
 
popad
iretd
 
; It is only possible to leave virtual-8086 mode by faulting to
; a protected-mode interrupt handler (typically the general-protection
; exception handler, which in turn calls the virtual 8086-mode monitor).
 
iglobal
v86_exc_str1 db 'V86 : unexpected exception ',0
v86_exc_str2 db ' at ',0
v86_exc_str3 db ':',0
v86_exc_str4 db 13,10,'V86 : faulted code:',0
v86_exc_str5 db ' (unavailable)',0
v86_newline db 13,10,0
v86_io_str1 db 'V86 : access to disabled i/o port ',0
v86_io_byte db ' (byte)',13,10,0
v86_io_word db ' (word)',13,10,0
v86_io_dword db ' (dword)',13,10,0
v86_irqerr db 'V86 : IRQ already hooked',13,10,0
endg
 
v86_exc_c:
; Did we all that we have wanted to do?
cmp bl, 1
jne @f
xor eax, eax
mov dr6, eax
@@:
mov eax, [esp+sizeof.v86_regs+10h+18h]
cmp word [esp+v86_regs.eip], ax
jnz @f
shr eax, 16
cmp word [esp+v86_regs.cs], ax
jz .done
@@:
; Various system events, which must be handled, result in #GP
cmp bl, 13
jnz .nogp
; If faulted EIP exceeds 0xFFFF, we have #GP and it is an error
cmp word [esp+v86_regs.eip+2], 0
jnz .nogp
; Otherwise we can safely access byte at CS:IP
; (because it is #GP, not #PF handler)
; If we could get an exception just because of reading code bytes,
; we would have got it already and it wouldn't be #GP
movzx esi, word [esp+v86_regs.cs]
shl esi, 4
add esi, [esp+v86_regs.eip]
lodsb
cmp al, 0xCD ; int xx command = CD xx
jz .handle_int
cmp al, 0xCF
jz .handle_iret
cmp al, 0xF3
jz .handle_rep
cmp al, 0xEC
jz .handle_in
cmp al, 0xED
jz .handle_in_word
cmp al, 0xEE
jz .handle_out
cmp al, 0xEF
jz .handle_out_word
cmp al, 0xE4
jz .handle_in_imm
cmp al, 0xE6
jz .handle_out_imm
cmp al, 0x9C
jz .handle_pushf
cmp al, 0x9D
jz .handle_popf
cmp al, 0xFA
jz .handle_cli
cmp al, 0xFB
jz .handle_sti
cmp al, 0x66
jz .handle_66
jmp .nogp
.handle_int:
cmp word [esp+v86_regs.eip], 0xFFFF
jae .nogp
xor eax, eax
lodsb
; call sys_msg_board_byte
; simulate INT command
; N.B. It is possible that some checks need to be corrected,
; but at least in case of normal execution the code works.
.simulate_int:
cmp word [esp+v86_regs.esp], 6
jae @f
mov bl, 12 ; #SS exception
jmp .nogp
@@:
movzx edx, word [esp+v86_regs.ss]
shl edx, 4
push eax
movzx eax, word [esp+4+v86_regs.esp]
sub eax, 6
add edx, eax
mov eax, edx
mov esi, [esp+4+sizeof.v86_regs+10h+4]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14 ; #PF exception
jmp .nogp
@@:
lea eax, [edx+5]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14 ; #PF exception
jmp .nogp
@@:
sub word [esp+4+v86_regs.esp], 6
mov eax, [esp+4+v86_regs.eip]
cmp byte [esp+1], 0
jnz @f
inc eax
inc eax
@@:
mov word [edx], ax
mov eax, [esp+4+v86_regs.cs]
mov word [edx+2], ax
mov eax, [esp+4+v86_regs.eflags]
mov word [edx+4], ax
pop eax
mov ah, 0
mov cx, [eax*4]
mov word [esp+v86_regs.eip], cx
mov cx, [eax*4+2]
mov word [esp+v86_regs.cs], cx
; note that interrupts will be disabled globally at IRET
and byte [esp+v86_regs.eflags+1], not 3 ; clear IF and TF flags
; continue V86 execution
popad
iretd
.handle_iret:
cmp word [esp+v86_regs.esp], 0x10000 - 6
jbe @f
mov bl, 12
jmp .nogp
@@:
movzx edx, word [esp+v86_regs.ss]
shl edx, 4
movzx eax, word [esp+v86_regs.esp]
add edx, eax
mov eax, edx
mov esi, [esp+sizeof.v86_regs+10h+4]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14
jmp .nogp
@@:
lea eax, [edx+5]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14
jmp .nogp
@@:
mov ax, [edx]
mov word [esp+v86_regs.eip], ax
mov ax, [edx+2]
mov word [esp+v86_regs.cs], ax
mov ax, [edx+4]
mov word [esp+v86_regs.eflags], ax
add word [esp+v86_regs.esp], 6
popad
iretd
.handle_pushf:
cmp word [esp+v86_regs.esp], 1
jnz @f
mov bl, 12
jmp .nogp
@@:
movzx edx, word [esp+v86_regs.ss]
shl edx, 4
mov eax, [esp+v86_regs.esp]
sub eax, 2
movzx eax, ax
add edx, eax
mov eax, edx
mov esi, [esp+sizeof.v86_regs+10h+4]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14 ; #PF exception
jmp .nogp
@@:
lea eax, [edx+1]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14
jmp .nogp
@@:
sub word [esp+v86_regs.esp], 2
mov eax, [esp+v86_regs.eflags]
mov [edx], ax
inc word [esp+v86_regs.eip]
popad
iretd
.handle_pushfd:
cmp word [esp+v86_regs.esp], 4
jae @f
mov bl, 12 ; #SS exception
jmp .nogp
@@:
movzx edx, word [esp+v86_regs.ss]
shl edx, 4
movzx eax, word [esp+v86_regs.esp]
sub eax, 4
add edx, eax
mov eax, edx
mov esi, [esp+sizeof.v86_regs+10h+4]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14 ; #PF exception
jmp .nogp
@@:
lea eax, [edx+3]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14 ; #PF exception
jmp .nogp
@@:
sub word [esp+v86_regs.esp], 4
movzx eax, word [esp+v86_regs.eflags]
mov [edx], eax
add word [esp+v86_regs.eip], 2
popad
iretd
.handle_popf:
cmp word [esp+v86_regs.esp], 0xFFFF
jnz @f
mov bl, 12
jmp .nogp
@@:
movzx edx, word [esp+v86_regs.ss]
shl edx, 4
movzx eax, word [esp+v86_regs.esp]
add edx, eax
mov eax, edx
mov esi, [esp+sizeof.v86_regs+10h+4]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14 ; #PF exception
jmp .nogp
@@:
lea eax, [edx+1]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14
jmp .nogp
@@:
mov ax, [edx]
mov word [esp+v86_regs.eflags], ax
add word [esp+v86_regs.esp], 2
inc word [esp+v86_regs.eip]
popad
iretd
.handle_popfd:
cmp word [esp+v86_regs.esp], 0x10000 - 4
jbe @f
mov bl, 12
jmp .nogp
@@:
movzx edx, word [esp+v86_regs.ss]
shl edx, 4
movzx eax, word [esp+v86_regs.esp]
add edx, eax
mov eax, edx
mov esi, [esp+sizeof.v86_regs+10h+4]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14
jmp .nogp
@@:
lea eax, [edx+3]
call v86_get_lin_addr
cmp eax, 0x1000
jae @f
mov bl, 14
jmp .nogp
@@:
mov eax, [edx]
mov word [esp+v86_regs.eflags], ax
add word [esp+v86_regs.esp], 4
add word [esp+v86_regs.eip], 2
popad
iretd
.handle_cli:
and byte [esp+v86_regs.eflags+1], not 2
inc word [esp+v86_regs.eip]
popad
iretd
.handle_sti:
or byte [esp+v86_regs.eflags+1], 2
inc word [esp+v86_regs.eip]
popad
iretd
.handle_rep:
cmp word [esp+v86_regs.eip], 0xFFFF
jae .nogp
lodsb
cmp al, 6Eh
jz .handle_rep_outsb
jmp .nogp
.handle_rep_outsb:
.handle_in:
.handle_out:
.invalid_io_byte:
movzx ebx, word [esp+v86_regs.edx]
mov ecx, 1
jmp .invalid_io
.handle_in_imm:
.handle_out_imm:
cmp word [esp+v86_regs.eip], 0xFFFF
jae .nogp
lodsb
movzx ebx, al
mov ecx, 1
jmp .invalid_io
.handle_66:
cmp word [esp+v86_regs.eip], 0xFFFF
jae .nogp
lodsb
cmp al, 0x9C
jz .handle_pushfd
cmp al, 0x9D
jz .handle_popfd
cmp al, 0xEF
jz .handle_out_dword
cmp al, 0xED
jz .handle_in_dword
jmp .nogp
.handle_in_word:
.handle_out_word:
movzx ebx, word [esp+v86_regs.edx]
mov ecx, 2
jmp .invalid_io
.handle_in_dword:
.handle_out_dword:
.invalid_io_dword:
movzx ebx, word [esp+v86_regs.edx]
mov ecx, 4
.invalid_io:
mov esi, v86_io_str1
call sys_msg_board_str
mov eax, ebx
call sys_msg_board_dword
mov esi, v86_io_byte
cmp ecx, 1
jz @f
mov esi, v86_io_word
cmp ecx, 2
jz @f
mov esi, v86_io_dword
@@:
call sys_msg_board_str
if DEBUG_SHOW_IO
mov edx, ebx
mov ebx, 200
call delay_hs
mov esi, [esp+v86_regs.size+10h+4]
mov eax, [esi+V86_machine.iopm]
@@:
btr [eax], edx
inc edx
loop @b
popad
iretd
else
mov eax, 2
jmp .exit
end if
.nogp:
 
mov esi, v86_exc_str1
call sys_msg_board_str
mov al, bl
call sys_msg_board_byte
mov esi, v86_exc_str2
call sys_msg_board_str
mov ax, [esp+32+4]
call sys_msg_board_word
mov esi, v86_exc_str3
call sys_msg_board_str
mov ax, [esp+32]
call sys_msg_board_word
mov esi, v86_exc_str4
call sys_msg_board_str
mov ecx, 8
movzx edx, word [esp+32+4]
shl edx, 4
add edx, [esp+32]
@@:
mov esi, [esp+sizeof.v86_regs+10h+4]
mov eax, edx
call v86_get_lin_addr
cmp eax, 0x1000
jb .nopage
mov esi, v86_exc_str3-2
call sys_msg_board_str
mov al, [edx]
call sys_msg_board_byte
inc edx
loop @b
jmp @f
.nopage:
mov esi, v86_exc_str5
call sys_msg_board_str
@@:
mov esi, v86_newline
call sys_msg_board_str
mov eax, 1
jmp .exit
 
.done:
xor eax, eax
 
.exit:
mov [esp+sizeof.v86_regs+10h+1Ch], eax
mov [esp+sizeof.v86_regs+10h+18h], ebx
 
mov edx, [esp+sizeof.v86_regs+10h+14h]
cmp edx, -1
jz @f
dec [v86_irqhooks+edx*8+4]
jnz @f
and [v86_irqhooks+edx*8], 0
@@:
 
mov esi, esp
mov edi, [esi+sizeof.v86_regs+10h+10h]
add edi, sizeof.v86_regs
mov ecx, sizeof.v86_regs/4
rep movsd
mov esp, esi
 
cli
mov ecx, [current_slot]
pop eax
 
mov [ecx+APPDATA.saved_esp0], eax
mov [tss._esp0], eax
pop eax
mov [ecx+APPDATA.process], eax
mov [current_process], eax
pop ebx
mov dword [ecx+APPDATA.io_map+4], ebx
mov dword [page_tabs + (tss._io_map_1 shr 10)], ebx
pop ebx
mov dword [ecx+APPDATA.io_map], ebx
mov dword [page_tabs + (tss._io_map_0 shr 10)], ebx
mov eax, [eax+PROC.pdt_0_phys]
mov cr3, eax
sti
 
popad
ret
 
;my05:
; mov dx, 30C2h
; mov cx, 4
;.0:
; in al, dx
; cmp al, 0FFh
; jz @f
; test al, 4
; jnz .1
;@@:
; add dx, 8
; in al, dx
; cmp al, 0FFh
; jz @f
; test al, 4
; jnz .1
;@@:
; loop .0
; ret
;.1:
; or al, 84h
; out dx, al
;.2:
; mov dx, 30F7h
; in al, dx
; mov byte [BOOT_VAR + 48Eh], 0FFh
; ret
 
align 4
v86_irq:
; push irq/pushad/jmp v86_irq
; ebp = irq
lea esi, [esp+1Ch]
lea edi, [esi+4]
mov ecx, 8
std
rep movsd
cld
mov edi, ebp
pop eax
v86_irq2:
mov esi, [v86_irqhooks+edi*8] ; get VM handle
mov eax, [esi+V86_machine.process]
mov ecx, [current_slot_idx]
shl ecx, 8
cmp [SLOT_BASE+ecx+APPDATA.process], eax
jnz .notcurrent
lea eax, [edi+8]
cmp al, 10h
mov ah, 1
jb @f
add al, 60h
@@:
jmp v86_exc_c.simulate_int
.notcurrent:
mov ebx, SLOT_BASE + 0x100
mov ecx, [thread_count]
.scan:
cmp [ebx+APPDATA.process], eax
jnz .cont
push ecx
mov ecx, [ebx+APPDATA.saved_esp0]
cmp word [ecx-sizeof.v86_regs+v86_regs.esp], 6
jb .cont2
movzx edx, word [ecx-sizeof.v86_regs+v86_regs.ss]
shl edx, 4
push eax
movzx eax, word [ecx-sizeof.v86_regs+v86_regs.esp]
sub eax, 6
add edx, eax
mov eax, edx
call v86_get_lin_addr
cmp eax, 0x1000
jb .cont3
lea eax, [edx+5]
call v86_get_lin_addr
cmp eax, 0x1000
jb .cont3
pop eax
pop ecx
jmp .found
.cont3:
pop eax
.cont2:
pop ecx
.cont:
add ebx, 0x100
loop .scan
mov ecx, edi
call irq_eoi
popad
iretd
.found:
mov eax, [eax+PROC.pdt_0_phys]
mov cr3, eax
mov esi, [ebx+APPDATA.saved_esp0]
sub word [esi-sizeof.v86_regs+v86_regs.esp], 6
mov ecx, [esi-sizeof.v86_regs+v86_regs.eip]
mov word [edx], cx
mov ecx, [esi-sizeof.v86_regs+v86_regs.cs]
mov word [edx+2], cx
mov ecx, [esi-sizeof.v86_regs+v86_regs.eflags]
mov word [edx+4], cx
lea eax, [edi+8]
cmp al, 10h
jb @f
add al, 60h
@@:
mov cx, [eax*4]
mov word [esi-sizeof.v86_regs+v86_regs.eip], cx
mov cx, [eax*4+2]
mov word [esi-sizeof.v86_regs+v86_regs.cs], cx
and byte [esi-sizeof.v86_regs+v86_regs.eflags+1], not 3
call update_counters
lea edi, [ebx + 0x100000000 - SLOT_BASE]
shr edi, 3
add edi, TASK_TABLE
call find_next_task.found
call do_change_task
popad
iretd
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/apic.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/hpet.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/slab.inc
0,0 → 1,125
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; Memory management for slab structures.
; The allocator meets special requirements:
; * memory blocks are properly aligned
; * memory blocks do not cross page boundary
; The allocator manages fixed-size blocks.
; Thus, the specific allocator works as follows:
; allocate one page, split into blocks, maintain the single-linked
; list of all free blocks in each page.
 
; Note: size must be a multiple of required alignment.
 
; Data for one pool: dd pointer to the first page, MUTEX lock.
 
; Allocator for fixed-size blocks: allocate a block.
; [ebx-4] = pointer to the first page, ebx = pointer to MUTEX structure.
proc slab_alloc
push edi ; save used register to be stdcall
virtual at esp
dd ? ; saved edi
dd ? ; return address
.size dd ?
end virtual
; 1. Take the lock.
mov ecx, ebx
call mutex_lock
; 2. Find the first allocated page with a free block, if any.
; 2a. Initialize for the loop.
mov edx, ebx
.pageloop:
; 2b. Get the next page, keeping the current in eax.
mov eax, edx
mov edx, [edx-4]
; 2c. If there is no next page, we're out of luck; go to 4.
test edx, edx
jz .newpage
add edx, 0x1000
@@:
; 2d. Get the pointer to the first free block on this page.
; If there is no free block, continue to 2b.
mov eax, [edx-8]
test eax, eax
jz .pageloop
; 2e. Get the pointer to the next free block.
mov ecx, [eax]
; 2f. Update the pointer to the first free block from eax to ecx.
; Normally [edx-8] still contains eax, if so, atomically set it to ecx
; and proceed to 3.
; However, the price of simplicity of slab_free (in particular, it doesn't take
; the lock) is that [edx-8] could (rarely) be changed while we processed steps
; 2d+2e. If so, return to 2d and retry.
lock cmpxchg [edx-8], ecx
jnz @b
.return:
; 3. Release the lock taken in step 1 and return.
push eax
mov ecx, ebx
call mutex_unlock
pop eax
pop edi ; restore used register to be stdcall
ret 4
.newpage:
; 4. Allocate a new page.
push eax
stdcall kernel_alloc, 0x1000
pop edx
; If failed, say something to the debug board and return zero.
test eax, eax
jz .nomemory
; 5. Add the new page to the tail of list of allocated pages.
mov [edx-4], eax
; 6. Initialize two service dwords in the end of page:
; first free block is (start of page) + (block size)
; (we will return first block at (start of page), so consider it allocated),
; no next page.
mov edx, eax
lea edi, [eax+0x1000-8]
add edx, [.size]
mov [edi], edx
and dword [edi+4], 0
; 7. All blocks starting from edx are free; join them in a single-linked list.
@@:
mov ecx, edx
add edx, [.size]
mov [ecx], edx
cmp edx, edi
jbe @b
sub ecx, [.size]
and dword [ecx], 0
; 8. Return (start of page).
jmp .return
.nomemory:
dbgstr 'no memory for slab allocation'
xor eax, eax
jmp .return
endp
 
; Allocator for fixed-size blocks: free a block.
proc slab_free
push ecx edx
virtual at esp
rd 2 ; saved registers
dd ? ; return address
.block dd ?
end virtual
; Insert the given block to the head of free blocks in this page.
mov ecx, [.block]
mov edx, ecx
or edx, 0xFFF
@@:
mov eax, [edx+1-8]
mov [ecx], eax
lock cmpxchg [edx+1-8], ecx
jnz @b
pop edx ecx
ret 4
endp
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/irq.inc
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
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/exports.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/mtrrtest.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/Tupfile.lua
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")
/kernel/branches/kolibrios-pe-clevermouse/core/test_malloc.asm
0,0 → 1,250
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2009-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
; Tests of malloc()/free() from the kernel heap.
; This file is not included in the kernel, it is just test application.
use32
db 'MENUET01'
dd 1, start, i_end, mem, mem, 0, 0
 
start:
; Zero-initialize uglobals (as in kernel at boot)
mov ecx, (zeroend - zerostart + 3) / 4
xor eax, eax
mov edi, zerostart
rep stosd
; Initialize small heap (as in kernel at boot)
call init_malloc
; Run tests
call run_test1
call run_test2
call run_test3
; All is OK, return
or eax, -1
int 0x40
 
run_test1:
; basic test
mov eax, 1
call malloc_with_test
mov byte [eax], 0xDD
mov esi, eax
mov eax, 1
call malloc_with_test
cmp byte [esi], 0xDD
jnz memory_destroyed
mov byte [eax], 0xEE
xchg eax, esi
call free
cmp byte [esi], 0xEE
jnz memory_destroyed
xchg eax, esi
call free
ret
 
run_test2:
ret
 
run_test3:
; 1024 times run random operation.
; Randomly select malloc(random size from 1 to 1023)
; or free(random of previously allocated areas)
mov edi, 0x12345678
xor esi, esi ; 0 areas allocated
mov ebx, 1024
.loop:
imul edi, 1103515245
add edi, 12345
mov eax, edi
shr eax, 16
test ebx, 64
jz .prefer_free
.prefer_malloc:
test eax, 3
jz .free
jmp @f
.prefer_free:
test eax, 3
jnz .free
@@:
shr eax, 2
and eax, 1023
jz .loop
push ebx
push eax
; mov ecx, [saved_state_num]
; mov [saved_state+ecx*8], eax
push edi
call malloc_with_test
pop ecx
cmp ecx, edi
jnz edi_destroyed
; mov ecx, [saved_state_num]
; mov [saved_state+ecx*8+4], eax
; inc [saved_state_num]
pop ecx
pop ebx
inc esi
push ecx eax
push edi
mov edi, eax
mov eax, esi
rep stosb
pop edi
jmp .common
.free:
test esi, esi
jz .loop
xor edx, edx
div esi
sub edx, esi
neg edx
dec edx
mov eax, [esp+edx*8]
; mov ecx, [saved_state_num]
; mov [saved_state+ecx*8], -1
; mov [saved_state+ecx*8+4], eax
; inc [saved_state_num]
mov ecx, [esp+edx*8+4]
push edi eax
mov edi, eax
mov al, [edi]
repz scasb
jnz memory_destroyed
pop eax edi
push ebx edx
push edi
call free
pop ecx
cmp ecx, edi
jnz edi_destroyed
pop edx ebx
dec esi
pop eax ecx
push edi
lea edi, [esp+4]
@@:
dec edx
js @f
xchg eax, [edi]
xchg ecx, [edi+4]
add edi, 8
jmp @b
@@:
pop edi
.common:
dec ebx
jnz .loop
@@:
dec esi
js @f
pop eax ecx
call free
jmp @b
@@:
ret
 
malloc_with_test:
; calls malloc() and checks returned value
call malloc
test eax, eax
jz generic_malloc_fail
call check_mutex
call check_range
ret
 
; Stubs for kernel procedures used by heap code
mutex_init:
and dword [ecx], 0
ret
mutex_lock:
inc dword [ecx]
ret
mutex_unlock:
dec dword [ecx]
ret
 
kernel_alloc:
cmp dword [esp+4], bufsize
jnz error1
mov eax, buffer
ret 4
 
macro $Revision [args]
{
}
 
; Error handlers
error1:
mov eax, 1
jmp error_with_code
 
generic_malloc_fail:
mov eax, 2
jmp error_with_code
 
check_mutex:
cmp dword [mst.mutex], 0
jnz @f
ret
@@:
mov eax, 3
jmp error_with_code
 
check_range:
cmp eax, buffer
jb @f
cmp eax, buffer+bufsize
jae @f
ret
@@:
mov eax, 4
jmp error_with_code
 
memory_destroyed:
mov eax, 5
jmp error_with_code
 
edi_destroyed:
mov eax, 6
jmp error_with_code
 
error_with_code:
mov edx, saved_state_num
; eax = error code
; 1 signals error in testing code (wrong bufsize)
; 2 = malloc() returned NULL
; 3 = mutex not released
; 4 = weird returned value from malloc()
; 5 = memory destroyed by malloc() or free()
int3 ; simplest way to report error
jmp $-1 ; just in case
 
; Include main heap code
include '../macros.inc'
include '../proc32.inc'
include '../struct.inc'
include '../const.inc'
include 'malloc.inc'
 
i_end:
 
align 4
zerostart:
mst MEM_STATE
 
align 16
bufsize = 0x40000 ; change if malloc.inc changes
buffer rb bufsize
zeroend:
 
saved_state_num dd ?
saved_state rd 0x10000
 
align 4
rb 0x10000 ; for stack
mem:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/mtrr.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/ext_lib.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/string.inc
0,0 → 1,189
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; Author: Kees J. Bot 1 Jan 1994 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
; size_t strncat(char *s1, const char *s2, size_t n)
; Append string s2 to s1.
 
; char *strchr(const char *s, int c)
 
 
; int strncmp(const char *s1, const char *s2, size_t n)
; Compare two strings.
 
; char *strncpy(char *s1, const char *s2, size_t n)
; Copy string s2 to s1.
 
; size_t strnlen(const char *s, size_t n)
; Return the length of a string.
 
; proc strrchr stdcall, s:dword, c:dword
; Look for the last occurrence a character in a string.
 
proc strncat stdcall, s1:dword, s2:dword, n:dword
push esi
push edi
mov edi, [s1] ; String s1
mov edx, [n] ; Maximum length
 
mov ecx, -1
xor al, al ; Null byte
cld
repne scasb ; Look for the zero byte in s1
dec edi ; Back one up (and clear 'Z' flag)
push edi ; Save end of s1
mov edi, [s2] ; edi = string s2
mov ecx, edx ; Maximum count
repne scasb ; Look for the end of s2
jne @F
inc ecx ; Exclude null byte
@@:
sub edx, ecx ; Number of bytes in s2
mov ecx, edx
mov esi, [s2] ; esi = string s2
pop edi ; edi = end of string s1
rep movsb ; Copy bytes
stosb ; Add a terminating null
mov eax, [s1] ; Return s1
pop edi
pop esi
ret
endp
 
align 4
proc strncmp stdcall, s1:dword, s2:dword, n:dword
 
push esi
push edi
mov ecx, [n]
test ecx, ecx ; Max length is zero?
je .done
 
mov esi, [s1] ; esi = string s1
mov edi, [s2] ; edi = string s2
cld
.compare:
cmpsb ; Compare two bytes
jne .done
cmp byte [esi-1], 0 ; End of string?
je .done
dec ecx ; Length limit reached?
jne .compare
.done:
seta al ; al = (s1 > s2)
setb ah ; ah = (s1 < s2)
sub al, ah
movsx eax, al ; eax = (s1 > s2) - (s1 < s2), i.e. -1, 0, 1
pop edi
pop esi
ret
endp
 
align 4
proc strncpy stdcall, s1:dword, s2:dword, n:dword
 
push esi
push edi
 
mov ecx, [n] ; Maximum length
mov edi, [s2] ; edi = string s2
xor al, al ; Look for a zero byte
mov edx, ecx ; Save maximum count
cld
repne scasb ; Look for end of s2
sub edx, ecx ; Number of bytes in s2 including null
xchg ecx, edx
mov esi, [s2] ; esi = string s2
mov edi, [s1] ; edi = string s1
rep movsb ; Copy bytes
 
mov ecx, edx ; Number of bytes not copied
rep stosb ; strncpy always copies n bytes by null padding
mov eax, [s1] ; Return s1
pop edi
pop esi
ret
endp
 
align 4
proc strnlen stdcall, s:dword, n:dword
 
push edi
mov ecx, [n]
mov edi, [s] ; edi = string
xor al, al ; Look for a zero byte
mov edx, ecx ; Save maximum count
cmp cl, 1 ; 'Z' bit must be clear if ecx = 0
cld
repne scasb ; Look for zero
jne @F
inc ecx ; Don't count zero byte
@@:
mov eax, edx
sub eax, ecx ; Compute bytes scanned
pop edi
ret
endp
 
align 4
proc strchr stdcall, s:dword, c:dword
push edi
cld
mov edi, [s] ; edi = string
mov edx, 16 ; Look at small chunks of the string
.next:
shl edx, 1 ; Chunks become bigger each time
mov ecx, edx
xor al, al ; Look for the zero at the end
repne scasb
pushf ; Remember the flags
sub ecx, edx
neg ecx ; Some or all of the chunk
sub edi, ecx ; Step back
mov eax, [c] ; The character to look for
repne scasb
je .found
popf ; Did we find the end of string earlier?
jne .next ; No, try again
xor eax, eax ; Return NULL
pop edi
ret
.found:
pop eax ; Get rid of those flags
lea eax, [edi-1] ; Address of byte found
pop edi
ret
 
endp
 
 
proc strrchr stdcall, s:dword, c:dword
push edi
mov edi, [s] ; edi = string
mov ecx, -1
xor al, al
cld
repne scasb ; Look for the end of the string
not ecx ; -1 - ecx = Length of the string + null
dec edi ; Put edi back on the zero byte
mov eax, [c] ; The character to look for
std ; Downwards search
repne scasb
cld ; Direction bit back to default
jne .fail
lea eax, [edi+1] ; Found it
pop edi
ret
.fail:
xor eax, eax ; Not there
pop edi
ret
endp
 
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/peload.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/conf_lib-sp.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/conf_lib.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/export.inc
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
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/malloc.inc
0,0 → 1,1035
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
; Small heap based on malloc/free/realloc written by Doug Lea
; Version 2.8.3 Thu Sep 22 11:16:15 2005 Doug Lea (dl at gee)
; Source ftp://gee.cs.oswego.edu/pub/misc/malloc.c
; License http://creativecommons.org/licenses/publicdomain.
 
 
; eax= size
 
; temp
; esi= nb
; ebx= idx
;
align 4
malloc:
push ebx esi
 
; nb = ((size+7)&~7)+8;
 
mov esi, eax ;size
add esi, 7
and esi, -8
add esi, 8
 
mov ecx, mst.mutex
call mutex_lock
 
cmp esi, 256
jae .large
 
mov ecx, esi
shr ecx, 3
or eax, -1
shl eax, cl
and eax, [mst.smallmap]
jz .small
 
push ebp
push edi
 
bsf eax, eax
mov ebx, eax
 
; psize= idx<<3;
; B = &ms.smallbins[idx];
; p = B->fd;
; F = p->fd;
; rsize= psize-nb;
 
lea ebp, [eax*8] ;ebp= psize
shl eax, 4
lea edi, [mst.smallbins+eax] ;edi= B
mov edx, [edi+8] ;edx= p
mov eax, [edx+8] ;eax= F
mov ecx, ebp
sub ecx, esi ;ecx= rsize
 
; if (B == F)
cmp edi, eax
jne @F
 
btr [mst.smallmap], ebx
@@:
 
; B->fd = F;
; F->bk = B;
; if(rsize<16)
 
cmp ecx, 16
mov [edi+8], eax
mov [eax+12], edi
jae .split
 
; p->head = psize|PINUSE_BIT|CINUSE_BIT;
; (p + psize)->head |= PINUSE_BIT;
 
lea eax, [edx+8]
or dword [edx+ebp+4], 1
 
or ebp, 3
mov [edx+4], ebp
 
pop edi
pop ebp
.done:
mov esi, eax
mov ecx, mst.mutex
call mutex_unlock
mov eax, esi
pop esi ebx
ret
 
.split:
lea ebx, [edx+8] ;ebx=mem
 
; r = chunk_plus_offset(p, nb);
; p->head = nb|PINUSE_BIT|CINUSE_BIT;
; r->head = rsize|PINUSE_BIT;
 
lea eax, [edx+esi] ;eax= r
or esi, 3
mov [edx+4], esi
 
mov edx, ecx
or edx, 1
mov [eax+4], edx
 
; (r + rsize)->prev_foot = rsize;
 
mov [eax+ecx], ecx
 
; I = rsize>>3;
 
shr ecx, 3
 
; ms.smallmap |= 1<< I;
bts [mst.smallmap], ecx
 
; B = &ms.smallbins[I];
 
shl ecx, 4
pop edi
pop ebp
add ecx, mst.smallbins ;ecx= B
 
mov edx, [ecx+8] ; F = B->fd;
mov [ecx+8], eax ; B->fd = r;
mov [edx+12], eax ; F->bk = r;
mov [eax+8], edx ; r->fd = F;
mov [eax+12], ecx ; r->bk = B;
 
mov eax, ebx
jmp .done
 
.small:
 
; if (ms.treemap != 0 && (mem = malloc_small(nb)) != 0)
;;;;;;;;;;; start a change <lrz>
mov eax, [mst.treemap]
test eax, eax
;;;;;;;;;;; end the change <lrz>
; cmp [mst.treemap], 0
jz .from_top
mov eax, esi
call malloc_small
test eax, eax
jz .from_top
jmp .done
 
.large:
 
; if (ms.treemap != 0 && (mem = malloc_large(nb)) != 0)
 
cmp [mst.treemap], 0
je .from_top
 
call malloc_large ;esi= nb
test eax, eax
jne .done
.from_top:
 
; if (nb < ms.topsize)
 
mov eax, [mst.topsize]
cmp esi, eax
jae .fail
 
; rsize = ms.topsize -= nb;
; p = ms.top;
 
mov ecx, [mst.top]
sub eax, esi
mov [mst.topsize], eax
 
; r = ms.top = chunk_plus_offset(p, nb);
; r->head = rsize | PINUSE_BIT;
; p->head = nb |PINUSE_BIT|CINUSE_BIT;
 
lea edx, [ecx+esi]
or eax, 1
mov [mst.top], edx
or esi, 3
mov [edx+4], eax
mov [ecx+4], esi
lea eax, [ecx+8]
jmp .done
 
.fail:
xor eax, eax
jmp .done
 
; param
; eax= mem
align 4
free:
test eax, eax
jz .exit
 
push ebx edi
mov edi, eax
add edi, -8
 
; if(p->head & CINUSE_BIT)
 
test byte [edi+4], 2
je .fail
 
mov ecx, mst.mutex
call mutex_lock
 
; psize = p->head & (~3);
 
mov eax, [edi+4]
push esi
mov esi, eax
and esi, -4
 
; next = chunk_plus_offset(p, psize);
; if(!(p->head & PINUSE_BIT))
 
test al, 1
lea ebx, [esi+edi]
jne .next
 
; prevsize = p->prev_foot;
; prev=p - prevsize;
; psize += prevsize;
; p = prev;
 
mov ecx, [edi] ;ecx= prevsize
add esi, ecx ;esi= psize
sub edi, ecx ;edi= p
 
; if (prevsize < 256)
 
cmp ecx, 256
jae .unlink_large
 
mov eax, [edi+8] ;F = p->fd;
mov edx, [edi+12] ;B = p->bk;
 
; if (F == B)
; ms.smallmap &= ~(1<< I);
shr ecx, 3
cmp eax, edx
jne @F
btr [mst.smallmap], ecx
@@:
mov [eax+12], edx ;F->bk = B;
mov [edx+8], eax ;B->fd = F
jmp .next
.unlink_large:
mov edx, edi
call unlink_large_chunk
.next:
 
; if(next->head & PINUSE_BIT)
 
mov eax, [ebx+4]
test al, 1
jz .fail2
 
; if (! (next->head & CINUSE_BIT))
 
test al, 2
jnz .fix_next
 
; if (next == ms.top)
 
cmp ebx, [mst.top]
jne @F
 
; tsize = ms.topsize += psize;
 
mov eax, [mst.topsize]
add eax, esi
mov [mst.topsize], eax
 
; ms.top = p;
; p->head = tsize | PINUSE_BIT;
 
or eax, 1
mov [mst.top], edi
mov [edi+4], eax
.fail2:
mov esi, eax
mov ecx, mst.mutex
call mutex_unlock
mov eax, esi
pop esi
.fail:
pop edi ebx
.exit:
ret
 
@@:
 
; nsize = next->head & ~INUSE_BITS;
 
and eax, -4
add esi, eax ;psize += nsize;
 
; if (nsize < 256)
 
cmp eax, 256
jae .unl_large
 
mov edx, [ebx+8] ;F = next->fd
mov ebx, [ebx+12] ;B = next->bk
 
; if (F == B)
 
cmp edx, ebx
jne @F
mov ecx, eax
shr ecx, 3
btr [mst.smallmap], ecx
@@:
mov [edx+12], ebx ;F->bk = B
 
; p->head = psize|PINUSE_BIT;
 
mov ecx, esi
mov [ebx+8], edx
or ecx, 1
mov [edi+4], ecx
 
; (p+psize)->prev_foot = psize;
 
mov [esi+edi], esi
 
; insert_chunk(p,psize);
 
mov eax, esi
mov ecx, edi
call insert_chunk
jmp .fail2
.unl_large:
 
; unlink_large_chunk((tchunkptr)next);
 
mov edx, ebx
call unlink_large_chunk
; p->head = psize|PINUSE_BIT;
 
mov ecx, esi
or ecx, 1
mov [edi+4], ecx
 
; (p+psize)->prev_foot = psize;
 
mov [esi+edi], esi
 
; insert_chunk(p,psize);
 
mov eax, esi
mov ecx, edi
call insert_chunk
jmp .fail2
.fix_next:
 
; (p+psize)->prev_foot = psize;
; next->head &= ~PINUSE_BIT;
; p->head = psize|PINUSE_BIT;
 
and eax, -2
mov edx, esi
mov [ebx+4], eax
or edx, 1
mov [edi+4], edx
 
; (p+psize)->prev_foot = psize;
 
mov [esi+edi], esi
; insert_chunk(p,psize);
 
mov eax, esi
mov ecx, edi
call insert_chunk
jmp .fail2
 
; param
; ecx = chunk
; eax = size
 
insert_chunk:
 
cmp eax, 256
push esi
mov esi, ecx
jae .large
 
; I = S>>3;
; ms.smallmap |= 1<< I;
 
shr eax, 3
bts [mst.smallmap], eax
 
; B = &ms.smallbins[I];
 
shl eax, 4
add eax, mst.smallbins
mov edx, [eax+8] ;F = B->fd
mov [eax+8], esi ;B->fd = P
mov [edx+12], esi ;F->bk = P
mov [esi+8], edx ;P->fd = F
mov [esi+12], eax ;P->bk = B
pop esi
ret
.large:
mov ebx, eax
call insert_large_chunk
pop esi
ret
 
 
; param
; esi= chunk
; ebx= size
 
insert_large_chunk:
 
; I = compute_tree_index(S);
 
mov edx, ebx
shr edx, 8
bsr eax, edx
lea ecx, [eax+7]
mov edx, ebx
shr edx, cl
and edx, 1
lea ecx, [edx+eax*2]
 
; X->index = I;
mov dword [esi+28], ecx
 
; X->child[0] = X->child[1] = 0;
and dword [esi+20], 0
and dword [esi+16], 0
 
; H = &ms.treebins[I];
 
mov eax, ecx
lea edx, [mst.treebins+eax*4]
 
; if (!(ms.treemap & 1<<I))
bt [mst.treemap], ecx
jc .tree
 
; ms.treemap |= 1<<I;
bts [mst.treemap], ecx
; *H = X;
mov dword [edx], esi
jmp .done
.tree:
 
; T = *H;
mov edx, [edx]
 
; K = S << leftshift_for_tree_index(I);
mov eax, ecx
shr eax, 1
sub ecx, 31
mov edi, 37
sub edi, eax
neg ecx
sbb ecx, ecx
and ecx, edi
mov eax, ebx
shl eax, cl ;eax= K
 
jmp .loop
.not_eq_size:
 
; C = &(T->child[(K >> 31) & 1]);
mov ecx, eax
shr ecx, 31
lea ecx, [edx+ecx*4+16]
 
; K <<= 1;
; if (*C != 0)
mov edi, [ecx]
add eax, eax
test edi, edi
jz .insert_child
 
; T = *C;
mov edx, edi
.loop:
 
; for (;;)
; if ((T->head & ~INUSE_BITS) != S)
 
mov ecx, [edx+4]
and ecx, not 3
cmp ecx, ebx
jne .not_eq_size
 
; F = T->fd;
mov eax, [edx+8]
 
; T->fd = F->bk = X;
mov [eax+12], esi
mov [edx+8], esi
 
; X->fd = F;
; X->bk = T;
; X->parent = 0;
 
and dword [esi+24], 0
mov [esi+8], eax
mov [esi+12], edx
ret
.insert_child:
 
; *C = X;
mov [ecx], esi
.done:
 
; X->parent = T;
mov [esi+24], edx
 
; X->fd = X->bk = X;
mov [esi+12], esi
mov [esi+8], esi
ret
 
 
; param
; edx= chunk
 
unlink_large_chunk:
 
mov eax, [edx+12]
cmp eax, edx
push edi
mov edi, [edx+24]
je @F
 
mov ecx, [edx+8] ;F = X->fd
mov [ecx+12], eax ;F->bk = R;
mov [eax+8], ecx ;R->fd = F
jmp .parent
@@:
mov eax, [edx+20]
test eax, eax
push esi
lea esi, [edx+20]
jne .loop
 
mov eax, [edx+16]
test eax, eax
lea esi, [edx+16]
je .l2
.loop:
cmp dword [eax+20], 0
lea ecx, [eax+20]
jne @F
 
cmp dword [eax+16], 0
lea ecx, [eax+16]
je .l1
@@:
mov eax, [ecx]
mov esi, ecx
jmp .loop
.l1:
mov dword [esi], 0
.l2:
pop esi
.parent:
test edi, edi
je .done
 
mov ecx, [edx+28]
cmp edx, [mst.treebins+ecx*4]
lea ecx, [mst.treebins+ecx*4]
jne .l3
 
test eax, eax
mov [ecx], eax
jne .l5
 
mov ecx, [edx+28]
btr [mst.treemap], ecx
pop edi
ret
 
.l3:
cmp [edi+16], edx
jne @F
 
mov [edi+16], eax
jmp .l4
 
@@:
mov [edi+20], eax
 
.l4:
test eax, eax
je .done
 
.l5:
mov [eax+24], edi
mov ecx, [edx+16]
test ecx, ecx
je .l6
 
mov [eax+16], ecx
mov [ecx+24], eax
 
.l6:
mov edx, [edx+20]
test edx, edx
je .done
 
mov [eax+20], edx
mov [edx+24], eax
 
.done:
pop edi
ret
 
; param
; esi= nb
 
malloc_small:
push ebp
mov ebp, esi
 
push edi
 
bsf eax, [mst.treemap]
mov ecx, [mst.treebins+eax*4]
 
; rsize = (t->head & ~INUSE_BITS) - nb;
 
mov edi, [ecx+4]
and edi, -4
sub edi, esi
 
.loop:
mov ebx, ecx
 
.loop_1:
 
; while ((t = leftmost_child(t)) != 0)
 
mov eax, [ecx+16]
test eax, eax
jz @F
mov ecx, eax
jmp .l1
 
@@:
mov ecx, [ecx+20]
 
.l1:
test ecx, ecx
jz .unlink
 
; trem = (t->head & ~INUSE_BITS) - nb;
 
mov eax, [ecx+4]
and eax, -4
sub eax, ebp
 
; if (trem < rsize)
 
cmp eax, edi
jae .loop_1
 
; rsize = trem;
 
mov edi, eax
jmp .loop
.unlink:
 
 
; r = chunk_plus_offset((mchunkptr)v, nb);
; unlink_large_chunk(v);
 
mov edx, ebx
lea esi, [ebx+ebp]
call unlink_large_chunk
 
; if (rsize < 16)
 
cmp edi, 16
jae .split
 
; v->head = (rsize + nb)|PINUSE_BIT|CINUSE_BIT;
 
lea ecx, [edi+ebp]
 
; (v+rsize + nb)->head |= PINUSE_BIT;
 
add edi, ebx
lea eax, [edi+ebp+4]
pop edi
or ecx, 3
mov [ebx+4], ecx
or dword [eax], 1
pop ebp
 
lea eax, [ebx+8]
ret
 
.split:
 
; v->head = nb|PINUSE_BIT|CINUSE_BIT;
; r->head = rsize|PINUSE_BIT;
; (r+rsize)->prev_foot = rsize;
 
or ebp, 3
mov edx, edi
or edx, 1
 
cmp edi, 256
mov [ebx+4], ebp
mov [esi+4], edx
mov [esi+edi], edi
jae .large
 
shr edi, 3
bts [mst.smallmap], edi
 
mov eax, edi
shl eax, 4
add eax, mst.smallbins
 
mov edx, [eax+8]
mov [eax+8], esi
mov [edx+12], esi
pop edi
mov [esi+12], eax
mov [esi+8], edx
pop ebp
lea eax, [ebx+8]
ret
 
.large:
lea eax, [ebx+8]
push eax
mov ebx, edi
call insert_large_chunk
pop eax
pop edi
pop ebp
ret
 
 
; param
; esi= nb
 
malloc_large:
.idx equ esp+4
.rst equ esp
 
push ebp
push esi
push edi
sub esp, 8
; v = 0;
; rsize = -nb;
 
mov edi, esi
mov ebx, esi
xor ebp, ebp
neg edi
 
; idx = compute_tree_index(nb);
 
mov edx, esi
shr edx, 8
bsr eax, edx
lea ecx, [eax+7]
shr esi, cl
and esi, 1
lea ecx, [esi+eax*2]
mov [.idx], ecx
 
; if ((t = ms.treebins[idx]) != 0)
 
mov eax, [mst.treebins+ecx*4]
test eax, eax
jz .l3
 
; sizebits = nb << leftshift_for_tree_index(idx);
 
cmp ecx, 31
jne @F
xor ecx, ecx
jmp .l1
 
@@:
mov edx, ecx
shr edx, 1
mov ecx, 37
sub ecx, edx
 
.l1:
mov edx, ebx
shl edx, cl
 
; rst = 0;
mov [.rst], ebp
 
.loop:
 
; trem = (t->head & ~INUSE_BITS) - nb;
 
mov ecx, [eax+4]
and ecx, -4
sub ecx, ebx
 
; if (trem < rsize)
 
cmp ecx, edi
jae @F
; v = t;
; if ((rsize = trem) == 0)
 
test ecx, ecx
mov ebp, eax
mov edi, ecx
je .l2
 
@@:
 
; rt = t->child[1];
 
mov ecx, [eax+20]
 
; t = t->child[(sizebits >> 31) & 1];
 
mov esi, edx
shr esi, 31
 
; if (rt != 0 && rt != t)
 
test ecx, ecx
mov eax, [eax+esi*4+16]
jz @F
cmp ecx, eax
jz @F
 
; rst = rt;
mov [.rst], ecx
 
@@:
; if (t == 0)
 
test eax, eax
jz @F
 
; sizebits <<= 1;
 
add edx, edx
jmp .loop
 
@@:
; t = rst;
mov eax, [.rst]
 
.l2:
; if (t == 0 && v == 0)
 
test eax, eax
jne .l4
test ebp, ebp
jne .l7
mov ecx, [.idx]
 
.l3:
 
; leftbits = (-1<<idx) & ms.treemap;
; if (leftbits != 0)
 
or edx, -1
shl edx, cl
and edx, [mst.treemap]
jz @F
 
bsf eax, edx
; t = ms.treebins[i];
mov eax, [mst.treebins+eax*4]
 
@@:
 
; while (t != 0)
test eax, eax
jz .l5
 
.l4:
 
; trem = (t->head & ~INUSE_BITS) - nb;
 
mov ecx, [eax+4]
and ecx, -4
sub ecx, ebx
 
; if (trem < rsize)
 
cmp ecx, edi
jae @F
; rsize = trem;
 
mov edi, ecx
; v = t;
mov ebp, eax
 
@@:
 
; t = leftmost_child(t);
 
mov ecx, [eax+16]
test ecx, ecx
je @F
mov eax, ecx
jmp .l6
 
@@:
mov eax, [eax+20]
 
.l6:
 
; while (t != 0)
 
test eax, eax
jne .l4
 
.l5:
 
; if (v != 0)
 
test ebp, ebp
jz .done
 
.l7:
 
; r = chunk_plus_offset((mchunkptr)v, nb);
; unlink_large_chunk(v);
 
mov edx, ebp
lea esi, [ebx+ebp]
call unlink_large_chunk
 
; if (rsize < 16)
 
cmp edi, 16
jae .large
 
; v->head = (rsize + nb)|PINUSE_BIT|CINUSE_BIT;
 
lea ecx, [edi+ebx]
 
; (v+rsize + nb)->head |= PINUSE_BIT;
 
add edi, ebp
lea eax, [edi+ebx+4]
or ecx, 3
mov [ebp+4], ecx
or dword [eax], 1
lea eax, [ebp+8]
add esp, 8
pop edi
pop esi
pop ebp
ret
 
.large:
 
; v->head = nb|PINUSE_BIT|CINUSE_BIT;
; r->head = rsize|PINUSE_BIT;
 
mov edx, edi
or ebx, 3
mov [ebp+4], ebx
or edx, 1
mov [esi+4], edx
 
; (r+rsize)->prev_foot = rsize;
; insert_large_chunk((tchunkptr)r, rsize);
 
mov [esi+edi], edi
mov eax, edi
mov ecx, esi
call insert_chunk
 
lea eax, [ebp+8]
add esp, 8
pop edi
pop esi
pop ebp
ret
 
.done:
add esp, 8
pop edi
pop esi
pop ebp
xor eax, eax
ret
 
init_malloc:
 
stdcall kernel_alloc, 0x40000
 
mov [mst.top], eax
mov [mst.topsize], 128*1024
mov dword [eax+4], (128*1024) or 1
mov eax, mst.smallbins
 
@@:
mov [eax+8], eax
mov [eax+12], eax
add eax, 16
cmp eax, mst.smallbins+512
jb @B
 
mov ecx, mst.mutex
call mutex_init
 
ret
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core/sys32-sp.inc
0,0 → 1,14
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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
 
msg_sel_ker cp850 "núcleo", 0
msg_sel_app cp850 "aplicación", 0
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/core
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/fs/fs_lfn.inc
0,0 → 1,794
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
ERROR_SUCCESS = 0
ERROR_DISK_BASE = 1
ERROR_UNSUPPORTED_FS = 2
ERROR_UNKNOWN_FS = 3
ERROR_PARTITION = 4
ERROR_FILE_NOT_FOUND = 5
ERROR_END_OF_FILE = 6
ERROR_MEMORY_POINTER = 7
ERROR_DISK_FULL = 8
ERROR_FS_FAIL = 9
ERROR_ACCESS_DENIED = 10
ERROR_DEVICE = 11
 
maxPathLength = 1000h
 
image_of_eax EQU esp+32
image_of_ebx EQU esp+20
 
; ; System function 70 security check
; align 4
; proc file_system_is_operation_safe stdcall, inf_struct_ptr: dword
; ; in:
; ; inf_struct_ptr = pointer to information structure was given to sysfn70
; ; out: ZF = 1 if operation is safe
; ; ZF = 0 if operation can cause kernel crash
; push ebx ecx edx
; xor ecx, ecx ; ecx - length of target buffer
 
; mov ebx, [inf_struct_ptr]
; mov edx, [ebx + 16] ; base of target buffer
 
; cmp dword [ebx], 0 ; if 70.0
; jnz .case1
; mov ecx, dword [ebx + 12]
; jmp .end_switch
 
; .case1:
; cmp dword [ebx], 1 ; if 70.1
; jnz .case2_3
; ;mov ecx, 32
; cmp dword [ebx + 8], 1 ; check encoding
; jbe .case1_304 ; if encdoing <= 1 i.e cpp866
; mov ecx, 560 ; if unicode then bdvk block len is 560 bytes
; jmp .case1_end
; .case1_304:
; mov ecx, 304 ; if cp866 then bdvk block len is 304 bytes
; .case1_end:
; imul ecx, dword [ebx + 12] ; multiply bdvk length by their count
; add ecx, 32 ; add result header len
; jmp .end_switch
 
; .case2_3:
; cmp dword [ebx], 3
; ja .case5 ; if subfn > 3
; mov ecx, dword [ebx + 12]
; jmp .end_switch
 
; .case5:
; cmp dword [ebx], 5
; jnz .case6
; mov ecx, 40
; jmp .end_switch
 
; .case6:
; cmp dword [ebx], 6
; jnz .switch_none
; mov ecx, 32
; jmp .end_switch
 
; .switch_none:
; mov ecx, 1
; test ecx, ecx
; jmp .ret
; .end_switch:
; ;;
; stdcall is_region_userspace, edx, ecx
; .ret:
; pop edx ecx ebx
; ret
; endp
 
; syscall_fileSystemUnicode: ; with user pointer correctness checking
; ; in: ebx -> f.80 parameter structure
; stdcall file_system_is_operation_safe, ebx
; jz @f
 
; DEBUGF 1, "sysfn80 addr error\n"
; mov dword [image_of_eax], ERROR_MEMORY_POINTER
; ret
; @@:
; jmp fileSystemUnicode
 
; temporarily commented out cause acpi driver (drivers/devman) uses sysfn70 via 0x40
; so because drivers it kernel space, pointer checking fails
; TODO solution: add filesystem functions without pointer checking to kernel exports
; and make the driver use them, not int 0x40
; syscall_fileSystemUnicode commented out for the same reason
; syscall_file_system_lfn: ; with user pointer correctness checking
; ; in: ebx -> f.70 parameter structure
; stdcall file_system_is_operation_safe, ebx
; jz @f
 
; DEBUGF 1, "sysfn70 addr error\n"
; mov dword [image_of_eax], ERROR_MEMORY_POINTER
; ret
; @@:
; jmp file_system_lfn
 
 
; System function 70
 
file_system_lfn_protected:
pushad
call protect_from_terminate
call file_system_lfn
call unprotect_from_terminate
popad
mov [image_of_eax], eax
mov [image_of_ebx], ebx
ret
 
fileSystemUnicode:
; in: ebx -> f.80 parameter structure
mov edi, [ebx+20]
mov esi, [ebx+24]
jmp @f
 
file_system_lfn:
; in: ebx -> f.70 parameter structure
xor edi, edi
lea esi, [ebx+20]
cmp byte [esi], 0
jnz @f
mov esi, [ebx+21]
@@:
cmp word [esi], '/'
jnz @f
cmp edi, 2
jnz .rootdir
cmp dword[esi], '/'
jz .rootdir
@@:
stdcall kernel_alloc, maxPathLength
push eax ebx
xchg eax, edi
call getFullPath
pop ebx ebp
test eax, eax
jz .notfound
cmp dword[ebx], 7 ; start application
jnz @f
mov edx, [ebx+4]
mov ecx, [ebx+8]
mov ebx, ebp
call fs_execute
mov [image_of_eax], eax
ret
 
@@:
lea esi, [ebp+2]
mov ax, [esi]
or ax, 2020h
cmp ax, 'cd'
jz .CD
call dyndisk_handler ; not returns if success
.notfound:
stdcall kernel_free, ebp
mov dword[image_of_eax], ERROR_FILE_NOT_FOUND
ret
 
.CD:
add esi, 2
xor eax, eax
lodsb ; disk number
sub eax, '0'
cmp eax, 10
jnc .notfound
mov edi, eax
lodsb
test eax, eax
jz .maindir
cmp al, '/'
jnz .notfound
lodsb ; partition number
test eax, eax
jz .maindir
cmp al, '1'
jnz .notfound
cmp byte [esi], '/'
jnz @f
inc esi
@@:
call reserve_cd
mov eax, edi
bt eax, 0
setc [DiskNumber]
bt eax, 1
setc [ChannelNumber]
inc [ChannelNumber]
inc eax
mov [cdpos], eax
call reserve_cd_channel
mov eax, edi
not eax
and eax, 3
shl eax, 1
inc eax
shr edi, 2
mov dword[image_of_eax], ERROR_FILE_NOT_FOUND
bt [edi*5+DRIVE_DATA+1], ax
jnc @f
mov ecx, [ebx+12]
mov edx, [ebx+16]
mov eax, [ebx]
mov dword[image_of_eax], ERROR_UNSUPPORTED_FS
cmp eax, fs_NumCdServices
jae @f
add ebx, 4
push ebp
call dword[fs_CdServices + eax*4]
pop ebp
mov [image_of_eax], eax
mov [image_of_ebx], ebx
@@:
call free_cd_channel
and [cd_status], 0
stdcall kernel_free, ebp
ret
 
.nextCD:
test eax, eax ; partition number
jnz @f
inc eax ; /cdX/1
ret
 
@@:
stc
ret
 
.maindir: ; list partitions
mov esi, .nextCD
xor ecx, ecx
.maindir_noesi: ; backjump from dyndisk_handler
push ebp
mov ebp, ecx
call kernel_free
mov edi, [ebx+16] ; buffer
cmp byte [ebx], 5
jz .deviceInfo
cmp byte [ebx], 1 ; read folder?
jnz .access_denied
push ebp
pushd [ebx+4] ; first block
mov ebp, [ebx+12] ; the number of blocks to read
mov ebx, [ebx+8] ; flags
mov ecx, 32/4
mov edx, edi
xor eax, eax
rep stosd
mov byte [edx], 1 ; version
.maindir_loop:
call esi
jc .maindir_done
inc dword[edx+8]
dec dword[esp]
jns .maindir_loop
dec ebp
js .maindir_loop
inc dword[edx+4]
mov dword[edi], 16 ; attributes: folder
mov dword[edi+4], ebx ; name encoding
push eax
mov ecx, 32/4
add edi, 8
xor eax, eax
rep stosd
pop eax
push eax edx edi
; convert number in eax to decimal string
push -'0'
mov ecx, 10
@@:
xor edx, edx
div ecx
push edx
test eax, eax
jnz @b
cmp ebx, 2
jz .uni
@@:
pop eax
add eax, '0'
stosb
test eax, eax
jnz @b
pop edi edx eax
cmp ebx, 3
jz @f
add edi, 264
jmp .maindir_loop
 
.uni:
pop eax
add eax, '0'
stosw
test eax, eax
jnz .uni
pop edi edx eax
@@:
add edi, 520
jmp .maindir_loop
 
.maindir_done:
pop eax eax
mov ebx, [edx+4]
xor eax, eax
dec ebp
js @f
mov al, ERROR_END_OF_FILE
@@:
mov [image_of_eax], eax
mov [image_of_ebx], ebx
ret
 
.access_denied:
mov dword[image_of_eax], ERROR_ACCESS_DENIED
ret
 
.deviceInfo:
test ebp, ebp
jz @f
mov eax, dword[ebp+DISK.MediaInfo.Capacity]
mov edx, dword[ebp+DISK.MediaInfo.Capacity+4]
shld edx, eax, 9
shl eax, 9
mov [edi+36], edx
mov [edi+32], eax
@@:
and dword[image_of_eax], 0
ret
 
.rootdir: ; / - virtual root folder
cmp byte [ebx], 5
jz @b
cmp byte [ebx], 1 ; read folder?
jnz .access_denied
mov ebp, [ebx+12] ; number of blocks
mov edx, [ebx+16] ; return area
push dword[ebx+4] ; first block
mov ebx, [ebx+8] ; flags
mov ecx, 32/4
mov edi, edx
xor eax, eax
rep stosd
mov byte [edx], 1 ; version
sub esp, 16
.rootdir_loop:
push edi
lea edi, [esp+4]
call dyndisk_enum_root
pop edi
test eax, eax
jz .rootdirCD
inc dword[edx+8]
dec dword[esp+16]
jns .rootdir_loop
dec ebp
js .rootdir_loop
inc dword[edx+4]
mov dword[edi], 16 ; attributes: folder
mov dword[edi+4], ebx ; name encoding
push eax
mov ecx, 32/4
add edi, 8
xor eax, eax
rep stosd
push edi
lea esi, [esp+8]
cmp ebx, 2
jz .uni2
@@:
lodsb
stosb
test eax, eax
jnz @b
pop edi eax
cmp ebx, 3
jz @f
add edi, 264
jmp .rootdir_loop
 
.uni2:
lodsb
stosw
test eax, eax
jnz .uni2
pop edi eax
@@:
add edi, 520
jmp .rootdir_loop
 
.rootdirCD:
add esp, 16
or esi, -1
.rootdirCD_loop:
inc esi
cmp esi, 10
jnc .rootdir_done
mov eax, esi
not eax
and eax, 3
shl eax, 1
inc eax
mov ecx, esi
shr ecx, 2
bt [ecx*5+DRIVE_DATA+1], ax
jnc .rootdirCD_loop
inc dword[edx+8]
dec dword[esp]
jns .rootdirCD_loop
dec ebp
js .rootdirCD_loop
inc dword[edx+4]
mov dword[edi], 16 ; attributes: folder
mov dword[edi+4], ebx ; name encoding
mov ecx, 32/4
add edi, 8
xor eax, eax
rep stosd
mov eax, esi
add eax, '0'
cmp ebx, 1
jz @f
mov word [edi], 'cd'
mov [edi+2], ax
add edi, 264
jmp .rootdirCD_loop
 
@@:
mov dword[edi], 640063h
mov [edi+4], eax
add edi, 520
jmp .rootdirCD_loop
 
.rootdir_done:
pop eax
mov ebx, [edx+4]
xor eax, eax
dec ebp
js @f
mov al, ERROR_END_OF_FILE
@@:
mov [image_of_eax], eax
mov [image_of_ebx], ebx
ret
 
;-----------------------------------------------------------------------------
process_replace_file_name:
; in: [esi] = virtual path
; out: [esi]+[ebp] = physical path
xor edi, edi
xor ebp, ebp
.loop:
cmp edi, [full_file_name_table.size]
jae .notfound
push esi edi
shl edi, 7
add edi, [full_file_name_table]
@@:
cmp byte [edi], 0
jz .dest_done
lodsb
test al, al
jz .cont
scasb
jz @b
or al, 20h
cmp [edi-1], al
jz @b
.cont:
pop edi esi
inc edi
jmp .loop
 
.dest_done:
cmp byte [esi], 0
jz .found
cmp byte [esi], '/'
jnz .cont
.found:
pop edi eax
shl edi, 7
add edi, [full_file_name_table]
mov ebp, esi
lea esi, [edi+64]
.notfound:
ret
 
;-----------------------------------------------------------------------------
uglobal
addDirSeal db ?
endg
 
sys_current_directory: ; sysfunction 30
mov eax, [current_slot]
mov edi, [eax+APPDATA.cur_dir]
xor eax, eax
dec ebx
jz .set
dec ebx
jz .get
dec ebx
jz .mount_additional_directory
mov eax, edx
dec ebx
jz .set
mov eax, esi
dec ebx
jz .get
@@:
ret
 
.mount_additional_directory:
; in: ecx -> dir name+dir path (128)
mov al, 1
xchg [addDirSeal], al
test al, al
jnz @b
mov esi, ecx
mov edi, sysdir_name1
mov ecx, 64
rep movsb ; copying fake directory name
mov byte [edi-1], 0
mov cl, 63
call cp866toUTF8_string
mov byte [edi], 0
mov [full_file_name_table.size], 2
ret
 
.get:
; in: ecx -> buffer, edx = length, eax = encoding
stdcall is_region_userspace, ecx, edx
jz @f
 
; if illegal buffer given
xor edx, edx
jmp .ret
@@:
 
mov esi, edi
inc esi
mov edi, ecx
cmp edx, maxPathLength
jc @f
mov edx, maxPathLength
@@:
mov ecx, edx
jecxz .ret
cmp eax, 2
jz .get16
cmp eax, 3
jz .get8
@@:
dec ecx
js @f
call utf8to16
call uni2ansi_char
stosb
test al, al
jnz @b
sub edx, ecx
@@:
mov byte [edi-1], 0
.ret:
mov [esp+32], edx
ret
 
.get8:
push edi
mov edi, esi
xor eax, eax
repnz scasb
sub edx, ecx
mov ecx, edx
pop edi
rep movsb
jmp @b
 
.get16:
shr ecx, 1
shr edx, 1
@@:
dec ecx
js @f
call utf8to16
stosw
test ax, ax
jnz @b
sub edx, ecx
@@:
shl edx, 1
mov word [edi-2], 0
jmp .ret
 
.set:
mov esi, ecx
getFullPath:
; in: esi -> file path, eax = string encoding, edi -> destination
; out: UTF-8 string (with marker), eax = length, 0 -> error
test eax, eax
jnz @f
cmp byte [esi], 4
jnc @f
cmp byte [esi], 0
jz @f
lodsb
@@:
cmp byte [esi], '/'
jnz .relative
cmp eax, 2
jnz @f
cmp word [esi], '/'
jnz .relative
inc esi
inc esi
jmp .start
 
@@:
inc esi
cmp byte [esi], 4
jnc .start
lodsb
cmp byte [esi], '/'
jnz .start
inc esi
.start:
push eax edi
call process_replace_file_name
mov edi, [esp]
mov ecx, maxPathLength
mov al, 3
mov ah, '/'
stosw
sub ecx, 2
test ebp, ebp
jz .absolute
@@:
lodsb
stosb
dec ecx
test al, al
jnz @b
mov esi, ebp
dec edi
.absolute:
cmp byte [esp+4], 2
jz .utf16
cmp byte [esp+4], 3
jz .utf8
call cp866toUTF8_string
jns .end
jmp .fail
 
.utf8:
dec ecx
js .fail
lodsb
stosb
test al, al
jz .end
jmp .utf8
 
.utf16:
call UTF16to8_string
jns .end
.fail:
mov byte [edi], 0
pop eax eax
xor eax, eax
ret
 
.relative:
push eax edi
mov ebx, esi
mov edi, [current_slot]
mov edi, [edi+APPDATA.cur_dir]
mov edx, edi
mov ecx, maxPathLength
xor eax, eax
repnz scasb
mov esi, edi
mov edi, [esp]
jecxz .fail
cmp byte [ebx], 0
jz .set_ok
dec esi
cmp edx, edi ; is destination equal to cur_dir?
mov edi, esi
jz @f
mov edi, [esp]
mov ecx, esi
sub ecx, edx
mov esi, edx
mov edx, edi
rep movsb
@@:
mov byte [edi], '/'
inc edi
mov esi, ebx
mov ecx, edx
add ecx, maxPathLength
sub ecx, edi
jmp .absolute
 
.set_ok:
cmp edx, edi ; is destination equal to cur_dir?
jz @f
mov ecx, esi
sub ecx, edx
mov esi, edx
rep movsb
@@:
pop eax
sub edi, eax
pop eax
mov eax, edi
ret
 
.end:
or ecx, -1
mov edi, [esp]
xor eax, eax
push edi
repnz scasb
not ecx
pop edi
.parse:
mov al, '/'
repnz scasb
jecxz @b
cmp byte [edi], '.'
jnz .parse
mov esi, edi
@@:
lodsw
sub ecx, 2
cmp ax, './'
jz @b
cmp ax, '..'
jnz @f
cmp byte [esi], '/'
jnz @f
mov edx, ecx
mov ecx, edi
sub ecx, [esp]
sub ecx, 2
jc .fail
sub edi, 2
lodsb
dec edx
std
repnz scasb
cld
add edi, 2
mov ecx, edx
jmp @b
 
@@:
sub esi, 2
add ecx, 2
cmp esi, edi
jz .parse
push edi ecx
rep movsb
pop ecx edi
jmp .parse
 
include "parse_fn.inc"
include "fs_common.inc"
include "iso9660.inc" ; read for CD filesystem
include "fat.inc"
include "ntfs.inc"
include "ext.inc"
include "xfs.asm"
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/iso9660.inc
0,0 → 1,740
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; CD external functions
; in:
; esi -> path string in UTF-8
; ebx -> parameter structure +4
; ecx = bytes to read
; edx -> buffer
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
fs_CdServices:
dd fs_CdRead
dd fs_CdReadFolder
dd fs_NotImplemented
dd fs_NotImplemented
dd fs_NotImplemented
dd fs_CdGetFileInfo
dd fs_NotImplemented
dd 0
dd fs_NotImplemented
dd fs_NotImplemented
fs_NumCdServices = ($ - fs_CdServices)/4
endg
 
uglobal
align 4
cd_current_pointer_of_input dd 0
cd_current_pointer_of_input_2 dd 0
cd_mem_location dd 0
cd_counter_block dd 0
cd_status dd 0
endg
 
;-----------------------------------------------------------------------------
fs_NotImplemented:
movi eax, ERROR_UNSUPPORTED_FS
ret
;-----------------------------------------------------------------------------
reserve_cd:
cli
cmp [cd_status], 0
je reserve_ok2
 
sti
call change_task
jmp reserve_cd
;-----------------------------------------------------------------------------
reserve_ok2:
push eax
mov eax, [current_slot_idx]
shl eax, 5
mov eax, [eax+TASK_TABLE+TASKDATA.pid]
mov [cd_status], eax
pop eax
sti
ret
;-----------------------------------------------------------------------------
reserve_cd_channel:
pushad
mov eax, [cdpos]
dec eax
shr eax, 2
 
test eax, eax
jnz .1
 
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel1_mutex
jmp .mutex_lock
;--------------------------------------
@@:
mov ecx, ide_channel2_mutex
jmp .mutex_lock
;--------------------------------------
.1:
dec eax
jnz .2
 
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel3_mutex
jmp .mutex_lock
;--------------------------------------
@@:
mov ecx, ide_channel4_mutex
jmp .mutex_lock
;--------------------------------------
.2:
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel5_mutex
jmp .mutex_lock
;--------------------------------------
@@:
mov ecx, ide_channel6_mutex
.mutex_lock:
call mutex_lock
popad
ret
;-----------------------------------------------------------------------------
free_cd_channel:
pushad
mov eax, [cdpos]
dec eax
shr eax, 2
 
test eax, eax
jnz .1
 
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel1_mutex
jmp .mutex_unlock
;--------------------------------------
@@:
mov ecx, ide_channel2_mutex
jmp .mutex_unlock
;--------------------------------------
.1:
dec eax
jnz .2
 
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel3_mutex
jmp .mutex_unlock
;--------------------------------------
@@:
mov ecx, ide_channel4_mutex
jmp .mutex_unlock
;--------------------------------------
.2:
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel5_mutex
jmp .mutex_unlock
;--------------------------------------
@@:
mov ecx, ide_channel6_mutex
.mutex_unlock:
call mutex_unlock
popad
ret
 
;-----------------------------------------------------------------------------
fs_CdRead:
call cd_find_lfn
jc .notFound
mov edi, [cd_current_pointer_of_input]
test byte [edi+25], 10b ; do not allow read directories
jnz .noaccess
test ebx, ebx
jz .l1
cmp dword [ebx+4], 0
jz @f
xor ebx, ebx
movi eax, ERROR_END_OF_FILE
ret
 
.notFound:
cmp [DevErrorCode], 0
jne .noaccess
xor ebx, ebx
movi eax, ERROR_FILE_NOT_FOUND
ret
 
.noaccess_3:
pop eax edx ecx
.noaccess:
xor ebx, ebx
movi eax, ERROR_ACCESS_DENIED
ret
 
@@:
mov ebx, [ebx]
.l1:
push ecx edx 0
mov eax, [edi+10] ; real size of the file section
sub eax, ebx
jb .eof
cmp eax, ecx
jae @f
mov ecx, eax
pop eax
push ERROR_END_OF_FILE
@@:
mov eax, [edi+2]
mov [CDSectorAddress], eax
; now eax=cluster, ebx=position, ecx=count, edx=buffer for data
.new_sector:
test ecx, ecx
jz .done
sub ebx, 2048
jae .next
add ebx, 2048
jnz .incomplete_sector
cmp ecx, 2048
jb .incomplete_sector
; we may read and memmove complete sector
mov [CDDataBuf_pointer], edx
call ReadCDWRetr
cmp [DevErrorCode], 0
jne .noaccess_3
add edx, 2048
sub ecx, 2048
.next:
inc dword [CDSectorAddress]
jmp .new_sector
 
.eof:
pop eax
push ERROR_END_OF_FILE
.done:
mov ebx, edx
pop eax edx ecx
sub ebx, edx
ret
 
.incomplete_sector: ; we must read and memmove incomplete sector
mov [CDDataBuf_pointer], CDDataBuf
call ReadCDWRetr
cmp [DevErrorCode], 0
jne .noaccess_3
push ecx
add ecx, ebx
cmp ecx, 2048
jbe @f
mov ecx, 2048
@@:
sub ecx, ebx
push edi esi ecx
mov edi, edx
lea esi, [CDDataBuf + ebx]
cld
rep movsb
pop ecx esi edi
add edx, ecx
sub [esp], ecx
pop ecx
xor ebx, ebx
jmp .next
 
;-----------------------------------------------------------------------------
fs_CdReadFolder:
push edi
call cd_find_lfn
jnc .found
pop edi
cmp [DevErrorCode], 0
jne .noaccess_1
xor ebx, ebx
mov eax, ERROR_FILE_NOT_FOUND
ret
 
.found:
mov edi, [cd_current_pointer_of_input]
test byte [edi+25], 10b ; do not allow read directories
jnz .found_dir
pop edi
.noaccess_1:
xor ebx, ebx
mov eax, ERROR_ACCESS_DENIED
ret
 
.end_buffer:
pop edx eax
sub eax, 2048 ; directory is over?
ja .read_to_buffer
mov eax, [cd_counter_block]
mov [edx+8], eax
mov eax, [ebx]
sub [edx+4], eax
xor eax, eax
dec ecx
js @f
mov al, ERROR_END_OF_FILE
@@:
pop ecx edi
mov ebx, [edx+4]
ret
 
.found_dir:
mov eax, [edi+2] ; eax=cluster
mov [CDSectorAddress], eax
mov eax, [edi+10] ; directory size
push eax ecx
mov edi, edx
mov ecx, 32/4
xor eax, eax
rep stosd
pop ecx eax
mov byte [edx], 1 ; version
mov [cd_mem_location], edx
add [cd_mem_location], 32
mov [cd_counter_block], dword 0
dec dword [CDSectorAddress]
push ecx
.read_to_buffer:
inc dword [CDSectorAddress]
mov [CDDataBuf_pointer], CDDataBuf
call ReadCDWRetr ; read sector of directory
cmp [DevErrorCode], 0
jne .noaccess_1
mov [cd_current_pointer_of_input_2], CDDataBuf
push eax edx
.get_names_from_buffer:
call cd_get_name
jc .end_buffer
inc dword [cd_counter_block]
mov eax, [cd_counter_block]
cmp [ebx], eax
jae .get_names_from_buffer
test ecx, ecx
jz .get_names_from_buffer
mov edi, [cd_counter_block]
mov [edx+4], edi
dec ecx
mov esi, ebp
call cd_get_parameters_of_file
add edi, 40
mov ax, '.'
cmp dword[ebx+4], 2
jz .utf16
cmp dword[ebx+4], 3
jz .utf8
cmp [cd_counter_block], 2
jbe .parentDirectory
@@:
lodsw
xchg ah, al
call uni2ansi_char
stosb
call .checkForEnd
jc @b
@@:
mov [edi], byte 0
add [cd_mem_location], 304
jmp .get_names_from_buffer
 
.parentDirectory:
stosb
cmp [cd_counter_block], 2
jnz @b
stosb
jmp @b
 
.utf8:
add [cd_mem_location], 256
cmp [cd_counter_block], 2
jbe .parentDirectory
push ecx
mov ecx, 519
@@:
lodsw
xchg ah, al
call UTF16to8
js @f
call .checkForEnd
jc @b
@@:
pop ecx
mov [edi], byte 0
add [cd_mem_location], 304
jmp .get_names_from_buffer
 
.checkForEnd:
mov ax, [esi]
cmp ax, 3B00h ; ';'
jz @f
; check for files not ending with separator
movzx eax, byte [ebp-33]
add eax, ebp
sub eax, 34
cmp esi, eax
jz @f
; check the end of the directory
movzx eax, byte [ebp-1]
add eax, ebp
cmp esi, eax
@@:
ret
 
.utf16:
cmp [cd_counter_block], 2
jbe .utf16ParentDirectory
@@:
lodsw
xchg ah, al
stosw
call .checkForEnd
jc @b
@@:
mov [edi], word 0
add [cd_mem_location], 560
jmp .get_names_from_buffer
 
.utf16ParentDirectory:
stosw
cmp [cd_counter_block], 2
jnz @b
stosw
jmp @b
 
cd_get_parameters_of_file:
mov edi, [cd_mem_location]
cd_get_parameters_of_file_1:
; get file attributes
xor eax, eax
; file is not archived
inc eax
shl eax, 1
; is a directory?
test [ebp-8], byte 2
jz .file
inc eax
.file:
; not as a volume label in the FAT, in this form not available
; file is not a system
shl eax, 3
; file is hidden? (attribute of existence)
test [ebp-8], byte 1
jz .hidden
inc eax
.hidden:
shl eax, 1
; file is always read-only, as this CD
inc eax
mov [edi], eax
mov eax, [ebx+4]
mov [edi+4], eax
; get the time to file
; hour
movzx eax, byte [ebp-12]
shl eax, 8
; minute
mov al, [ebp-11]
shl eax, 8
; second
mov al, [ebp-10]
; file creation time
mov [edi+8], eax
; last access time
mov [edi+16], eax
; last write time
mov [edi+24], eax
; get date for file
; year
movzx eax, byte [ebp-15]
add eax, 1900
shl eax, 8
; month
mov al, [ebp-14]
shl eax, 8
; day
mov al, [ebp-13]
; file creation date
mov [edi+12], eax
; last access date
mov [edi+20], eax
; last write date
mov [edi+28], eax
; get the file size in bytes
xor eax, eax
mov [edi+32+4], eax
mov eax, [ebp-23]
mov [edi+32], eax
ret
 
;-----------------------------------------------------------------------------
fs_CdGetFileInfo:
call cd_find_lfn
movi eax, ERROR_FILE_NOT_FOUND
jc @f
mov edi, edx
mov eax, [ebx+4]
mov [edx+4], eax
cmp byte [esi], 0
jz .volume
mov ebp, [cd_current_pointer_of_input]
add ebp, 33
call cd_get_parameters_of_file_1
xor eax, eax
@@:
ret
 
.volume:
test eax, eax
jz .size
mov ecx, 16
mov esi, CDDataBuf+40
add edi, 40
cmp eax, 2
jz .utf16
cmp eax, 3
jz .utf8
@@:
lodsw
xchg al, ah
call uni2ansi_char
stosb
loop @b
jmp .size
 
.utf16:
lodsw
xchg al, ah
stosw
loop .utf16
jmp .size
 
.utf8:
mov ebx, ecx
shl ecx, 1
@@:
lodsw
xchg ah, al
call UTF16to8
dec ebx
jnz @b
.size:
mov eax, [CDDataBuf+80]
shl eax, 11
mov [edx+32], eax
xor eax, eax
mov [edx+36], eax
stosw
mov byte [edx], 8
ret
 
;-----------------------------------------------------------------------------
cd_find_lfn:
mov [cd_appl_data], 0
; in: esi -> path string in UTF-8
; out: [cd_current_pointer_of_input] -> direntry, CF=1 -> file not found
push eax esi
; Sector 16 - start set of volume descriptors
call WaitUnitReady
cmp [DevErrorCode], 0
jne .access_denied
 
call prevent_medium_removal
; testing of reading
mov [CDSectorAddress], dword 16
mov [CDDataBuf_pointer], CDDataBuf
call ReadCDWRetr;_1
cmp [DevErrorCode], 0
jne .access_denied
 
; calculation of the last session
call WaitUnitReady
cmp [DevErrorCode], 0
jne .access_denied
 
call Read_TOC
mov ah, [CDDataBuf+4+4]
mov al, [CDDataBuf+4+5]
shl eax, 16
mov ah, [CDDataBuf+4+6]
mov al, [CDDataBuf+4+7]
add eax, 15
mov [CDSectorAddress], eax
; mov [CDSectorAddress],dword 15
mov [CDDataBuf_pointer], CDDataBuf
;--------------------------------------
.start:
inc dword [CDSectorAddress]
call ReadCDWRetr;_1
cmp [DevErrorCode], 0
jne .access_denied
 
.start_check:
; checking for "lice"
cmp [CDDataBuf+1], dword 'CD00'
jne .access_denied
 
cmp [CDDataBuf+5], byte '1'
jne .access_denied
; sector is the terminator of set of descriptors volumes?
cmp [CDDataBuf], byte 0xff
je .access_denied
; sector is an additional and improved descriptor of volume?
cmp [CDDataBuf], byte 0x2
jne .start
; sector is an additional descriptor of volume?
cmp [CDDataBuf+6], byte 0x1
jne .start
 
; parameters of root directory
mov eax, [CDDataBuf+0x9c+2]; start of root directory
mov [CDSectorAddress], eax
mov eax, [CDDataBuf+0x9c+10]; size of root directory
cmp byte [esi], 0
jnz @f
 
mov [cd_current_pointer_of_input], CDDataBuf+0x9c
jmp .done
;--------------------------------------
@@:
; start the search
.mainloop:
dec dword [CDSectorAddress]
;--------------------------------------
.read_to_buffer:
inc dword [CDSectorAddress]
mov [CDDataBuf_pointer], CDDataBuf
call ReadCDWRetr ; read sector of directory
cmp [DevErrorCode], 0
jne .access_denied
call cd_find_name_in_buffer
jnc .found
sub eax, 2048
; directory is over?
cmp eax, 0
ja .read_to_buffer
; desired element of chain is not found
.access_denied:
pop esi eax
mov [cd_appl_data], 1
stc
ret
;--------------------------------------
; desired element of chain found
.found:
; the end of the file path
cmp byte [esi-1], 0
jz .done
mov eax, [cd_current_pointer_of_input]
push dword [eax+2]
pop dword [CDSectorAddress] ; beginning of the directory
mov eax, [eax+2+8] ; size of directory
jmp .mainloop
;--------------------------------------
; file pointer found
.done:
pop esi eax
mov [cd_appl_data], 1
clc
ret
;-----------------------------------------------------------------------------
cd_find_name_in_buffer:
mov [cd_current_pointer_of_input_2], CDDataBuf
;--------------------------------------
.start:
call cd_get_name
jc .not_found
 
call cd_compare_name
jc .start
;--------------------------------------
.found:
clc
ret
;--------------------------------------
.not_found:
stc
ret
;-----------------------------------------------------------------------------
cd_get_name:
push eax
mov ebp, [cd_current_pointer_of_input_2]
mov [cd_current_pointer_of_input], ebp
mov eax, [ebp]
test eax, eax ; entry's is over?
jz .next_sector
 
cmp ebp, CDDataBuf+2048 ; buffer is over?
jae .next_sector
 
movzx eax, byte [ebp]
add [cd_current_pointer_of_input_2], eax ; next entry of directory
add ebp, 33; pointer is set to the beginning of the name
pop eax
clc
ret
;--------------------------------------
.next_sector:
pop eax
stc
ret
;-----------------------------------------------------------------------------
cd_compare_name:
; in: esi -> UTF-8 name, ebp -> UTF-16BE name
; out: CF=0 -> names match, esi -> next component of name
; CF=1 -> esi is not changed
push edx edi eax esi
mov edi, ebp
.loop:
call utf8to16
call utf16toUpper
mov edx, eax
mov ax, [edi]
xchg al, ah
call utf16toUpper
cmp ax, dx
jne .name_not_coincide
add edi, 2
cmp [esi], byte '/' ; path separator is end of current element
je .done
cmp [esi], byte 0 ; path separator end of name
jne .loop
.done:
; check end of file
cmp [edi], word 3B00h; separator end of file ';'
je .done_1
; check for files not ending with separator
movzx eax, byte [ebp-33]
add eax, ebp
sub eax, 34
cmp edi, eax
je .done_1
; check the end of directory
movzx eax, byte [ebp-1]
add eax, ebp
cmp edi, eax
jne .name_not_coincide
.done_1:
pop eax eax edi edx
inc esi
ret
 
.name_not_coincide:
pop esi eax edi edx
stc
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/parse_fn.inc
0,0 → 1,340
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
iglobal
full_file_name_table dd sysdir_name
.size dd 1
endg
 
uglobal
sysdir_name rb 64 ; 'sys',0
sysdir_path rb 64
sysdir_name1 rb 64
sysdir_path1 rb 64
endg
; Example:
; align 64
; sysdir_name1 db 'KolibriOS',0
; align 64
; sysdir_path1 db 'HD0/1',0
 
proc Parser_params
locals
buff rb 4 ; for test cd
endl
if defined extended_primary_loader
mov ecx, sysdir_path
mov [ecx-64], dword 'sys'
mov [ecx-2], byte 3
mov esi, BOOT.syspath
mov edi, sysdir_path-1
mov ecx, 20
rep movsb
ret
else
mov ax, [BOOT.sys_disk]
mov ecx, sysdir_path
mov [ecx-64], dword 'sys'
mov [ecx-2], byte 3
mov [ecx-1], byte '/'
cmp al, 'r' ; ram disk
jnz @f
mov [ecx], dword 'RD/?'
mov [ecx+3], byte ah
mov [ecx+4], byte 0
ret
 
@@:
cmp al, 'm'
jnz .hard_disk
mov [ecx], dword 'CD?/'
mov [ecx+4], byte '1'
mov [ecx+5], dword '/KOL'
mov [ecx+9], dword 'IBRI'
mov [ecx+13], byte 0
.next_cd:
mov [ecx+2], byte ah
inc ah
cmp ah, '5'
je @f
lea edx, [buff]
pushad
stdcall read_file, read_firstapp, edx, 0, 4
popad
cmp [edx], dword 'MENU'
jne .next_cd
@@:
ret
end if
 
.hard_disk:
sub al, '1'
mov [ecx], dword 'HD?/'
mov [ecx+2], byte al
mov [ecx+4], byte ah
mov [ecx+5], dword '/KOL'
mov [ecx+9], dword 'IBRI'
mov [ecx+13], byte 0
ret
endp
 
cp866toUpper:
; convert cp866 character in al to uppercase
cmp al, 'a'
jb .ret
cmp al, 'z'
jbe @f
cmp al, 0xA0
jb .ret
cmp al, 0xB0
jb @f
cmp al, 0xE0
jb .ret
cmp al, 0xF0
jb .rus
cmp al, 0xF7
ja .ret
and eax, -2
.ret:
ret
 
@@:
sub eax, 32
ret
 
.rus:
sub eax, 0xE0-0x90
ret
 
utf16toUpper:
; convert UTF-16 character in ax to uppercase
cmp ax, 'a'
jb .ret
cmp ax, 'z'
jbe @f
cmp ax, 430h
jb .ret
cmp ax, 450h
jb @f
cmp ax, 460h
jnc .ret
sub eax, 80
.ret:
ret
 
@@:
sub eax, 32
ret
 
uni2ansi_char:
; convert UNICODE character in ax to ANSI character in al using cp866 encoding
cmp ax, 0x80
jb .ret
cmp ax, 0xB6
jz .B6
cmp ax, 0x400
jb .unk
cmp ax, 0x410
jb @f
cmp ax, 0x440
jb .rus1
cmp ax, 0x450
jb .rus2
cmp ax, 0x460
jb @f
.unk:
mov al, '_'
.ret:
ret
 
.B6:
mov al, 20
ret
 
.rus1: ; 0x410-0x43F -> 0x80-0xAF
add al, 0x70
ret
 
.rus2: ; 0x440-0x44F -> 0xE0-0xEF
add al, 0xA0
ret
 
@@:
push ecx edi
mov ecx, 8
mov edi, .table
repnz scasb
mov ah, cl
pop edi ecx
jnz .unk
mov al, 0xF7
sub al, ah
ret
 
.table db 1, 51h, 4, 54h, 7, 57h, 0Eh, 5Eh
 
ansi2uni_char:
; convert ANSI character in al to UNICODE character in ax, using cp866 encoding
movzx eax, al
cmp al, 0x80
jb @f ; 0x00-0x7F - trivial map
cmp al, 0xB0
jb .rus ; 0x80-0xAF -> 0x410-0x43F
cmp al, 0xE0
jb .unk
cmp al, 0xF0
jb .rus2 ; 0xE0-0xEF -> 0x440-0x44F
cmp al, 0xF8
jnc .unk
mov al, [eax+uni2ansi_char.table-0xF0]
add ax, 400h
ret
 
@@:
cmp al, 20
jnz .ret
mov al, 0xB6
.ret:
ret
 
.rus:
add ax, 0x410-0x80
ret
 
.rus2:
add ax, 0x440-0xE0
ret
 
.unk:
mov al, '_'
ret
 
cp866toUTF8_string:
; in:
; esi -> cp866 string (could be zero terminated)
; edi -> buffer for UTF-8 string
; ecx = buffer size (signed)
lodsb
call ansi2uni_char
push eax
call UTF16to8
pop eax
js @f
test eax, eax
jnz cp866toUTF8_string
@@:
ret
 
; SF=1 -> counter
; ZF=1 -> zero char
 
UTF16to8_string:
; in:
; esi -> UTF-16 string (could be zero terminated)
; edi -> buffer for UTF-8 string
; ecx = buffer size (signed)
xor eax, eax
@@:
lodsw
push eax
call UTF16to8
pop eax
js @f
test eax, eax
jnz @b
@@:
ret
 
UTF16to8:
; in:
; eax = UTF-16 char
; edi -> buffer for UTF-8 char (increasing)
; ecx = byte counter (decreasing)
dec ecx
js .ret
cmp eax, 80h
jnc @f
stosb
test eax, eax ; SF=0
.ret:
ret
 
@@:
dec ecx
js .ret
cmp eax, 800h
jnc @f
shl eax, 2
shr al, 2
or eax, 1100000010000000b
xchg al, ah
stosw
ret
 
@@:
dec ecx
js .ret
shl eax, 4
shr ax, 2
shr al, 2
or eax, 111000001000000010000000b
bswap eax
shr eax, 8
stosb
shr eax, 8
stosw
ret
 
utf8to16:
; in: esi -> UTF-8 char (increasing)
; out: ax = UTF-16 char
lodsb
test al, al
jns .got
shl al, 2
jnc utf8to16
@@:
shl ax, 8
lodsb
test al, al
jns .got
shl al, 2
jc @b
shr ah, 2
shl ax, 3
jnc @f
shl eax, 3
lodsb
test al, al
jns .got
shl al, 2
jc @b
shr eax, 2
ret
 
@@:
shr ax, 5
ret
 
.got:
xor ah, ah
ret
 
strlen:
; in: esi -> source
; out: ecx = length
push edi eax
or ecx, -1
mov edi, esi
xor eax, eax
repnz scasb
inc ecx
not ecx
pop eax edi
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/xfs.asm
0,0 → 1,2124
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
include 'xfs.inc'
 
macro omit_frame_pointer_prologue procname,flag,parmbytes,localbytes,reglist {
local loc
loc = (localbytes+3) and (not 3)
if localbytes
sub esp, loc
end if
irps reg, reglist \{ push reg \}
counter = 0
irps reg, reglist \{counter = counter+1 \}
parmbase@proc equ esp+counter*4+loc+4
localbase@proc equ esp
}
 
macro omit_frame_pointer_epilogue procname,flag,parmbytes,localbytes,reglist {
local loc
loc = (localbytes+3) and (not 3)
irps reg, reglist \{ reverse pop reg \}
if localbytes
lea esp, [esp+loc]
end if
if flag and 10000b
retn
else
retn parmbytes
end if
}
 
prologue@proc equ omit_frame_pointer_prologue
epilogue@proc equ omit_frame_pointer_epilogue
 
macro movbe reg, arg {
if CPUID_MOVBE eq Y
movbe reg, arg
else
mov reg, arg
if reg in <eax,ebx,ecx,edx,esi,edi,ebp,esp>
bswap reg
else if ax eq reg
xchg al, ah
else if bx eq reg
xchg bl, bh
else if cx eq reg
xchg cl, ch
else if dx eq reg
xchg dl, dh
else
err
end if
end if
}
 
;
; This file contains XFS related code.
; For more information on XFS check links and source below.
;
; 1. https://xfs.wiki.kernel.org/
;
; 2. XFS Algorithms & Data Structures:
; git://git.kernel.org/pub/scm/fs/xfs/xfs-documentation.git
; https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
;
; 3. Linux source at https://www.kernel.org/
; git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
; /fs/xfs
;
 
iglobal
align 4
xfs._.user_functions:
dd xfs._.free
dd (xfs._.user_functions_end-xfs._.user_functions-4)/4
dd xfs_Read
dd xfs_ReadFolder
dd 0;xfs_Rewrite
dd 0;xfs_Write
dd 0;xfs_SetFileEnd
dd xfs_GetFileInfo
xfs._.user_functions_end:
endg
 
; test partition type (valid XFS one?)
; alloc and fill XFS (see xfs.inc) structure
; this function is called for each partition
; return 0 (not XFS or invalid) / pointer to partition structure
proc xfs_create_partition uses ebx esi edi
; check XFS signature
cmp [ebx+xfs_sb.sb_magicnum], XFS_SB_MAGIC
jnz .error_nofree
; test for supported feature flags and version in sb_versionnum
movzx eax, [ebx+xfs_sb.sb_versionnum]
xchg al, ah
; allow only known and supported features
; return error otherwise
test eax, NOT XFS_SB_VERSION_SUPPORTED
jnz .error_nofree
; version < 4 obsolete, not supported
; version = 4,5 supported
; version > 5 unknown
and al, XFS_SB_VERSION_NUMBITS
cmp al, 4
jb .error_nofree
cmp al, 5
ja .error_nofree
; if MOREBITS bit is set, additional feature flags are in sb_features2
test eax, XFS_SB_VERSION_MOREBITSBIT
jz @f
movbe eax, [ebx+xfs_sb.sb_features2]
test eax, NOT XFS_SB_VERSION2_SUPPORTED
jnz .error_nofree
@@:
movbe eax, [ebx+xfs_sb.sb_features_incompat]
test eax, NOT XFS_SB_FEAT_INCOMPAT_SUPPORTED
jnz .error_nofree
; all presented features are either supported or don't affect reading
movi eax, sizeof.XFS
call malloc
mov edi, eax
test eax, eax
jz .error
 
; standard partition initialization, common for all file systems
mov eax, dword[ebp+PARTITION.FirstSector+DQ.lo]
mov dword[edi+XFS.FirstSector+DQ.lo], eax
mov eax, dword[ebp+PARTITION.FirstSector+DQ.hi]
mov dword[edi+XFS.FirstSector+DQ.hi], eax
mov eax, dword[ebp+PARTITION.Length+DQ.lo]
mov dword[edi+XFS.Length+DQ.lo], eax
mov eax, dword[ebp+PARTITION.Length+DQ.hi]
mov dword[edi+XFS.Length+DQ.hi], eax
mov eax, [ebp+PARTITION.Disk]
mov [edi+XFS.Disk], eax
mov [edi+XFS.FSUserFunctions], xfs._.user_functions
; here we initialize only one mutex (for the entire partition)
; XFS potentially allows parallel r/w access to different AGs, keep it in mind
lea ecx, [edi+XFS.Lock]
call mutex_init
 
; movzx eax, [ebx+xfs_sb.sb_sectsize]
; xchg al, ah
mov eax, [eax+DISK.MediaInfo.SectorSize]
mov [edi+XFS.sectsize], eax
 
movbe eax, [ebx+xfs_sb.sb_blocksize]
mov [edi+XFS.blocksize], eax
 
movzx eax, [ebx+xfs_sb.sb_versionnum]
xchg al, ah
mov [edi+XFS.versionnum], eax
and eax, XFS_SB_VERSION_NUMBITS
mov [edi+XFS.version], eax
 
movbe eax, [ebx+xfs_sb.sb_features2]
mov [edi+XFS.features2], eax
cmp [edi+XFS.version], 5
jz .v5
.v4:
mov [edi+XFS.inode_core_size], sizeof.xfs_dinode_core
test eax, XFS_SB_VERSION2_FTYPE
setnz al
movzx eax, al
mov [edi+XFS.ftype_size], eax
mov [edi+XFS.dir_block_magic], XFS_DIR2_BLOCK_MAGIC
mov [edi+XFS.dir_data_magic], XFS_DIR2_DATA_MAGIC
mov [edi+XFS.dir_leaf1_magic], XFS_DIR2_LEAF1_MAGIC
mov [edi+XFS.dir_leafn_magic], XFS_DIR2_LEAFN_MAGIC
mov [edi+XFS.da_node_magic], XFS_DA_NODE_MAGIC
mov [edi+XFS.bmap_magic], XFS_BMAP_MAGIC
mov [edi+XFS.dir_block_size], sizeof.xfs_dir2_data_hdr
mov [edi+XFS.bmbt_block_size], sizeof.xfs_bmbt_block
mov [edi+XFS.da_blkinfo_size], sizeof.xfs_da_blkinfo
jmp .vcommon
.v5:
mov [edi+XFS.inode_core_size], sizeof.xfs_dinode3_core
movbe eax, [ebx+xfs_sb.sb_features_incompat]
mov [edi+XFS.features_incompat], eax
test eax, XFS_SB_FEAT_INCOMPAT_FTYPE
setnz al
movzx eax, al
mov [edi+XFS.ftype_size], eax
mov [edi+XFS.dir_block_magic], XFS_DIR3_BLOCK_MAGIC
mov [edi+XFS.dir_data_magic], XFS_DIR3_DATA_MAGIC
mov [edi+XFS.dir_leaf1_magic], XFS_DIR3_LEAF1_MAGIC
mov [edi+XFS.dir_leafn_magic], XFS_DIR3_LEAFN_MAGIC
mov [edi+XFS.da_node_magic], XFS_DA3_NODE_MAGIC
mov [edi+XFS.bmap_magic], XFS_BMAP3_MAGIC
mov [edi+XFS.dir_block_size], sizeof.xfs_dir3_data_hdr
mov [edi+XFS.bmbt_block_size], sizeof.xfs_bmbt3_block
mov [edi+XFS.da_blkinfo_size], sizeof.xfs_da3_blkinfo
.vcommon:
 
movzx eax, [ebx+xfs_sb.sb_inodesize]
xchg al, ah
mov [edi+XFS.inodesize], eax
 
movzx eax, [ebx+xfs_sb.sb_inopblock]
xchg al, ah
mov [edi+XFS.inopblock], eax
 
movzx eax, [ebx+xfs_sb.sb_blocklog]
mov [edi+XFS.blocklog], eax
 
; movzx eax, [ebx+xfs_sb.sb_sectlog]
mov eax, [edi+XFS.sectsize]
bsf eax, eax
mov [edi+XFS.sectlog], eax
 
movzx eax, [ebx+xfs_sb.sb_inodelog]
mov [edi+XFS.inodelog], eax
 
movzx eax, [ebx+xfs_sb.sb_inopblog]
mov [edi+XFS.inopblog], eax
 
movzx ecx, [ebx+xfs_sb.sb_dirblklog]
mov [edi+XFS.dirblklog], ecx
movi eax, 1
shl eax, cl
mov [edi+XFS.blkpdirblk], eax
 
movbe eax, [ebx+xfs_sb.sb_rootino.hi]
mov [edi+XFS.rootino.lo], eax
movbe eax, [ebx+xfs_sb.sb_rootino.lo]
mov [edi+XFS.rootino.hi], eax
 
mov eax, [edi+XFS.blocksize]
mov ecx, [edi+XFS.dirblklog]
shl eax, cl
mov [edi+XFS.dirblocksize], eax ; blocks are for files, dirblocks are for directories
 
; sector is always smaller than block
; so precalculate shift order to allow faster sector_num->block_num conversion
mov ecx, [edi+XFS.blocklog]
sub ecx, [edi+XFS.sectlog]
mov [edi+XFS.sectpblog], ecx
 
mov eax, 1
shl eax, cl
mov [edi+XFS.sectpblock], eax
 
movbe eax, [ebx+xfs_sb.sb_agblocks]
mov [edi+XFS.agblocks], eax
 
movzx ecx, [ebx+xfs_sb.sb_agblklog]
mov [edi+XFS.agblklog], ecx
 
; get the mask for block numbers
; block numbers are AG relative!
; bitfield length may vary between partitions
mov eax, 1
xor edx, edx
shld edx, eax, cl
shl eax, cl
sub eax, 1
sbb edx, 0
mov [edi+XFS.agblockmask.lo], eax
mov [edi+XFS.agblockmask.hi], edx
 
; calculate magic offsets for directories
mov ecx, [edi+XFS.blocklog]
mov eax, XFS_DIR2_LEAF_OFFSET AND 0xffffffff ; lo
mov edx, XFS_DIR2_LEAF_OFFSET SHR 32 ; hi
shrd eax, edx, cl
shr edx, cl
mov [edi+XFS.dir2_leaf_offset_blocks.lo], eax
mov [edi+XFS.dir2_leaf_offset_blocks.hi], edx
 
mov ecx, [edi+XFS.blocklog]
mov eax, XFS_DIR2_FREE_OFFSET AND 0xffffffff ; lo
mov edx, XFS_DIR2_FREE_OFFSET SHR 32 ; hi
shrd eax, edx, cl
shr edx, cl
mov [edi+XFS.dir2_free_offset_blocks.lo], eax
mov [edi+XFS.dir2_free_offset_blocks.hi], edx
 
 
; allocate memory for temp block, dirblock, inode, etc
mov eax, [edi+XFS.blocksize]
call malloc
mov [edi+XFS.cur_block], eax
test eax, eax
jz .error
 
mov eax, [edi+XFS.blocksize]
call malloc
mov [edi+XFS.cur_block_data], eax
test eax, eax
jz .error
 
; we do need XFS.blocksize bytes for single inode
; minimal file system structure is block, inodes are packed in blocks
; FIXME
mov eax, [edi+XFS.blocksize]
call malloc
mov [edi+XFS.cur_inode], eax
test eax, eax
jz .error
 
mov eax, [edi+XFS.blocksize]
call malloc
test eax, eax
jz .error
mov [edi+XFS.tmp_inode], eax
 
; current sector
; only for sector sized structures like AGF
; inodes usually fit this size, but not always!
; therefore never store inode here
mov eax, [edi+XFS.sectsize]
call malloc
mov [edi+XFS.cur_sect], eax
test eax, eax
jz .error
 
mov eax, [edi+XFS.dirblocksize]
call malloc
mov [edi+XFS.cur_dirblock], eax
test eax, eax
jz .error
 
.quit:
; return pointer to allocated XFS partition structure
mov eax, edi
ret
.error:
mov eax, edi
call xfs._.free
.error_nofree:
xor eax, eax
ret
endp
 
 
; lock partition access mutex
xfs._.lock:
lea ecx, [ebp+XFS.Lock]
jmp mutex_lock
 
 
; unlock partition access mutex
xfs._.unlock:
lea ecx, [ebp+XFS.Lock]
jmp mutex_unlock
 
 
; free all the allocated memory
; called on partition destroy
; or during failed initialization from xfs_create_partition
xfs._.free:
test eax, eax
jz .done
push ebx
mov ebx, eax
 
 
; freeing order must correspond the order of
; allocation in xfs_create_partition
mov eax, [ebx+XFS.cur_block]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_block_data]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_inode]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.tmp_inode]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_sect]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_dirblock]
test eax, eax
jz .done
call free
 
 
mov eax, ebx
call free
pop ebx
.done:
ret
 
 
;---------------------------------------------------------------
; block number
; eax -- inode_lo
; edx -- inode_hi
; ebx -- buffer
;---------------------------------------------------------------
proc xfs._.read_block
movi ecx, 1
call xfs._.read_blocks
ret
endp
 
 
proc xfs._.blkrel2sectabs uses esi
push edx eax
 
; XFS block numbers are AG relative
; they come in bitfield form of concatenated AG and block numbers
; to get absolute block number for fs_read64_sys we should
; 1. get AG number and multiply it by the AG size in blocks
; 2. extract and add AG relative block number
 
; 1.
mov ecx, [ebp+XFS.agblklog]
shrd eax, edx, cl
shr edx, cl
mul [ebp+XFS.agblocks]
; 2.
pop ecx esi
and ecx, [ebp+XFS.agblockmask.lo]
and esi, [ebp+XFS.agblockmask.hi]
add eax, ecx
adc edx, esi
 
mov ecx, [ebp+XFS.sectpblog]
shld edx, eax, cl
shl eax, cl
ret
endp
 
 
;---------------------------------------------------------------
; start block number
; edx:eax -- block
; ebx -- buffer
; ecx -- count
;---------------------------------------------------------------
proc xfs._.read_blocks
push ecx
call xfs._.blkrel2sectabs
pop ecx
imul ecx, [ebp+XFS.sectpblock]
call fs_read64_sys
test eax, eax
ret
endp
 
 
proc xfs._.read_dirblock uses ebx, _startblock:qword, _buffer
mov eax, dword[_startblock+DQ.lo]
mov edx, dword[_startblock+DQ.hi]
mov ebx, [_buffer]
mov ecx, [ebp+XFS.blkpdirblk]
call xfs._.read_blocks
ret
endp
 
 
;---------------------------------------------------------------
; test eax, eax
;---------------------------------------------------------------
proc xfs_read_inode uses ebx, _inode_lo, _inode_hi, _buffer
mov eax, [_inode_lo]
mov edx, [_inode_hi]
mov ebx, [_buffer]
; inodes are packed into blocks
; 1. calculate block number
; 2. read the block
; 3. add inode offset to block base address
; 1.
mov ecx, [ebp+XFS.inopblog]
shrd eax, edx, cl
shr edx, cl
; 2.
call xfs._.read_block
jnz .error
; inode numbers should be first extracted from bitfields by mask
 
mov eax, [_inode_lo]
mov edx, 1
mov ecx, [ebp+XFS.inopblog]
shl edx, cl
dec edx ; get inode number mask
and eax, edx ; apply mask
mov ecx, [ebp+XFS.inodelog]
shl eax, cl
add ebx, eax
xor eax, eax
 
cmp [ebx+xfs_inode.di_core.di_magic], XFS_DINODE_MAGIC
jz .quit
movi eax, ERROR_FS_FAIL
.quit:
mov edx, ebx
.error:
ret
endp
 
 
; skip ecx first entries
proc xfs._.dir_sf_skip _count
mov ecx, [_count]
.next:
dec ecx
js .quit
dec [ebp+XFS.entries_left_in_dir]
js .quit
.self:
bts [ebp+XFS.dir_sf_self_done], 0
jc .parent
jmp .next
.parent:
bts [ebp+XFS.dir_sf_parent_done], 0
jc .common
jmp .next
.common:
movzx eax, [esi+xfs_dir2_sf_entry.namelen]
add esi, xfs_dir2_sf_entry.name
add esi, eax
add esi, [ebp+XFS.ftype_size]
add esi, [ebp+XFS.shortform_inodelen]
jmp .next
.quit:
ret
endp
 
 
proc xfs._.dir_sf_read uses edi, _count
locals
_dst dd ?
endl
.next:
dec [_count]
js .quit
dec [ebp+XFS.entries_left_in_dir]
js .quit
mov [_dst], edx
.self:
bts [ebp+XFS.dir_sf_self_done], 0
jc .parent
lea edi, [edx+bdfe.name]
mov dword[edi], '.'
stdcall xfs_get_inode_info, [ebp+XFS.cur_inode], edx
jmp .common
.parent:
bts [ebp+XFS.dir_sf_parent_done], 0
jc .not_special
lea edi, [edx+bdfe.name] ; get file name offset
mov dword[edi], '..' ; terminator included
mov edi, edx
lea edx, [ebx+xfs_dir2_sf.hdr.parent]
call xfs._.get_inode_number_sf
stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
test eax, eax
jnz .error
stdcall xfs_get_inode_info, edx, edi
jmp .common
.not_special:
movzx ecx, [esi+xfs_dir2_sf_entry.namelen]
add esi, xfs_dir2_sf_entry.name
lea edi, [edx+bdfe.name]
stdcall xfs._.copy_filename
add esi, [ebp+XFS.ftype_size]
mov edi, edx
mov edx, esi
call xfs._.get_inode_number_sf
stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
test eax, eax
jnz .error
stdcall xfs_get_inode_info, edx, edi
add esi, [ebp+XFS.shortform_inodelen]
.common:
mov edx, [_dst]
mov eax, [ebp+XFS.bdfe_nameenc]
mov [edx+bdfe.nameenc], eax
add edx, [ebp+XFS.bdfe_len]
inc [ebp+XFS.entries_read]
jmp .next
.quit:
xor eax, eax
.error:
ret
endp
 
 
proc xfs._.readdir_sf uses esi, _src, _dst
mov ebx, [_src]
mov edx, [_dst]
mov [ebp+XFS.dir_sf_self_done], 0
mov [ebp+XFS.dir_sf_parent_done], 0
mov [ebp+XFS.entries_read], 0
movzx eax, [ebx+xfs_dir2_sf.hdr.count]
; '..' and '.' are implicit
add eax, 2
mov [ebp+XFS.entries_left_in_dir], eax
mov [edx+bdfe_hdr.total_cnt], eax
; inode numbers are often saved as 4 bytes (iff they fit)
; compute the length of inode numbers
; 8 iff i8count != 0, 4 otherwise
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
setnz al
lea eax, [eax*4+4]
mov [ebp+XFS.shortform_inodelen], eax
add edx, sizeof.bdfe_hdr
lea esi, [ebx+xfs_dir2_sf.hdr.parent+eax]
stdcall xfs._.dir_sf_skip, [ebp+XFS.entries_to_skip]
stdcall xfs._.dir_sf_read, [ebp+XFS.requested_cnt]
ret
endp
 
 
proc xfs._.readdir_block _literal_area, _out_buf
mov ebx, [_literal_area]
mov [ebp+XFS.entries_read], 0
mov eax, ebx
mov ebx, [ebp+XFS.cur_dirblock]
stdcall xfs._.extent_unpack, eax
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], ebx
mov edx, [_out_buf]
jnz .error
mov eax, [ebp+XFS.dir_block_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
mov eax, [ebp+XFS.dirblocksize]
movbe ecx, [ebx+eax-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.stale]
movbe eax, [ebx+eax-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.count]
sub eax, ecx ; actual number of entries = count - stale
mov [ebp+XFS.entries_left_in_dir], eax
mov [edx+bdfe_hdr.total_cnt], eax
 
add ebx, [ebp+XFS.dir_block_size]
add edx, sizeof.bdfe_hdr
mov [_out_buf], edx
lea edi, [_out_buf]
.next:
movi eax, ERROR_SUCCESS
cmp [ebp+XFS.requested_cnt], 0
jz .quit
cmp [ebp+XFS.entries_left_in_dir], 0
jz .quit
stdcall xfs._.dir_entry_skip_read, edi
jz .next
.error:
.quit:
ret
endp
 
 
proc xfs._.readdir_leaf_node uses esi, _inode_data, _out_buf
mov ebx, [_inode_data]
mov edx, [_out_buf]
mov [ebp+XFS.cur_inode_save], ebx
mov [ebp+XFS.entries_read], 0
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_extent_list, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.leafn_calc_entries, 0
jnz .error
mov eax, [ebp+XFS.entries_read]
mov edx, [_out_buf]
mov [edx+bdfe_hdr.total_cnt], eax
mov [ebp+XFS.entries_left_in_dir], eax
add [_out_buf], sizeof.bdfe_hdr
mov [ebp+XFS.entries_read], 0
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
lea ecx, [_out_buf]
push ecx
mov [ebp+XFS.offset_begin.lo], 0
mov [ebp+XFS.offset_begin.hi], 0
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
pop ecx
stdcall xfs._.walk_extent_list, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.dir_btree_skip_read, ecx
; jnz .error
.error:
.quit:
ret
endp
 
 
proc xfs._.dir_entry_skip_read uses esi edi, _arg
cmp [ebx+xfs_dir2_data_union.unused.freetag], XFS_NULL
jnz @f
movzx eax, [ebx+xfs_dir2_data_union.unused.length]
xchg al, ah
add ebx, eax
jmp .quit
@@:
cmp [ebp+XFS.entries_to_skip], 0
jz .read
.skip:
dec [ebp+XFS.entries_to_skip]
movzx ecx, [ebx+xfs_dir2_data_union.xentry.namelen]
lea ebx, [ebx+xfs_dir2_data_union.xentry.name+ecx+2]
add ebx, [ebp+XFS.ftype_size]
jmp .common
.read:
dec [ebp+XFS.requested_cnt]
inc [ebp+XFS.entries_read]
mov edi, [_arg]
mov edi, [edi]
movbe edx, [ebx+xfs_dir2_data_union.xentry.inumber.lo]
movbe eax, [ebx+xfs_dir2_data_union.xentry.inumber.hi]
stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
stdcall xfs_get_inode_info, edx, edi
jnz .error
mov edx, [_arg]
mov edx, [edx]
mov ecx, [ebp+XFS.bdfe_nameenc]
mov [edx+bdfe.nameenc], ecx
lea edi, [edx+bdfe.name]
movzx ecx, [ebx+xfs_dir2_data_union.xentry.namelen]
lea esi, [ebx+xfs_dir2_data_union.xentry.name]
stdcall xfs._.copy_filename
lea ebx, [esi+2] ; skip 'tag'
add ebx, [ebp+XFS.ftype_size]
mov eax, [_arg]
mov edx, [eax]
add edx, [ebp+XFS.bdfe_len]
mov [eax], edx
.common:
sub ebx, [ebp+XFS.cur_dirblock]
add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes
and ebx, not 7
add ebx, [ebp+XFS.cur_dirblock]
dec [ebp+XFS.entries_left_in_dir]
.quit:
movi eax, ERROR_SUCCESS
cmp esp, esp
.error:
ret
endp
 
 
proc xfs._.dir_btree_skip_read uses ebx ecx edx esi edi, _cur_dirblock, _offset_lo, _offset_hi, _arg
mov ebx, [_cur_dirblock]
mov eax, [ebp+XFS.dir_data_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
mov eax, ebx
add eax, [ebp+XFS.dirblocksize]
mov [ebp+XFS.max_dirblockaddr], eax
; add ebx, xfs_dir2_block.u
add ebx, [ebp+XFS.dir_block_size]
.next:
movi eax, ERROR_SUCCESS
cmp [ebp+XFS.requested_cnt], 0
jz .quit
cmp [ebp+XFS.entries_left_in_dir], 0
jz .quit
cmp ebx, [ebp+XFS.max_dirblockaddr]
jz .quit
stdcall xfs._.dir_entry_skip_read, [_arg]
jz .next
.error:
.quit:
ret
endp
 
 
proc xfs._.readdir_btree uses esi, _inode_data, _out_buf
mov [ebp+XFS.cur_inode_save], ebx
mov [ebp+XFS.entries_read], 0
mov eax, [ebp+XFS.inodesize]
sub eax, xfs_inode.di_u
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
lea edx, [ebx+xfs_inode.di_u]
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_btree, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.leafn_calc_entries, 0, 1
mov eax, [ebp+XFS.entries_read]
mov edx, [_out_buf]
mov [edx+bdfe_hdr.total_cnt], eax
mov [ebp+XFS.entries_left_in_dir], eax
mov [ebp+XFS.entries_read], 0
add [_out_buf], sizeof.bdfe_hdr
mov eax, [ebp+XFS.inodesize]
sub eax, xfs_inode.di_u
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
lea edx, [ebx+xfs_inode.di_u]
mov [ebp+XFS.offset_begin.lo], 0
mov [ebp+XFS.offset_begin.hi], 0
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
mov ecx, [_out_buf]
push ecx
mov ecx, esp
stdcall xfs._.walk_btree, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.dir_btree_skip_read, ecx, 1
pop ecx
.error:
.quit:
ret
endp
 
 
proc xfs._.copy_filename uses eax
mov eax, [ebp+XFS.bdfe_nameenc]
cmp eax, 3
jz .utf8
cmp eax, 2
jz .utf16
.cp866:
call unicode.utf8.decode
call unicode.cp866.encode
stosb
test ecx, ecx
jnz .cp866
mov byte[edi], 0
jmp .done
.utf16:
call unicode.utf8.decode
call unicode.utf16.encode
stosw
shr eax, 16
jz @f
stosw
@@:
test ecx, ecx
jnz .utf16
mov word[edi], 0
jmp .done
.utf8:
rep movsb
mov byte[edi], 0
.done:
ret
endp
 
;----------------------------------------------------------------
; src ; inode
; dst ; bdfe
; start_number ; from 0
;----------------------------------------------------------------
proc xfs._.readdir uses ebx esi edi, _start_number, _entries_to_read, _dst, _src, _encoding
mov ecx, [_start_number]
mov [ebp+XFS.entries_to_skip], ecx
mov eax, [_entries_to_read]
mov [ebp+XFS.requested_cnt], eax
mov eax, [_encoding]
mov [ebp+XFS.bdfe_nameenc], eax
mov ecx, 304
cmp eax, 1 ; CP866
jbe @f
mov ecx, 560
@@:
mov [ebp+XFS.bdfe_len], ecx
mov edx, [_dst]
mov [ebp+XFS.bdfe_buf], edx
mov ebx, [_src]
mov [ebp+XFS.cur_inode_save], ebx
 
mov [edx+bdfe_hdr.version], 1
mov [edx+bdfe_hdr.zeroed+0x00], 0
mov [edx+bdfe_hdr.zeroed+0x04], 0
mov [edx+bdfe_hdr.zeroed+0x08], 0
mov [edx+bdfe_hdr.zeroed+0x0c], 0
mov [edx+bdfe_hdr.zeroed+0x10], 0
 
movzx eax, [ebx+xfs_inode.di_core.di_format]
; switch directory ondisk format and jump to corresponding label
cmp eax, XFS_DINODE_FMT_LOCAL
jnz @f
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.readdir_sf, ebx, [_dst]
test eax, eax
jnz .error
jmp .quit
@@:
cmp eax, XFS_DINODE_FMT_BTREE
jnz @f
stdcall xfs._.readdir_btree, ebx, [_dst]
jmp .quit
@@:
cmp eax, XFS_DINODE_FMT_EXTENTS
movi eax, ERROR_FS_FAIL
jnz .error
call xfs._.get_last_dirblock
test eax, eax
jnz @f
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.readdir_block, ebx, [_dst]
jmp .quit
@@:
stdcall xfs._.readdir_leaf_node, ebx, [_dst]
jmp .quit
.quit:
mov edx, [_dst]
mov ebx, [ebp+XFS.entries_read]
mov [edx+bdfe_hdr.read_cnt], ebx
xor eax, eax
.error:
ret
endp
 
 
; returns edx:eax inode or 0
proc xfs._.lookup_sf _name, _len
add ebx, [ebp+XFS.inode_core_size]
mov esi, [_name]
mov ecx, [_len]
cmp ecx, 2
ja .common
jz .check_parent
.check_self:
cmp byte[esi], '.'
jnz .common
mov eax, [ebp+XFS.inode_self.lo]
mov edx, [ebp+XFS.inode_self.hi]
jmp .quit
.check_parent:
cmp word[esi], '..'
jnz .common
lea edx, [ebx+xfs_dir2_sf.hdr.parent]
call xfs._.get_inode_number_sf
jmp .quit
.common:
movzx edx, [ebx+xfs_dir2_sf.hdr.count]
movi eax, 0
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
setnz al
lea eax, [eax*4+4]
lea edi, [ebx+xfs_dir2_sf.hdr.parent+eax]
.next_name:
dec edx
jns @f
movi eax, ERROR_FILE_NOT_FOUND
jmp .error
@@:
movzx ecx, [edi+xfs_dir2_sf_entry.namelen]
add edi, xfs_dir2_sf_entry.name
mov esi, [_name]
cmp ecx, [_len]
jnz @f
repz cmpsb
jz .found
@@:
add edi, [ebp+XFS.ftype_size]
add edi, ecx
add edi, eax
jmp .next_name
.found:
add edi, [ebp+XFS.ftype_size]
mov edx, edi
call xfs._.get_inode_number_sf
.quit:
cmp esp, esp
.error:
ret
endp
 
 
proc xfs._.lookup_block uses esi, _name, _len
add ebx, [ebp+XFS.inode_core_size]
mov eax, ebx
mov ebx, [ebp+XFS.cur_dirblock]
stdcall xfs._.extent_unpack, eax
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], ebx
jnz .error
mov eax, [ebp+XFS.dir_block_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
stdcall xfs_hashname, [_name+4], [_len]
add ebx, [ebp+XFS.dirblocksize]
movbe ecx, [ebx-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.count]
lea edx, [ecx*sizeof.xfs_dir2_leaf_entry+sizeof.xfs_dir2_block_tail]
sub ebx, edx
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
movbe edx, [ebx+eax*XFS_DIR2_DATA_ALIGN+xfs_dir2_data_entry.inumber.lo]
movbe eax, [ebx+eax*XFS_DIR2_DATA_ALIGN+xfs_dir2_data_entry.inumber.hi]
.quit:
.error:
ret
endp
 
 
proc xfs._.get_inode_by_addr uses ebx esi edi, _inode_buf
xor edx, edx
shld edx, eax, XFS_DIR2_DATA_ALIGN_LOG
shl eax, XFS_DIR2_DATA_ALIGN_LOG
mov esi, [ebp+XFS.dirblocksize]
dec esi
and esi, eax
mov ecx, [ebp+XFS.blocklog]
add ecx, [ebp+XFS.dirblklog]
shrd eax, edx, cl
shr edx, cl
mov ecx, [ebp+XFS.dirblklog]
shld edx, eax, cl
shl eax, cl
mov ebx, [_inode_buf]
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jz .extents
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jz .btree
jmp .error
.extents:
movbe ecx, [ebx+xfs_inode.di_core.di_nextents]
add ebx, [ebp+XFS.inode_core_size]
mov [ebp+XFS.offset_begin.lo], eax
mov [ebp+XFS.offset_begin.hi], edx
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .error
jmp .common
.btree:
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
shl ecx, 3
test ecx, ecx
jnz @f
mov ecx, [ebp+XFS.inodesize]
sub ecx, [ebp+XFS.inode_core_size]
@@:
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.btree_read_block, ebx, ecx, eax, edx, [ebp+XFS.cur_dirblock]
.common:
mov ebx, [ebp+XFS.cur_dirblock]
mov eax, [ebp+XFS.dir_data_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
movbe edx, [ebx+esi+xfs_dir2_data_entry.inumber.lo]
movbe eax, [ebx+esi+xfs_dir2_data_entry.inumber.hi]
.error:
.quit:
ret
endp
 
 
proc xfs._.lookup_leaf uses ebx esi edi, _name, _len
movbe ecx, [ebx+xfs_inode.di_core.di_nextents]
add ebx, [ebp+XFS.inode_core_size]
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
movzx eax, [ebp+XFS.dir_leaf1_magic]
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], ax
movi eax, ERROR_FS_FAIL
jnz .error
stdcall xfs_hashname, [_name+4], [_len]
cmp [ebp+XFS.version], 5
jz .v5
.v4:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
jmp .vcommon
.v5:
movzx ecx, [ebx+xfs_dir3_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir3_leaf.ents
.vcommon:
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
.error:
ret
endp
 
 
proc xfs._.lookup_node uses ebx esi edi, _name, _len
locals
.hash dd ?
endl
mov [ebp+XFS.cur_inode_save], ebx
stdcall xfs_hashname, [_name+4], [_len]
mov [.hash], eax
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov esi, [ebp+XFS.dir2_leaf_offset_blocks.lo]
.begin:
mov ebx, [ebp+XFS.cur_inode_save]
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ebx, eax
mov [ebp+XFS.offset_begin.lo], esi
mov [ebp+XFS.offset_begin.hi], 0
stdcall xfs._.extent_list.seek, edx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
movzx eax, [ebp+XFS.da_node_magic]
cmp [ebx+xfs_da_intnode.hdr.info.magic], ax
jz .node
movzx eax, [ebp+XFS.dir_leafn_magic]
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], ax
jz .leaf
movi eax, ERROR_FS_FAIL
jmp .error
.node:
cmp [ebp+XFS.version], 5
jz .node.v5
.node.v4:
lea eax, [ebx+sizeof.xfs_da_intnode]
movzx edx, [ebx+xfs_da_intnode.hdr.count]
jmp .node.vcommon
.node.v5:
lea eax, [ebx+sizeof.xfs_da3_intnode]
movzx edx, [ebx+xfs_da3_intnode.hdr.count]
.node.vcommon:
xchg dl, dh
stdcall xfs._.get_before_by_hashval, eax, edx, [.hash]
jnz .error
mov esi, eax
jmp .begin
.leaf:
cmp [ebp+XFS.version], 5
jz .leaf.v5
.leaf.v4:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
jmp .leaf.vcommon
.leaf.v5:
movzx ecx, [ebx+xfs_dir3_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir3_leaf.ents
.leaf.vcommon:
mov eax, [.hash]
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
cmp esp, esp
ret
.error:
test esp, esp
ret
endp
 
 
proc xfs._.lookup_btree uses ebx esi edi, _name, _len
locals
.hash dd ?
endl
mov [ebp+XFS.cur_inode_save], ebx
stdcall xfs_hashname, [_name+4], [_len]
mov [.hash], eax
mov edx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.lo]
jmp .next_level.first
.next_level:
lea eax, [ebx+sizeof.xfs_da_intnode]
movzx edx, [ebx+xfs_da_intnode.hdr.count]
xchg dl, dh
stdcall xfs._.get_before_by_hashval, eax, edx, [.hash]
jnz .error
xor edx, edx
.next_level.first:
mov ebx, [ebp+XFS.cur_inode_save]
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
shl ecx, 3
test ecx, ecx
jnz @f
mov ecx, [ebp+XFS.inodesize]
sub ecx, xfs_inode.di_u
@@:
add ebx, xfs_inode.di_u
stdcall xfs._.btree_read_block, ebx, ecx, eax, edx, [ebp+XFS.cur_dirblock]
mov ebx, [ebp+XFS.cur_dirblock]
cmp [ebx+xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
jz .next_level
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
jz .leafn
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], XFS_DIR2_LEAF1_MAGIC
jnz .error
mov eax, [.hash]
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
jmp .got_addr
.leafn:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
mov eax, [.hash]
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
mov ebx, [ebp+XFS.cur_block]
.got_addr:
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
cmp esp, esp
ret
.error:
test esp, esp
ret
endp
 
 
; search for the _name in _inode dir
; called for each /path/component/to/my/file
; out:
; ZF/zf = ok/fail
; edx:eax = inode/garbage:error
proc xfs._.get_inode_short uses esi, _inode:qword, _len, _name
mov esi, [_name]
mov eax, dword[_inode+DQ.lo]
mov edx, dword[_inode+DQ.hi]
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
; switch directory ondisk format
mov ebx, edx
mov [ebp+XFS.cur_inode_save], ebx
movzx eax, [ebx+xfs_inode.di_core.di_format]
cmp eax, XFS_DINODE_FMT_LOCAL
mov edi, xfs._.lookup_sf
jz .lookup
cmp eax, XFS_DINODE_FMT_BTREE
mov edi, xfs._.lookup_btree
jz .lookup
cmp eax, XFS_DINODE_FMT_EXTENTS
jnz .error
call xfs._.get_last_dirblock
test eax, eax
mov edi, xfs._.lookup_block
jz .lookup
cmp edx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov edi, xfs._.lookup_node
ja .lookup
cmp eax, [ebp+XFS.dir2_free_offset_blocks.lo]
jae .lookup
mov edi, xfs._.lookup_leaf
.lookup:
stdcall edi, [_name+4], [_len]
.error:
ret
endp
 
 
; ZF/zf = ok/fail
; edx:eax = inode/garbage:error
proc xfs_get_inode uses ebx esi edi, _name
; call *._.get_inode_short until file is found / error returned
; start from the root inode
mov eax, [ebp+XFS.rootino.lo]
mov edx, [ebp+XFS.rootino.hi]
mov esi, [_name]
.next_dir:
@@:
cmp byte[esi], '/'
jnz @f
inc esi
jmp @b
@@:
cmp byte[esi], 0
jz .found
push esi
inc esi
@@:
cmp byte[esi], 0
jz @f
cmp byte[esi], '/'
jz @f
inc esi
jmp @b
@@:
mov ecx, esi
sub ecx, [esp]
mov [ebp+XFS.inode_self.lo], eax
mov [ebp+XFS.inode_self.hi], edx
stdcall xfs._.get_inode_short, eax, edx, ecx ; esi pushed above
jz .next_dir
.error:
.found:
ret
endp
 
 
; in: ebp = pointer to XFS structure
; in: esi
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
; out: [edx] -- f70.1 out structure
proc xfs_ReadFolder uses esi edi
call xfs._.lock
stdcall xfs_get_inode, esi
jnz .error
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
jnz .error
stdcall xfs._.readdir, [ebx+f70s1arg.start_idx], [ebx+f70s1arg.count], [ebx+f70s1arg.buf], edx, [ebx+f70s1arg.encoding]
test eax, eax
jnz .error
mov edx, [ebx+f70s1arg.buf]
mov ecx, [ebx+f70s1arg.count]
cmp [edx+bdfe_hdr.read_cnt], ecx
jz .quit
movi eax, ERROR_END_OF_FILE
.quit:
mov ebx, [edx+bdfe_hdr.read_cnt]
 
.error:
push eax
call xfs._.unlock
pop eax
ret
endp
 
 
; edx -- pointer to inode number in big endian
; ZF -- must be set at exit
proc xfs._.get_inode_number_sf
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
jz .i4bytes
.i8bytes:
movbe eax, [edx+DQ.hi]
movbe edx, [edx+DQ.lo]
ret
.i4bytes:
movbe eax, [edx+DQ.lo]
xor edx, edx
ret
endp
 
 
proc xfs_get_inode_info uses ebx, _src, _dst
; get access time and other file properties
; useful for browsing directories
; called for each dir entry
xor eax, eax
mov edx, [_src]
movzx ecx, [edx+xfs_inode.di_core.di_mode]
xchg cl, ch
test ecx, S_IFDIR
jz @f
movi eax, 0x10 ; set directory flag
@@:
mov edi, [_dst]
mov [edi+bdfe.attr], eax
movbe eax, [edx+xfs_inode.di_core.di_size.lo]
mov [edi+bdfe.size.hi], eax
movbe eax, [edx+xfs_inode.di_core.di_size.hi]
mov [edi+bdfe.size.lo], eax
 
add edi, 8
movbe eax, [edx+xfs_inode.di_core.di_ctime.t_sec]
push edx
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
movbe eax, [edx+xfs_inode.di_core.di_atime.t_sec]
push edx
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
movbe eax, [edx+xfs_inode.di_core.di_mtime.t_sec]
push edx
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
proc xfs._.extent_unpack uses eax ebx ecx edx, _extent_data
; extents come as packet 128bit bitfields
; unpack them to access internal fields
; write result to the XFS.extent structure
mov ebx, [_extent_data]
 
xor eax, eax
movbe edx, [ebx+0]
test edx, 0x80000000 ; mask, see documentation
setnz al
mov [ebp+XFS.extent.br_state], eax
 
and edx, 0x7fffffff ; mask
movbe eax, [ebx+4]
shrd eax, edx, 9
shr edx, 9
mov [ebp+XFS.extent.br_startoff.lo], eax
mov [ebp+XFS.extent.br_startoff.hi], edx
 
movbe edx, [ebx+4]
movbe eax, [ebx+8]
movbe ecx, [ebx+12]
and edx, 0x000001ff ; mask
shrd ecx, eax, 21
shrd eax, edx, 21
mov [ebp+XFS.extent.br_startblock.lo], ecx
mov [ebp+XFS.extent.br_startblock.hi], eax
 
movbe eax, [ebx+12]
and eax, 0x001fffff ; mask
mov [ebp+XFS.extent.br_blockcount], eax
ret
endp
 
 
proc xfs_hashname uses ecx esi, _name, _len
xor eax, eax
mov esi, [_name]
mov ecx, [_len]
@@:
rol eax, 7
xor al, [esi]
add esi, 1
dec ecx
jnz @b
ret
endp
 
 
; eax -- hash value
proc xfs._.get_addr_by_hash uses ebx esi, _base, _len
; look for the directory entry offset by its file name hash
; allows fast file search for block, leaf and node directories
; binary (ternary) search
mov ebx, [_base]
mov edx, [_len]
.next:
mov ecx, edx
; jecxz .error
test ecx, ecx
jz .not_found
shr ecx, 1
movbe esi, [ebx+ecx*sizeof.xfs_dir2_leaf_entry+xfs_dir2_leaf_entry.hashval]
cmp eax, esi
jb .below
ja .above
movbe eax, [ebx+ecx*sizeof.xfs_dir2_leaf_entry+xfs_dir2_leaf_entry.address]
ret
.below:
mov edx, ecx
jmp .next
.above:
lea ebx, [ebx+(ecx+1)*sizeof.xfs_dir2_leaf_entry]
sub edx, ecx
dec edx
jmp .next
.not_found:
movi eax, ERROR_FILE_NOT_FOUND
test esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; xfs_GetFileInfo: XFS implementation of getting file info
; in: ebp = pointer to XFS structure
; in: esi = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
proc xfs_GetFileInfo uses ecx edx esi edi
call xfs._.lock
stdcall xfs_get_inode, esi
jnz .error
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
stdcall xfs_get_inode_info, edx, [ebx+f70s5arg.buf]
.quit:
call xfs._.unlock
xor eax, eax
ret
.error:
push eax
call xfs._.unlock
pop eax
ret
endp
 
 
proc xfs._.file.read_extent uses ebx ecx edx, _callback, _callback_data
mov eax, [ebp+XFS.file_offset.lo]
mov edx, [ebp+XFS.file_offset.hi]
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
mov ecx, [ebp+XFS.blocklog]
shld edi, esi, cl
shl esi, cl
cmp edx, edi
jb .hole
ja .try_head
cmp eax, esi
ja .try_head
jz .try_match
.hole:
sub esi, eax
sbb edi, edx
movi ecx, -1
test edi, edi
jnz @f
mov ecx, esi
@@:
cmp ecx, [ebp+XFS.bytes_to_read]
jbe @f
mov ecx, [ebp+XFS.bytes_to_read]
@@:
mov edi, [ebp+XFS.file_buffer]
xor eax, eax
sub [ebp+XFS.bytes_to_read], ecx
sub [ebp+XFS.bytes_left_in_file.lo], ecx
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], ecx
add [ebp+XFS.file_buffer], ecx
add [ebp+XFS.file_offset.lo], ecx
adc [ebp+XFS.file_offset.hi], 0
rep stosb
cmp [ebp+XFS.bytes_to_read], 0
jz .quit
jmp .try_match
.try_head:
mov eax, [ebp+XFS.file_offset.lo]
mov ecx, [ebp+XFS.blocksize]
dec ecx
test eax, ecx
jz .try_match
.head:
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.cur_block_data]
stdcall xfs._.read_block
mov esi, [ebp+XFS.cur_block_data]
mov edi, [ebp+XFS.file_buffer]
mov eax, [ebp+XFS.file_offset.lo]
mov ecx, [ebp+XFS.blocksize]
dec ecx
and eax, ecx
add esi, eax
inc ecx
sub ecx, eax
cmp ecx, [ebp+XFS.bytes_to_read]
jbe @f
mov ecx, [ebp+XFS.bytes_to_read]
@@:
sub [ebp+XFS.bytes_to_read], ecx
sub [ebp+XFS.bytes_left_in_file.lo], ecx
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], ecx
add [ebp+XFS.file_buffer], ecx
add [ebp+XFS.file_offset.lo], ecx
adc [ebp+XFS.file_offset.hi], 0
rep movsb
add [ebp+XFS.extent.br_startoff.lo], 1
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], 1
adc [ebp+XFS.extent.br_startblock.hi], 0
dec [ebp+XFS.extent.br_blockcount]
; cmp [ebp+XFS.bytes_to_read], 0
jz .quit
.try_match:
mov eax, [ebp+XFS.bytes_to_read]
test eax, eax
jz .quit
cmp eax, [ebp+XFS.blocksize]
jb .tail
mov ecx, [ebp+XFS.blocklog]
shr eax, cl
cmp eax, [ebp+XFS.extent.br_blockcount]
jbe @f
mov eax, [ebp+XFS.extent.br_blockcount]
@@:
mov ecx, eax
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.file_buffer]
push ecx
stdcall xfs._.read_blocks
pop eax
add [ebp+XFS.extent.br_startoff.lo], eax
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], eax
adc [ebp+XFS.extent.br_startblock.hi], 0
sub [ebp+XFS.extent.br_blockcount], eax
imul eax, [ebp+XFS.blocksize]
sub [ebp+XFS.bytes_to_read], eax
sub [ebp+XFS.bytes_left_in_file.lo], eax
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], eax
add [ebp+XFS.file_buffer], eax
add [ebp+XFS.file_offset.lo], eax
adc [ebp+XFS.file_offset.hi], 0
; cmp [ebp+XFS.bytes_to_read], 0
cmp [ebp+XFS.extent.br_blockcount], 0
jz .quit
.tail:
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.cur_block_data]
stdcall xfs._.read_block
mov ecx, [ebp+XFS.bytes_to_read]
cmp [ebp+XFS.bytes_left_in_file.hi], 0
jnz @f
cmp ecx, [ebp+XFS.bytes_left_in_file.lo]
jbe @f
mov ecx, [ebp+XFS.bytes_left_in_file.lo]
@@:
mov esi, [ebp+XFS.cur_block_data]
mov edi, [ebp+XFS.file_buffer]
mov eax, ecx
rep movsb
add [ebp+XFS.bytes_read], eax
sub [ebp+XFS.bytes_to_read], eax
sub [ebp+XFS.bytes_left_in_file.lo], eax
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.file_buffer], eax
add [ebp+XFS.file_offset.lo], eax
adc [ebp+XFS.file_offset.hi], 0
add [ebp+XFS.extent.br_startoff.lo], 1
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], 1
adc [ebp+XFS.extent.br_startblock.hi], 0
dec [ebp+XFS.extent.br_blockcount]
.quit:
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; in: ebp = pointer to XFS structure
; in: esi = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
proc xfs_Read uses ecx edx esi edi
locals
.offset_begin DQ ?
.offset_end DQ ?
endl
call xfs._.lock
mov [ebp+XFS.bytes_read], 0
mov eax, [ebx+f70s0arg.count]
mov [ebp+XFS.bytes_to_read], eax
test eax, eax
jz .quit
mov eax, [ebx+f70s0arg.buf]
mov [ebp+XFS.file_buffer], eax
mov eax, [ebx+f70s0arg.offset.hi]
mov [ebp+XFS.file_offset.hi], eax
mov eax, [ebx+f70s0arg.offset.lo]
mov [ebp+XFS.file_offset.lo], eax
 
stdcall xfs_get_inode, esi
jnz .error
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
mov [ebp+XFS.cur_inode_save], edx
mov ebx, edx
; precompute .offset_begin
mov esi, [ebp+XFS.file_offset.lo]
mov edi, [ebp+XFS.file_offset.hi]
mov ecx, [ebp+XFS.blocklog]
shrd esi, edi, cl
shr edi, cl
mov [.offset_begin.lo], esi
mov [.offset_begin.hi], edi
; precompute .offset_end
mov esi, [ebp+XFS.file_offset.lo]
mov edi, [ebp+XFS.file_offset.hi]
add esi, [ebp+XFS.bytes_to_read]
adc edi, 0
mov ecx, [ebp+XFS.blocksize]
dec ecx
add esi, ecx
adc edi, 0
mov ecx, [ebp+XFS.blocklog]
shrd esi, edi, cl
shr edi, cl
mov [.offset_end.lo], esi
mov [.offset_end.hi], edi
 
movbe ecx, [ebx+xfs_inode.di_core.di_size.hi]
movbe edx, [ebx+xfs_inode.di_core.di_size.lo]
mov [ebp+XFS.bytes_left_in_file.lo], ecx
mov [ebp+XFS.bytes_left_in_file.hi], edx
 
sub ecx, [ebp+XFS.file_offset.lo]
sbb edx, [ebp+XFS.file_offset.hi]
movi eax, ERROR_END_OF_FILE
jb .error
mov [ebp+XFS.eof], 0
test edx, edx
jnz @f
cmp ecx, [ebp+XFS.bytes_to_read]
jae @f
mov [ebp+XFS.eof], ERROR_END_OF_FILE
mov [ebp+XFS.bytes_to_read], ecx
@@:
 
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jz .btree
.extent_list:
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ecx, [.offset_begin.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [.offset_begin.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [.offset_end.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [.offset_end.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_extent_list, edx, eax, xfs._.file.read_extent, 0, 0
jnz .error
jmp .hole_check
.btree:
mov eax, [ebp+XFS.inodesize]
sub eax, [ebp+XFS.inode_core_size]
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
mov edx, ebx
add edx, [ebp+XFS.inode_core_size]
mov ecx, [.offset_begin.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [.offset_begin.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [.offset_end.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [.offset_end.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_btree, edx, eax, xfs._.file.read_extent, 0, 0, 1
.hole_check:
cmp [ebp+XFS.bytes_left_in_file.hi], 0
jnz @f
cmp [ebp+XFS.bytes_left_in_file.lo], 0
jz .hole_done
@@:
cmp [ebp+XFS.bytes_to_read], 0
jz .hole_done
mov ebx, [ebp+XFS.cur_inode_save]
movbe edx, [ebx+xfs_inode.di_core.di_size.lo]
movbe eax, [ebx+xfs_inode.di_core.di_size.hi]
sub eax, [ebp+XFS.file_offset.lo]
sbb edx, [ebp+XFS.file_offset.hi]
jc .hole_done
mov ecx, [ebp+XFS.bytes_to_read]
test edx, edx
jnz .hole_read
cmp eax, [ebp+XFS.bytes_to_read]
jae .hole_read
mov ecx, eax
jmp .hole_read
.hole_read:
sub [ebp+XFS.bytes_to_read], ecx
add [ebp+XFS.bytes_read], ecx
mov edi, [ebp+XFS.file_buffer]
xor eax, eax
rep stosb
.hole_done:
.quit:
mov eax, [ebp+XFS.eof]
.error:
push eax
call xfs._.unlock
pop eax
mov ebx, [ebp+XFS.bytes_read]
ret
endp
 
 
proc xfs._.leafn_calc_entries uses ebx ecx edx esi edi, _cur_dirblock, _offset_lo, _offset_hi, _arg
mov edx, [_cur_dirblock]
movzx eax, [ebp+XFS.da_node_magic]
cmp [edx+xfs_dir2_leaf.hdr.info.magic], ax
jz .quit
cmp [ebp+XFS.version], 5
jnz @f
add edx, xfs_dir3_leaf.hdr.count-xfs_dir2_leaf.hdr.count
@@:
movzx eax, [edx+xfs_dir2_leaf.hdr.count]
movzx ecx, [edx+xfs_dir2_leaf.hdr.stale]
xchg al, ah
xchg cl, ch
sub eax, ecx
add [ebp+XFS.entries_read], eax
.quit:
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
proc xfs._.get_before_by_hashval uses ebx edx esi edi, _base, _count, _hash
mov edi, [_hash]
mov edx, [_count]
xor ecx, ecx
.node.next:
movbe eax, [ebx+xfs_da_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.hashval]
cmp [ebp+XFS.version], 5
jnz @f
movbe eax, [ebx+xfs_da3_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.hashval]
@@:
cmp eax, edi
ja .node.leaf_found
inc ecx
cmp ecx, edx
jnz .node.next
movi eax, ERROR_FILE_NOT_FOUND
test esp, esp
jmp .error
.node.leaf_found:
movbe eax, [ebx+xfs_da_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.before]
cmp [ebp+XFS.version], 5
jnz @f
movbe eax, [ebx+xfs_da3_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.before]
@@:
jmp .quit
.error:
test esp, esp
ret
.quit:
cmp esp, esp
ret
endp
 
 
proc xfs._.long_btree.seek uses ebx esi edi, _ptr, _size
mov ebx, [_ptr]
mov esi, [_size]
sub esi, sizeof.xfs_bmdr_block
shr esi, 4
shl esi, 3
movzx eax, [ebx+xfs_bmdr_block.bb_level]
movzx ecx, [ebx+xfs_bmdr_block.bb_numrecs]
xchg cl, ch
add ebx, sizeof.xfs_bmdr_block
jmp .common
.not_root:
mov esi, [ebp+XFS.blocksize]
sub esi, sizeof.xfs_bmbt_block
shr esi, 4
shl esi, 3
movzx eax, [ebx+xfs_bmbt_block.bb_level]
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
xchg cl, ch
add ebx, sizeof.xfs_bmbt_block
.common:
test eax, eax
jz .leaf
.node:
.next_rec:
dec ecx
js .error
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_key+xfs_bmbt_key.br_startoff.lo]
cmp [ebp+XFS.offset_begin.hi], eax
ja .node_found
jb .next_rec
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_key+xfs_bmbt_key.br_startoff.hi]
cmp [ebp+XFS.offset_begin.lo], eax
jae .node_found
jmp .next_rec
.node_found:
add ebx, esi
movbe edx, [ebx+ecx*sizeof.xfs_bmbt_ptr+xfs_bmbt_ptr.lo]
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_ptr+xfs_bmbt_ptr.hi]
mov ebx, [ebp+XFS.cur_block]
stdcall xfs._.read_block
test eax, eax
jnz .error
mov ebx, [ebp+XFS.cur_block]
jmp .not_root
.leaf:
jmp .quit
.error:
.quit:
ret
endp
 
 
proc xfs._.walk_btree uses ebx esi edi, _ptr, _size, _callback_extent, _callback_block, _callback_data, _is_root
stdcall xfs._.long_btree.seek, [_ptr+4], [_size]
mov [_is_root], 0
.begin:
mov ebx, [ebp+XFS.cur_block]
mov eax, [ebp+XFS.bmap_magic]
cmp [ebx+xfs_bmbt_block.bb_magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
xchg cl, ch
add ebx, [ebp+XFS.bmbt_block_size]
stdcall xfs._.walk_extent_list, ecx, ebx, [_callback_extent+8], [_callback_block+4], [_callback_data]
jnz .error
mov esi, [ebp+XFS.offset_begin.lo]
mov edi, [ebp+XFS.offset_begin.hi]
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
sub ebx, [ebp+XFS.bmbt_block_size]
movbe edx, [ebx+xfs_bmbt_block.bb_rightsib.lo]
movbe eax, [ebx+xfs_bmbt_block.bb_rightsib.hi]
mov ecx, eax
and ecx, edx
inc ecx
jz .quit
mov ebx, [ebp+XFS.cur_block]
stdcall xfs._.read_block
jnz .error
jmp .begin
.error:
.quit:
ret
endp
 
 
proc xfs._.btree_read_block uses ebx esi edi, _tree, _size, _block_lo, _block_hi, _buf
mov eax, [_block_lo]
mov [ebp+XFS.offset_begin.lo], eax
mov eax, [_block_hi]
mov [ebp+XFS.offset_begin.hi], eax
stdcall xfs._.long_btree.seek, [_tree+4], [_size]
jnz .error
mov ebx, [ebp+XFS.cur_block]
mov eax, [ebp+XFS.bmap_magic]
cmp [ebx+xfs_bmbt_block.bb_magic], eax
jnz .error
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
xchg cl, ch
add ebx, [ebp+XFS.bmbt_block_size]
mov eax, [_block_lo]
mov [ebp+XFS.offset_begin.lo], eax
mov eax, [_block_hi]
mov [ebp+XFS.offset_begin.hi], eax
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [_buf]
.error:
.quit:
ret
endp
 
 
proc xfs._.extent_list.seek uses esi, _count
sub ebx, sizeof.xfs_bmbt_rec
inc [_count]
.find_low:
add ebx, sizeof.xfs_bmbt_rec
dec [_count]
jz .quit
stdcall xfs._.extent_unpack, ebx
mov eax, [ebp+XFS.extent.br_startoff.lo]
mov edx, [ebp+XFS.extent.br_startoff.hi]
mov esi, [ebp+XFS.extent.br_blockcount]
add eax, esi
adc edx, 0
 
cmp edx, [ebp+XFS.offset_begin.hi]
ja .low_found
jb .find_low
cmp eax, [ebp+XFS.offset_begin.lo]
ja .low_found
jmp .find_low
.low_found:
add ebx, sizeof.xfs_bmbt_rec
 
mov eax, [ebp+XFS.offset_begin.lo]
mov edx, [ebp+XFS.offset_begin.hi]
mov esi, eax
sub esi, [ebp+XFS.extent.br_startoff.lo]
jbe .quit
; same br_blockcount for block and dirblock?
mov [ebp+XFS.extent.br_startoff.lo], eax
mov [ebp+XFS.extent.br_startoff.hi], edx
sub [ebp+XFS.extent.br_blockcount], esi
add [ebp+XFS.extent.br_startblock.lo], esi
adc [ebp+XFS.extent.br_startblock.hi], 0
jmp .quit
.quit:
mov eax, [_count]
ret
endp
 
 
proc xfs._.extent_iterate_dirblocks _callback, _callback_data
.check_high:
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
jb .read_dirblock
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
.read_dirblock:
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
mov edx, [ebp+XFS.cur_dirblock]
mov eax, [_callback]
stdcall eax, edx, esi, edi, [_callback_data]
test eax, eax
jnz .error
mov eax, [ebp+XFS.blkpdirblk]
add esi, eax
adc edi, 0
add [ebp+XFS.extent.br_startblock.lo], eax
adc [ebp+XFS.extent.br_startblock.hi], 0
sub [ebp+XFS.extent.br_blockcount], eax
jnz .check_high
.error:
.quit:
ret
endp
 
 
proc xfs._.walk_extent_list uses ebx esi edi, _count, _ptr, _callback_extent, _callback_block, _callback_data
mov ebx, [_ptr]
stdcall xfs._.extent_list.seek, [_count]
mov [_count], eax
dec [_count]
js .quit
jmp .next_extent.decoded
.next_extent:
stdcall xfs._.extent_unpack, ebx
add ebx, sizeof.xfs_bmbt_rec
.next_extent.decoded:
mov eax, [ebp+XFS.extent.br_blockcount]
add [ebp+XFS.offset_begin.lo], eax
adc [ebp+XFS.offset_begin.hi], 0
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
stdcall [_callback_extent+8], [_callback_block+4], [_callback_data]
jnz .error
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
jb @f
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
@@:
dec [_count]
js .quit
jmp .next_extent
.quit:
movi eax, ERROR_SUCCESS
.error:
test eax, eax
ret
endp
 
 
proc xfs._.get_last_dirblock uses ecx
movbe eax, [ebx+xfs_inode.di_core.di_nextents]
assert (sizeof.xfs_bmbt_rec AND (sizeof.xfs_bmbt_rec - 1)) = 0
shl eax, BSF sizeof.xfs_bmbt_rec
add eax, [ebp+XFS.inode_core_size]
lea eax, [ebx+eax-sizeof.xfs_bmbt_rec]
stdcall xfs._.extent_unpack, eax
xor edx, edx
mov eax, [ebp+XFS.extent.br_blockcount]
mov ecx, [ebp+XFS.dirblklog]
shr eax, cl
dec eax
add eax, [ebp+XFS.extent.br_startoff.lo]
adc edx, [ebp+XFS.extent.br_startoff.hi]
ret
endp
 
 
restore prologue@proc,epilogue@proc
restore movbe
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/xfs.inc
0,0 → 1,622
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; file types from stat.h
S_IFMT = 0170000o ; These bits determine file type
S_IFDIR = 0040000o ; Directory
S_IFCHR = 0020000o ; Character device
S_IFBLK = 0060000o ; Block device
S_IFREG = 0100000o ; Regular file
S_IFIFO = 0010000o ; FIFO
S_IFLNK = 0120000o ; Symbolic link
S_IFSOCK = 0140000o ; Socket
 
; XFS null constant: empty fields must be all ones, not zeros!
XFS_NULL = -1
 
XFS_SECT_SB = 0
 
; signatures of file system structures
XFS_AGF_MAGIC = 'XAGF'
XFS_DINODE_MAGIC = 'IN'
XFS_BMAP_MAGIC = 'BMAP'
XFS_DA_NODE_MAGIC = 0xbefe
XFS_DIR2_LEAF1_MAGIC = 0xf1d2
XFS_DIR2_LEAFN_MAGIC = 0xffd2
XFS_DIR2_BLOCK_MAGIC = 'XD2B'
XFS_DIR2_DATA_MAGIC = 'XD2D'
 
XFS_BMAP3_MAGIC = 'BMA3'
XFS_DA3_NODE_MAGIC = 0xbe3e ; non-leaf blocks
XFS_DIR3_LEAF1_MAGIC = 0xf13d ; v3 dir single blks
XFS_DIR3_LEAFN_MAGIC = 0xff3d ; v3 dir multi blks
XFS_DIR3_BLOCK_MAGIC = 'XDB3' ; single block dirs
XFS_DIR3_DATA_MAGIC = 'XDD3' ; multiblock dirs
 
XFS_SB_MAGIC = 'XFSB'
XFS_SB_VERSION_NUMBITS = 0x000f
XFS_SB_VERSION_ALLFBITS = 0xfff0
XFS_SB_VERSION_REALFBITS = 0x0ff0
XFS_SB_VERSION_ATTRBIT = 0x0010
XFS_SB_VERSION_NLINKBIT = 0x0020
XFS_SB_VERSION_QUOTABIT = 0x0040
XFS_SB_VERSION_ALIGNBIT = 0x0080
XFS_SB_VERSION_DALIGNBIT = 0x0100
XFS_SB_VERSION_SHAREDBIT = 0x0200
XFS_SB_VERSION_LOGV2BIT = 0x0400
XFS_SB_VERSION_SECTORBIT = 0x0800
XFS_SB_VERSION_EXTFLGBIT = 0x1000
XFS_SB_VERSION_DIRV2BIT = 0x2000
XFS_SB_VERSION_BORGBIT = 0x4000 ; ASCII only case-insensitive
XFS_SB_VERSION_MOREBITSBIT = 0x8000
 
XFS_SB_VERSION_SUPPORTED = XFS_SB_VERSION_NUMBITS OR \
XFS_SB_VERSION_ATTRBIT OR \
XFS_SB_VERSION_NLINKBIT OR \
XFS_SB_VERSION_QUOTABIT OR \
XFS_SB_VERSION_ALIGNBIT OR \
XFS_SB_VERSION_LOGV2BIT OR \
XFS_SB_VERSION_SECTORBIT OR \
XFS_SB_VERSION_EXTFLGBIT OR \
XFS_SB_VERSION_DIRV2BIT OR \
XFS_SB_VERSION_MOREBITSBIT
 
XFS_SB_VERSION2_RESERVED1BIT = 0x00000001
XFS_SB_VERSION2_LAZYSBCOUNTBIT = 0x00000002 ; Superblk counters
XFS_SB_VERSION2_RESERVED4BIT = 0x00000004
XFS_SB_VERSION2_ATTR2BIT = 0x00000008 ; Inline attr rework
XFS_SB_VERSION2_PARENTBIT = 0x00000010 ; parent pointers in xattr
XFS_SB_VERSION2_PROJID32BIT = 0x00000080 ; 32 bit project id
XFS_SB_VERSION2_CRCBIT = 0x00000100 ; metadata CRCs
XFS_SB_VERSION2_FTYPE = 0x00000200 ; inode type in dir
 
XFS_SB_VERSION2_SUPPORTED = XFS_SB_VERSION2_LAZYSBCOUNTBIT OR \
XFS_SB_VERSION2_ATTR2BIT OR \
XFS_SB_VERSION2_PARENTBIT OR \
XFS_SB_VERSION2_PROJID32BIT OR \
XFS_SB_VERSION2_CRCBIT OR \
XFS_SB_VERSION2_FTYPE
 
XFS_SB_FEAT_INCOMPAT_FTYPE = 1 ; filetype in dirent
XFS_SB_FEAT_INCOMPAT_SPINODES = 2 ; sparse inode chunks
XFS_SB_FEAT_INCOMPAT_META_UUID = 4 ; metadata UUID
XFS_SB_FEAT_INCOMPAT_SUPPORTED = XFS_SB_FEAT_INCOMPAT_FTYPE OR \
XFS_SB_FEAT_INCOMPAT_SPINODES OR \
XFS_SB_FEAT_INCOMPAT_META_UUID
 
; bitfield lengths for packed extent
; MSB to LSB / left to right
BMBT_EXNTFLAG_BITLEN = 1
BMBT_STARTOFF_BITLEN = 54
BMBT_STARTBLOCK_BITLEN = 52
BMBT_BLOCKCOUNT_BITLEN = 21
 
XFS_DIR2_DATA_ALIGN_LOG = 3
XFS_DIR2_DATA_ALIGN = 1 SHL XFS_DIR2_DATA_ALIGN_LOG
XFS_DIR2_SPACE_SIZE = (1 SHL (32 + XFS_DIR2_DATA_ALIGN_LOG))
XFS_DIR2_DATA_OFFSET = 0*XFS_DIR2_SPACE_SIZE
XFS_DIR2_LEAF_OFFSET = 1*XFS_DIR2_SPACE_SIZE
XFS_DIR2_FREE_OFFSET = 2*XFS_DIR2_SPACE_SIZE
 
; data section magic constants for directories (xfs_dir2_data.h)
XFS_DIR2_DATA_FD_COUNT = 3
 
; valid inode formats
; enum xfs_dinode_fmt (xfs_dinode.h)
XFS_DINODE_FMT_DEV = 0
XFS_DINODE_FMT_LOCAL = 1
XFS_DINODE_FMT_EXTENTS = 2
XFS_DINODE_FMT_BTREE = 3
XFS_DINODE_FMT_UUID = 4
 
; size of the unlinked inode hash table in the agi
XFS_AGI_UNLINKED_BUCKETS = 64
 
; possible extent states
; enum xfs_exntst_t (xfs_bmap_btree.h)
XFS_EXT_NORM = 0
XFS_EXT_UNWRITTEN = 1
XFS_EXT_DMAPI_OFFLINE = 2
XFS_EXT_INVALID = 3
 
; values for inode core flags / di_flags (xfs_dinode.h)
XFS_DIFLAG_REALTIME_BIT = 0 ; file's blocks come from rt area
XFS_DIFLAG_PREALLOC_BIT = 1 ; file space has been preallocated
XFS_DIFLAG_NEWRTBM_BIT = 2 ; for rtbitmap inode, new format
XFS_DIFLAG_NODUMP_BIT = 7 ; do not dump
XFS_DIFLAG_REALTIME = (1 SHL XFS_DIFLAG_REALTIME_BIT)
XFS_DIFLAG_PREALLOC = (1 SHL XFS_DIFLAG_PREALLOC_BIT)
XFS_DIFLAG_NEWRTBM = (1 SHL XFS_DIFLAG_NEWRTBM_BIT)
XFS_DIFLAG_NODUMP = (1 SHL XFS_DIFLAG_NODUMP_BIT)
 
; superblock _ondisk_ structure (xfs_sb.h)
; this is _not_ the partition structure
; for XFS partition structure see XFS below
struct xfs_sb
sb_magicnum dd ? ; signature, must be XFS_SB_MAGIC
sb_blocksize dd ? ; block is the minimal file system unit, in bytes
sb_dblocks DQ ? ; number of data blocks
sb_rblocks DQ ? ; number of realtime blocks
sb_rextents DQ ? ; number of realtime extents
sb_uuid rb 16 ; file system unique identifier
sb_logstart DQ ? ; starting block of log (for internal journal)
sb_rootino DQ ? ; root inode number
sb_rbmino DQ ? ; bitmap inode for realtime extents
sb_rsumino DQ ? ; summary inode for rt bitmap
sb_rextsize dd ? ; realtime extent size, blocks
sb_agblocks dd ? ; size of an allocation group (the last one may be smaller!)
sb_agcount dd ? ; number of allocation groups
sb_rbmblocks dd ? ; number of rt bitmap blocks
sb_logblocks dd ? ; number of log blocks
sb_versionnum dw ? ; header version
sb_sectsize dw ? ; volume sector size in bytes
sb_inodesize dw ? ; inode size, bytes
sb_inopblock dw ? ; inodes per block
sb_fname rb 12 ; inodes per block (aka label)
sb_blocklog db ? ; log2 of sb_blocksize
sb_sectlog db ? ; log2 of sb_blocksize
sb_inodelog db ? ; log2 of sb_inodesize
sb_inopblog db ? ; log2 of sb_inopblock
sb_agblklog db ? ; log2 of sb_agblocks (rounded up!)
sb_rextslog db ? ; log2 of sb_rextents
sb_inprogress db ? ; mkfs is in progress, don't mount
sb_imax_pct db ? ; max % of fs for inode space
; statistics
sb_icount DQ ? ; allocated inodes
sb_ifree DQ ? ; free inodes
sb_fdblocks DQ ? ; free data blocks
sb_frextents DQ ? ; free realtime extents
 
sb_uquotino DQ ? ; user quota inode
sb_gquotino DQ ? ; group quota inode
sb_qflags dw ? ; quota flags
sb_flags db ? ; misc. flags
sb_shared_vn db ? ; shared version number
sb_inoalignmt dd ? ; inode chunk alignment, fsblocks
sb_unit dd ? ; stripe or raid unit
sb_width dd ? ; stripe or raid width
sb_dirblklog db ? ; log2 of dir block size (fsbs)
sb_logsectlog db ? ; log2 of the log sector size
sb_logsectsize dw ? ; sector size for the log, bytes
sb_logsunit dd ? ; stripe unit size for the log
sb_features2 dd ? ; additional feature bits
sb_bad_features2 dd ?
sb_features_compat dd ?
sb_features_ro_compat dd ?
sb_features_incompat dd ?
sb_features_log_incompat dd ?
sb_crc dd ? ; superblock crc
sb_spino_align dd ? ; sparse inode chunk alignment
sb_pquotino DQ ? ; project quota inode
sb_lsn DQ ? ; last write sequence
sb_meta_uuid rb 16 ; metadata file system unique id
ends
 
; structure to store create, access and modification time in inode core
struct xfs_timestamp
t_sec dd ?
t_nsec dd ? ; nanoseconds
ends
 
; inode core structure: basic information about file
struct xfs_dinode_core
di_magic dw ? ; inode magic = XFS_DINODE_MAGIC
di_mode dw ? ; mode and type of file
di_version db ? ; inode version
di_format db ? ; format of di_c data
di_onlink dw ? ; old number of links to file
di_uid dd ? ; owner's user id
di_gid dd ? ; owner's group id
di_nlink dd ? ; number of links to file
di_projid dw ? ; owner's project id
di_pad rb 8 ; unused, zeroed space
di_flushiter dw ? ; incremented on flush
di_atime xfs_timestamp ; time last accessed
di_mtime xfs_timestamp ; time last modified
di_ctime xfs_timestamp ; time created/inode modified
di_size DQ ? ; number of bytes in file
di_nblocks DQ ? ; number of direct & btree blocks used
di_extsize dd ? ; basic/minimum extent size for file
di_nextents dd ? ; number of extents in data fork
di_anextents dw ? ; number of extents in attribute fork
di_forkoff db ? ; attr fork offs, <<3 for 64b align
di_aformat db ? ; format of attr fork's data
di_dmevmask dd ? ; DMIG event mask
di_dmstate dw ? ; DMIG state info
di_flags dw ? ; random flags, XFS_DIFLAG_...
di_gen dd ? ; generation number
di_next_unlinked dd ? ; unlinked but still used inode (if any, XFS_NULL otherwise)
ends
 
struct xfs_dinode3_core xfs_dinode_core
di_crc dd ? ; CRC of the inode
di_changecount DQ ? ; number of attribute changes
di_lsn DQ ? ; flush sequence
di_flags2 DQ ? ; more random flags
di_cowextsize dd ? ; basic cow extent size for file
di_pad2 rb 12 ; more padding for future expansion
 
; fields only written to during inode creation
di_crtime xfs_timestamp ; time created
di_ino DQ ? ; inode number
di_uuid rb 16 ; UUID of the filesystem
ends
 
 
struct xfs_dir2_sf_hdr
count db ?
i8count db ?
parent DQ ? ; parent inode number, 4 or 8 bytes
ends
 
struct xfs_dir2_sf_entry
namelen db ? ; actual name length (ASCII)
offset rb 2 ; saved offset
name db ? ; name, variable size
inumber DQ ? ; 4 or 8 bytes
ends
 
struct xfs_dir2_sf
hdr xfs_dir2_sf_hdr
entries xfs_dir2_sf_entry
ends
 
; active entry in a data block
; aligned to 8 bytes
; tag appears as the last 2 bytes
struct xfs_dir2_data_entry
inumber DQ ?
namelen db ?
name db ? ; name bytes array without terminator
; tag dw ? ; starting offset of the entry
ends
 
; unused entry in a data block
struct xfs_dir2_data_unused
freetag dw ? ; XFS_DIR2_DATA_FREE_TAG aka XFS_NULL
length dw ? ; total free length
; tag dw ? ; starting offset of the entry
ends
 
; generic data entry
struct xfs_dir2_data_union
union
xentry xfs_dir2_data_entry
unused xfs_dir2_data_unused
ends
ends
 
; describe a free area in the data block
; the freespace will be formatted as a xfs_dir2_data_unused_t
struct xfs_dir2_data_free
offset dw ? ; start of freespace
length dw ? ; length of freespace
ends
 
; header for the data blocks
; always at the beginning of a directory-sized block
; the code knows that XFS_DIR2_DATA_FD_COUNT is 3
struct xfs_dir2_data_hdr
magic dd ? ; XFS_DIR2_DATA_MAGIC or XFS_DIR2_BLOCK_MAGIC
bestfree xfs_dir2_data_free
bestfree2 xfs_dir2_data_free
bestfree3 xfs_dir2_data_free
ends
 
struct xfs_dir3_data_hdr xfs_dir2_data_hdr
magic3 dd ?
crc dd ?
blkno DQ ?
lsn DQ ?
uuid rb 16
owner DQ ?
ends
 
; leaf block entry
struct xfs_dir2_leaf_entry
hashval dd ? ; hash value of name
address dd ? ; address of data entry
ends
 
; the tail of directory block
struct xfs_dir2_block_tail
count dd ? ; count of leaf entries
stale dd ? ; count of stale leaf entries
ends
 
; generic single-block structure, for xfs_db
struct xfs_dir2_block
hdr xfs_dir2_data_hdr ; magic XFS_DIR2_DATA_MAGIC
u xfs_dir2_data_union
; leaf xfs_dir2_leaf_entry
; tail xfs_dir2_block_tail
ends
 
struct xfs_da_blkinfo
forw dd ? ; previous block in list
back dd ? ; following block in list
magic dw ? ; validity check on block
pad dw ? ; unused
ends
 
struct xfs_dir2_leaf_hdr
info xfs_da_blkinfo
count dw ?
stale dw ?
ends
 
struct xfs_da3_blkinfo xfs_da_blkinfo
crc dd ? ; CRC of block
blkno DQ ? ; first block of the buffer
lsn DQ ? ; sequence number of last write
uuid rb 16 ; filesystem we belong to
owner DQ ? ; inode that owns the block
ends
 
struct xfs_dir3_leaf_hdr
info xfs_da3_blkinfo
count dw ?
stale dw ?
pad dd ?
ends
 
; bests and tail are at the end of the block for single-leaf only
; (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC)
struct xfs_dir2_leaf
hdr xfs_dir2_leaf_hdr
ents xfs_dir2_leaf_entry
; bests dw ?
; tail xfs_dir2_leaf_tail
ends
 
struct xfs_dir3_leaf
hdr xfs_dir3_leaf_hdr
ents xfs_dir2_leaf_entry
; bests
; tail
ends
 
struct xfs_dir2_free_hdr
magic dd ? ; XFS_DIR2_FREE_MAGIC
firstdb dd ? ; db of first entry
nvalid dd ? ; count of valid entries
nused dd ? ; count of used entries
ends
 
struct xfs_da_node_hdr
info xfs_da_blkinfo
count dw ?
level dw ?
ends
 
struct xfs_da_node_entry
hashval dd ? ; hash value for this descendant
before dd ? ; Btree block before this key
ends
 
struct xfs_da_intnode
hdr xfs_da_node_hdr
btree xfs_da_node_entry
ends
 
struct xfs_da3_node_hdr
info xfs_da3_blkinfo
count dw ?
level dw ?
pad dd ?
ends
 
struct xfs_da3_intnode
hdr xfs_da3_node_hdr
btree xfs_da_node_entry
ends
 
; packet extent
struct xfs_bmbt_rec
l0 DQ ?
l1 DQ ?
ends
 
; unpacked extent
struct xfs_bmbt_irec
br_startoff DQ ?
br_startblock DQ ?
br_blockcount dd ?
br_state dd ?
ends
 
struct xfs_dir2_bmx
bmx xfs_bmbt_rec
ends
 
; bmap root header
struct xfs_bmdr_block
bb_level dw ? ; 0 is a leaf
bb_numrecs dw ? ; current number of data records
ends
 
; key structure for non-leaf levels of the tree
struct xfs_bmbt_key
br_startoff DQ ? ; starting file offset
ends
 
struct xfs_bmdr_ptr DQ
ends
 
struct xfs_bmbt_ptr DQ
ends
 
; long form header: bmap btrees
; xfs_btree_lblock is xfs_bmbt_block (xfs_btree.h)
struct xfs_bmbt_block
bb_magic dd ? ; magic number for block type
bb_level dw ? ; 0 is a leaf
bb_numrecs dw ? ; current number of data records
bb_leftsib DQ ? ; left sibling block or NULLDFSBNO
bb_rightsib DQ ? ; right sibling block or NULLDFSBNO
ends
 
struct xfs_bmbt3_block xfs_bmbt_block
bb_blkno DQ ?
bb_lsn DQ ?
bb_uuid rb 16
bb_owner DQ ?
bb_crc dd ?
bb_pad dd ?
ends
 
struct xfs_inode
di_core xfs_dinode_core ; main info, aka core
union
di_u db ? ; data fork inode part
dir2_sf xfs_dir2_sf
bmx xfs_dir2_bmx
ends
; di_a db ? ; data attribute
ends
 
struct xfs_agf
agf_magicnum dd ? ; magic number == XFS_AGF_MAGIC
agf_versionnum dd ? ; header version == XFS_AGF_VERSION
agf_seqno dd ? ; sequence # starting from 0
agf_length dd ? ; size in blocks of AG
agf_roots dd ?
agf_levels dd ?
agf_flfirst dd ?
agf_fllast dd ?
agf_flcount dd ?
agf_freeblks dd ? ; free blocks in AG
ends
 
; internal data for every XFS partition
; this _is_ XFS partition structure
; most fields are unpacked or bswap'ed values of the superblock, see xfs_sb structure above
struct XFS PARTITION
Lock MUTEX ? ; access mutex
sectsize dd ?
blocksize dd ?
dirblocksize dd ?
inodesize dd ?
rootino DQ ?
versionnum dd ?
version dd ?
features2 dd ?
inopblock dd ?
blkpdirblk dd ?
blocklog dd ?
sectlog dd ?
inodelog dd ?
inopblog dd ?
agblklog dd ?
sectpblog dd ?
dirblklog dd ? ; in fsblocks
sectpblock dd ?
agblocks dd ?
dir2_leaf_offset_blocks DQ ?
dir2_free_offset_blocks DQ ?
agblockmask DQ ?
inode_core_size dd ?
features_incompat dd ?
ftype_size dd ?
dir_block_magic dd ?
dir_data_magic dd ?
dir_leaf1_magic dw ?
dir_leafn_magic dw ?
da_node_magic dw ?
bmap_magic dd ?
bmbt_block_size dd ?
dir_block_size dd ?
dir_data_size dd ?
dir_leaf1_size dd ?
dir_leafn_size dd ?
da_node_size dd ?
da_blkinfo_size dd ?
; helpers, temporary vars, etc
; should go to file descriptor and local vars?
cur_block dd ?
cur_block_data dd ?
cur_inode dd ?
cur_sect dd ?
cur_dirblock dd ?
tmp_inode dd ?
extent xfs_bmbt_irec
bytes_to_read dd ?
bytes_read dd ?
bytes_left_in_file DQ ?
file_offset DQ ?
file_buffer dd ?
entries_read dd ?
requested_cnt dd ?
dir_sf_self_done dd ?
dir_sf_parent_done dd ?
entries_left_in_dir dd ?
entries_to_skip dd ?
max_dirblockaddr dd ?
cur_inode_save dd ?
shortform_inodelen dd ?
bdfe_nameenc dd ?
bdfe_len dd ?
bdfe_process dd ?
inode_self DQ ?
bdfe_buf dd ?
eof dd ?
offset_begin DQ ?
offset_end DQ ?
ends
 
struct f70s0arg
sf dd ?
offset DQ ?
count dd ?
buf dd ?
zero db ?
path dd ?
ends
 
struct f70s1arg
sf dd ?
start_idx dd ?
encoding dd ?
count dd ?
buf dd ?
zero db ?
path dd ?
ends
 
struct f70s5arg
sf dd ?
dd ?
xflags dd ? ; name flags is already used
dd ?
buf dd ?
zero db ?
path dd ?
ends
 
struct bdfe_hdr
version dd ?
read_cnt dd ?
total_cnt dd ?
zeroed rd 5
ends
 
struct bdfe
attr dd ?
nameenc dd ?
; nameenc db ?
; reserved db 3 dup(?)
ctime dd ?
cdate dd ?
atime dd ?
adate dd ?
mtime dd ?
mdate dd ?
size DQ ?
name db ?
ends
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/fat.inc
0,0 → 1,3152
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; FAT external functions
; in:
; ebx -> parameter structure of sysfunc 70
; ebp -> FAT structure
; esi -> path string in UTF-8
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
fat_user_functions:
dd fat_free
dd (fat_user_functions_end - fat_user_functions - 4) / 4
dd fat_Read
dd fat_ReadFolder
dd fat_CreateFile
dd fat_Write
dd fat_SetFileEnd
dd fat_GetFileInfo
dd fat_SetFileInfo
dd 0
dd fat_Delete
dd fat_CreateFolder
dd fat_Rename
fat_user_functions_end:
endg
 
cache_max = 1919 ; max. is 1919*512+0x610000=0x6ffe00
 
PUSHAD_EAX equ [esp+28]
PUSHAD_ECX equ [esp+24]
PUSHAD_EDX equ [esp+20]
PUSHAD_EBX equ [esp+16]
PUSHAD_EBP equ [esp+8]
PUSHAD_ESI equ [esp+4]
PUSHAD_EDI equ [esp+0]
 
; Internal data for every FAT partition.
struct FAT PARTITION
fs_type db ?
fat_change db ? ; 1=fat has changed
createOption db ?
rb 1
Lock MUTEX ; currently operations with one partition
; can not be executed in parallel since the legacy code is not ready
SECTORS_PER_FAT dd ?
NUMBER_OF_FATS dd ?
SECTORS_PER_CLUSTER dd ?
BYTES_PER_SECTOR dd ? ; Note: if BPS <> 512 need lots of changes
ROOT_CLUSTER dd ? ; first rootdir cluster
FAT_START dd ? ; start of fat table
ROOT_START dd ? ; start of rootdir (only fat16)
ROOT_SECTORS dd ? ; count of rootdir sectors (only fat16)
DATA_START dd ? ; start of data area (=first cluster 2)
LAST_CLUSTER dd ? ; last availabe cluster
ADR_FSINFO dd ? ; used only by fat32
fatRESERVED dd ?
fatBAD dd ?
fatEND dd ?
fatMASK dd ?
fatStartScan dd ?
cluster_tmp dd ? ; used by analyze_directory and analyze_directory_to_write
longname_sec1 dd ? ; used by analyze_directory to save 2 previous
longname_sec2 dd ? ; directory sectors for delete long filename
fat_in_cache dd ?
; For FAT16/FAT32, this points to 512-byte buffer for the current sector of FAT.
; For FAT12, the entire FAT structure is read
; and unpacked from 12bit per cluster to word per cluster.
; Note: work with unpacked copy of FAT12 means
; additional memory and additional code for packing/unpacking.
; I'm not sure that the economy justifies the cost, but anyway,
; there is how work was done before my edits, and I'm just keeping the principle.
fat_cache_ptr dd ?
fat12_unpacked_ptr dd ?
volumeLabel rb 12
buffer rb 512
fsinfo_buffer rb 512
ends
 
uglobal
align 4
partition_count dd ? ; partitions found by set_FAT32_variables
hd_error dd ?
hd_setup dd ?
hd_wait_timeout dd ?
cache_search_start dd ? ; used by find_empty_slot
Sector512: ; label for dev_hdcd.inc
buffer:
rb 512
endg
 
; these labels are located before the main function to make
; most of jumps to these be short
fat_create_partition.free_return0:
mov eax, ebp
call free
pop ebp
fat_create_partition.return0:
xor eax, eax
ret
 
fat_create_partition:
cmp dword [esi+DISK.MediaInfo.SectorSize], 512
jnz .return0
; bootsector must have been successfully read
cmp dword [esp+4], 0
jnz .return0
; bootsector signature must be correct
cmp word [ebx+0x1fe], 0xaa55
jnz .return0
; sectors per cluster must be nonzero
cmp byte [ebx+0xd], 0
jz .return0
; bytes per sector must be 0x200
cmp word [ebx+0xb], 0x200
jnz .return0
; number of fats must be nonzero
cmp byte [ebx+0x10], 0
jz .return0
; The only reason to be invalid partition now is FAT12. Since the test for
; FAT size requires knowledge of some calculated values, which are also used
; in the normal operation, let's hope for the best and allocate data now; if
; it will prove wrong, just deallocate it.
movi eax, sizeof.FAT
call malloc
test eax, eax
jz .return0
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+FAT.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+FAT.FirstSector+4], ecx
mov ecx, dword [ebp+PARTITION.Length]
mov dword [eax+FAT.Length], ecx
mov ecx, dword [ebp+PARTITION.Length+4]
mov dword [eax+FAT.Length+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+FAT.Disk], ecx
mov [eax+FAT.FSUserFunctions], fat_user_functions
or [eax+FAT.fat_in_cache], -1
mov [eax+FAT.fat_change], 0
push ebp
mov ebp, eax
lea ecx, [ebp+FAT.Lock]
call mutex_init
movzx eax, word [ebx+0xe] ; sectors reserved
mov [ebp+FAT.FAT_START], eax
movzx eax, byte [ebx+0xd] ; sectors per cluster
mov [ebp+FAT.SECTORS_PER_CLUSTER], eax
movzx ecx, word [ebx+0xb] ; bytes per sector
mov [ebp+FAT.BYTES_PER_SECTOR], ecx
movzx eax, word [ebx+0x11] ; count of rootdir entries (=0 fat32)
shl eax, 5 ; mul 32
dec ecx
add eax, ecx ; round up if not equal count
inc ecx ; bytes per sector
xor edx, edx
div ecx
mov [ebp+FAT.ROOT_SECTORS], eax ; count of rootdir sectors
movzx eax, word [ebx+0x16] ; sectors per fat <65536
test eax, eax
jnz @f
mov eax, [ebx+0x24] ; sectors per fat
@@:
mov [ebp+FAT.SECTORS_PER_FAT], eax
movzx eax, byte [ebx+0x10] ; number of fats
mov [ebp+FAT.NUMBER_OF_FATS], eax
mul [ebp+FAT.SECTORS_PER_FAT]
test edx, edx
jnz .free_return0
add eax, [ebp+FAT.FAT_START]
jc .free_return0
mov [ebp+FAT.ROOT_START], eax ; rootdir = fat_start + fat_size * fat_count
add eax, [ebp+FAT.ROOT_SECTORS] ; rootdir sectors should be 0 on fat32
jc .free_return0
mov [ebp+FAT.DATA_START], eax ; data area = rootdir + rootdir_size
movzx eax, word [ebx+0x13] ; total sector count <65536
test eax, eax
jnz @f
mov eax, [ebx+0x20] ; total sector count
@@:
cmp dword [ebp+FAT.Length+4], 0
jnz @f
cmp eax, dword [ebp+FAT.Length]
ja .free_return0
@@:
mov dword [ebp+FAT.Length], eax
and dword [ebp+FAT.Length+4], 0
sub eax, [ebp+FAT.DATA_START] ; eax = count of data sectors
jc .free_return0
xor edx, edx
div [ebp+FAT.SECTORS_PER_CLUSTER]
inc eax
mov [ebp+FAT.LAST_CLUSTER], eax
dec eax ; cluster count
jz .free_return0
mov [ebp+FAT.fatStartScan], 2
cmp eax, 0xfff5
jb .fat16
.fat32:
pusha
lea esi, [ebx+71]
lea edi, [ebp+FAT.volumeLabel]
movsd
movsd
movsd
popa
mov eax, [ebx+0x2c] ; rootdir cluster
mov [ebp+FAT.ROOT_CLUSTER], eax
movzx eax, word [ebx+0x30]
mov [ebp+FAT.ADR_FSINFO], eax
push ebx
add ebx, 512
call fs_read32_sys
test eax, eax
jnz @f
mov eax, [ebx+0x1ec]
cmp eax, -1
jz @f
mov [ebp+FAT.fatStartScan], eax
@@:
pop ebx
mov [ebp+FAT.fatRESERVED], 0x0FFFFFF6
mov [ebp+FAT.fatBAD], 0x0FFFFFF7
mov [ebp+FAT.fatEND], 0x0FFFFFF8
mov [ebp+FAT.fatMASK], 0x0FFFFFFF
mov al, 32
.fat_not_12_finalize:
mov [ebp+FAT.fs_type], al
; For FAT16 and FAT32, allocate 512 bytes for FAT cache.
mov eax, 512
call malloc
test eax, eax
jz .free_return0
mov [ebp+FAT.fat_cache_ptr], eax
mov eax, ebp
pop ebp
ret
 
.fat16:
pusha
lea esi, [ebx+43]
lea edi, [ebp+FAT.volumeLabel]
movsd
movsd
movsd
popa
cmp eax, 0xff5
jb .fat12
and [ebp+FAT.ROOT_CLUSTER], 0
mov [ebp+FAT.fatRESERVED], 0x0000FFF6
mov [ebp+FAT.fatBAD], 0x0000FFF7
mov [ebp+FAT.fatEND], 0x0000FFF8
mov [ebp+FAT.fatMASK], 0x0000FFFF
mov al, 16
jmp .fat_not_12_finalize
 
.fat12:
and [ebp+FAT.ROOT_CLUSTER], 0
mov [ebp+FAT.fatRESERVED], 0xFF6
mov [ebp+FAT.fatBAD], 0xFF7
mov [ebp+FAT.fatEND], 0xFFF
mov [ebp+FAT.fatMASK], 0xFFF
mov al, 12
mov [ebp+FAT.fs_type], al
; For FAT12, allocate&read data for entire table:
; calculate A = ALIGN_UP(NUM_CLUSTERS, 8),
; allocate ALIGN_UP(A*3/2, 512) bytes for FAT table plus A*2 bytes for unpacked data.
mov eax, [ebp+FAT.LAST_CLUSTER]
and eax, not 7
add eax, 8
mov edx, eax
lea eax, [eax*3]
add eax, 512*2-1
shr eax, 10
shl eax, 9
lea eax, [eax+edx*2]
call malloc
test eax, eax
jz .free_return0
; Read ALIGN_UP(NUM_CLUSTERS*3/2, 512) bytes.
push ebx
mov [ebp+FAT.fat_cache_ptr], eax
mov edx, [ebp+FAT.LAST_CLUSTER]
lea edx, [(edx+1)*3 + 512*2-1]
shr edx, 10
xchg eax, ebx
xor eax, eax
.read_fat:
push eax
add eax, [ebp+FAT.FAT_START]
call fs_read32_sys
test eax, eax
pop eax
jz @f
mov eax, [ebp+FAT.fat_cache_ptr]
call free
pop ebx
jmp .free_return0
 
@@:
add ebx, 512
inc eax
cmp eax, edx
jb .read_fat
mov [ebp+FAT.fat12_unpacked_ptr], ebx
pushad
mov esi, [ebp+FAT.fat_cache_ptr]
mov edi, [ebp+FAT.fat12_unpacked_ptr]
mov edx, [ebp+FAT.LAST_CLUSTER]
and edx, not 7
lea edx, [edi+(edx+8)*2]
push edx
@@:
mov eax, dword [esi]
mov ebx, dword [esi+4]
mov ecx, dword [esi+8]
mov edx, ecx
shr edx, 4
shr dx, 4
xor ch, ch
shld ecx, ebx, 20
shr cx, 4
shld ebx, eax, 12
and ebx, 0x0fffffff
shr bx, 4
shl eax, 4
and eax, 0x0fffffff
shr ax, 4
mov dword [edi], eax
mov dword [edi+4], ebx
mov dword [edi+8], ecx
mov dword [edi+12], edx
add edi, 16
add esi, 12
cmp edi, [esp]
jnz @b
pop eax
popad
mov eax, ebp
pop ebx ebp
ret
 
fat_free:
push eax
mov eax, [eax+FAT.fat_cache_ptr]
call free
pop eax
jmp free
 
iglobal
label fat_legal_chars byte
; 0 = not allowed
; 1 = allowed only in long names
; 3 = allowed
times 32 db 0
; ! " # $ % & ' ( ) * + , - . /
db 1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0
; 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
db 3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0
; @ A B C D E F G H I J K L M N O
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
; P Q R S T U V W X Y Z [ \ ] ^ _
db 3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3
; ` a b c d e f g h i j k l m n o
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
; p q r s t u v w x y z { | } ~
db 3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0
endg
 
fat_name_is_legal:
; in: esi -> UTF-8 name
; out: CF=1 -> legal
push esi
xor eax, eax
@@:
lodsb
test al, al
js @b
test [fat_legal_chars+eax], 1
jnz @b
test al, al
jnz @f
stc
@@:
pop esi
ret
 
fat_next_short_name:
; in: edi->8+3 name
; out: name corrected, CF=1 -> error
pushad
mov ecx, 8
mov al, '~'
std
push edi
add edi, 7
repnz scasb
pop edi
cld
jz .tilde
; tilde is not found, insert "~1" at end
add edi, 6
cmp word [edi], ' '
jnz .insert_tilde
@@:
dec edi
cmp byte [edi], ' '
jz @b
inc edi
.insert_tilde:
mov word [edi], '~1'
popad
clc
ret
 
.tilde:
push edi
add edi, 7
xor ecx, ecx
@@: ; after tilde may be only digits and trailing spaces
cmp byte [edi], '~'
jz .break
cmp byte [edi], ' '
jz .space
cmp byte [edi], '9'
jnz .found
dec edi
jmp @b
 
.space:
dec edi
inc ecx
jmp @b
 
.found:
inc byte [edi]
add dword [esp], 8
jmp .zerorest
 
.break:
jecxz .noplace
inc edi
mov al, '1'
@@:
xchg al, [edi]
inc edi
cmp al, ' '
mov al, '0'
jnz @b
.succ:
pop edi
popad
clc
ret
 
.noplace:
dec edi
cmp edi, [esp]
jz .err
add dword [esp], 8
mov word [edi], '~1'
inc edi
inc edi
@@:
mov byte [edi], '0'
.zerorest:
inc edi
cmp edi, [esp]
jb @b
pop edi
popad
ret
 
.err:
pop edi
popad
stc
ret
 
fat_gen_short_name:
; in:
; esi -> UTF-8 name
; edi -> buffer (8+3=11 chars)
pushad
mov eax, ' '
push edi
stosd
stosd
stosd
pop edi
xor eax, eax
movi ebx, 8
lea ecx, [edi+8]
.loop:
lodsb
test al, al
js .space
jz .done
test [fat_legal_chars+eax], 2
jz .space
cmp al, '.'
jz .dot
dec bl
jns .store
inc bl
.space:
or bh, 1
jmp .loop
 
.store:
call cp866toUpper
stosb
jmp .loop
 
.dot:
test bh, 2
jz .firstdot
pop ebx
add ebx, edi
sub ebx, ecx
push ebx
cmp ebx, ecx
jb @f
pop ebx
push ecx
@@:
cmp edi, ecx
jbe .skip
@@:
dec edi
mov al, [edi]
dec ebx
mov [ebx], al
mov byte [edi], ' '
cmp edi, ecx
ja @b
.skip:
mov bh, 3
jmp @f
 
.firstdot:
cmp bl, 8
jz .space
push edi
or bh, 2
@@:
mov edi, ecx
mov bl, 3
jmp .loop
 
.done:
test bh, 2
jz @f
pop edi
@@:
lea edi, [ecx-8]
test bh, 1
jz @f
call fat_next_short_name
@@:
popad
ret
 
set_FAT:
; in: eax = cluster, edx = value to save
; out: edx = old value, CF=1 -> error
push eax ebx esi
cmp eax, 2
jc .ret
cmp [ebp+FAT.LAST_CLUSTER], eax
jc .ret
cmp [ebp+FAT.fs_type], 12
je .FAT12
cmp [ebp+FAT.fs_type], 16
je @f
add eax, eax
@@:
add eax, eax
mov esi, 511
and esi, eax
shr eax, 9
add eax, [ebp+FAT.FAT_START]
mov ebx, [ebp+FAT.fat_cache_ptr]
cmp eax, [ebp+FAT.fat_in_cache]
je .inCache
cmp [ebp+FAT.fat_change], 0
je @f
call write_fat_sector
@@:
mov [ebp+FAT.fat_in_cache], eax
call fs_read32_sys
test eax, eax
jne .error
.inCache:
cmp [ebp+FAT.fs_type], 16
jne .test32
xchg [ebx+esi], dx ; save new value and get old value
jmp .write
 
.test32:
mov eax, [ebp+FAT.fatMASK]
and edx, eax
xor eax, -1 ; mask for high bits
and eax, [ebx+esi] ; get high 4 bits
or eax, edx
mov edx, [ebx+esi] ; get old value
mov [ebx+esi], eax ; save new value
.write:
mov [ebp+FAT.fat_change], 1
and edx, [ebp+FAT.fatMASK]
.ret:
pop esi ebx eax
ret
 
.error:
stc
jmp .ret
 
.FAT12:
test edx, 0xF000
jnz .error
mov ebx, [ebp+FAT.fat12_unpacked_ptr]
xchg [ebx+eax*2], dx
mov [ebp+FAT.fat_change], 1
jmp .ret
 
get_FAT:
; in: eax = cluster
; out: eax = next cluster, CF=1 -> error
push ebx esi
cmp [ebp+FAT.fs_type], 12
je .FAT12
cmp [ebp+FAT.fs_type], 16
je @f
add eax, eax
@@:
add eax, eax
mov esi, 511
and esi, eax
shr eax, 9
add eax, [ebp+FAT.FAT_START]
mov ebx, [ebp+FAT.fat_cache_ptr]
cmp eax, [ebp+FAT.fat_in_cache]
je .inCache
cmp [ebp+FAT.fat_change], 0
je @f
call write_fat_sector
@@:
mov [ebp+FAT.fat_in_cache], eax
call fs_read32_sys
test eax, eax
jnz .error
.inCache:
mov eax, [ebx+esi]
and eax, [ebp+FAT.fatMASK]
.ret:
pop esi ebx
ret
 
.error:
stc
jmp .ret
 
.FAT12:
mov ebx, [ebp+FAT.fat12_unpacked_ptr]
movzx eax, word [ebx+eax*2]
jmp .ret
 
get_free_FAT:
; out: eax = number of first free cluster, CF=1 -> disk full
push ecx
mov ecx, [ebp+FAT.LAST_CLUSTER]
mov eax, [ebp+FAT.fatStartScan]
cmp [ebp+FAT.fs_type], 12
jz get_free_FAT12
dec ecx
cmp eax, 2
jb .reset
.test:
cmp eax, [ebp+FAT.LAST_CLUSTER]
jbe .inRange
.reset:
mov eax, 2
.inRange:
push eax
call get_FAT
jc @f
test eax, eax
pop eax
je .found
inc eax
dec ecx
jnz .test
.notFound:
pop ecx
stc
ret
 
@@:
pop eax
jmp .notFound
 
.found:
lea ecx, [eax+1]
mov [ebp+FAT.fatStartScan], ecx
pop ecx
clc
ret
 
get_free_FAT12:
push edx edi
mov edi, [ebp+FAT.fat12_unpacked_ptr]
cmp eax, 2
jb .reset
cmp eax, ecx
jbe @f
.reset:
mov eax, 2
@@:
mov edx, eax
lea edi, [edi+eax*2]
sub ecx, eax
inc ecx
xor eax, eax
repnz scasw
jz .found
cmp edx, 2
jz .notfound
mov edi, [ebp+FAT.fat12_unpacked_ptr]
lea ecx, [edx-2]
repnz scasw
jnz .notfound
.found:
sub edi, [ebp+FAT.fat12_unpacked_ptr]
shr edi, 1
mov [ebp+FAT.fatStartScan], edi
lea eax, [edi-1]
@@:
pop edi edx ecx
ret
 
.notfound:
stc
jmp @b
 
write_fat_sector:
push eax ebx ecx
mov [ebp+FAT.fat_change], 0
mov eax, [ebp+FAT.fat_in_cache]
cmp eax, -1
jz @f
mov ebx, [ebp+FAT.fat_cache_ptr]
mov ecx, [ebp+FAT.NUMBER_OF_FATS]
.write_next_fat:
push eax
call fs_write32_sys
pop eax
add eax, [ebp+FAT.SECTORS_PER_FAT]
dec ecx
jnz .write_next_fat
@@:
pop ecx ebx eax
ret
 
get_date_for_file:
; out in ax:
; bits 0-4 = day
; bits 5-8 = month
; bits 9-15 = count of years from 1980
mov al, 7
call fsReadCMOS
ror eax, 5
mov al, 8
call fsReadCMOS
ror eax, 4
mov al, 9
call fsReadCMOS
add ax, 20
rol eax, 9
ret
 
get_time_for_file:
; out in ax:
; bits 0-4 = second (the low bit is lost)
; bits 5-10 = minute
; bits 11-15 = hour
mov al, 0
call fsReadCMOS
ror eax, 6
mov al, 2
call fsReadCMOS
ror eax, 6
mov al, 4
call fsReadCMOS
rol eax, 11
ret
 
add_disk_free_space:
; in: ecx = cluster count (signed)
test ecx, ecx
je .ret
cmp [ebp+FAT.fs_type], 32
jne .ret
push eax ebx
mov eax, [ebp+FAT.ADR_FSINFO]
lea ebx, [ebp+FAT.fsinfo_buffer]
call fs_read32_sys
test eax, eax
jnz @f
cmp dword [ebx+0x1fc], 0xaa550000 ; check sector id
jne @f
add [ebx+0x1e8], ecx
push [ebp+FAT.fatStartScan]
pop dword [ebx+0x1ec]
mov eax, [ebp+FAT.ADR_FSINFO]
call fs_write32_sys
@@:
pop ebx eax
.ret:
ret
 
clear_cluster_chain:
; in: eax = first cluster
push eax ecx edx
xor ecx, ecx ; cluster count
@@:
cmp eax, [ebp+FAT.LAST_CLUSTER]
ja @f
cmp eax, 2
jb @f
cmp eax, [ebp+FAT.ROOT_CLUSTER]
jz @f
xor edx, edx
call set_FAT
jc .ret
inc ecx
mov eax, edx
jmp @b
 
@@:
call add_disk_free_space
clc
.ret:
pop edx ecx eax
ret
 
update_disk:
cmp [ebp+FAT.fat_change], 0
jz .noChange
cmp [ebp+FAT.fs_type], 12
jz .fat12
call write_fat_sector
.noChange:
mov esi, [ebp+PARTITION.Disk]
call disk_sync
ret
 
.fat12:
mov esi, [ebp+FAT.fat12_unpacked_ptr]
mov edi, [ebp+FAT.fat_cache_ptr]
mov edx, [ebp+FAT.LAST_CLUSTER]
and edx, not 7
lea edx, [esi+(edx+8)*2]
@@:
mov eax, dword [esi]
mov ebx, dword [esi+4]
shl ax, 4
shl eax, 4
shl bx, 4
shr ebx, 4
shrd eax, ebx, 8
shr ebx, 8
mov dword [edi], eax
mov word [edi+4], bx
add edi, 6
add esi, 8
cmp esi, edx
jb @b
mov esi, [ebp+FAT.NUMBER_OF_FATS]
mov edx, [ebp+FAT.LAST_CLUSTER]
lea edx, [(edx+1)*3 + 512*2-1]
shr edx, 10
push [ebp+FAT.FAT_START]
.write_fats:
xor eax, eax
mov ebx, [ebp+FAT.fat_cache_ptr]
.loop1:
push eax
add eax, [esp+4]
call fs_write32_sys
test eax, eax
pop eax
jnz @f
add ebx, 512
inc eax
cmp eax, edx
jb .loop1
pop eax
add eax, [ebp+FAT.SECTORS_PER_FAT]
push eax
dec esi
jnz .write_fats
@@:
pop eax
mov [ebp+FAT.fat_change], 0
jmp .noChange
 
fat_lock:
lea ecx, [ebp+FAT.Lock]
jmp mutex_lock
 
fat_unlock:
lea ecx, [ebp+FAT.Lock]
jmp mutex_unlock
 
fat_get_name:
; in: edi -> FAT entry, esi -> buffer for UTF-16 name
; out: CF=1 -> no valid entry
cmp byte [edi], 0
jz .no
cmp byte [edi], 0xE5
jz .no
cmp byte [edi+11], 0xF
jz .longname
push edi
xchg esi, edi
test byte [esi+11], 8
jnz .label
pushd ecx 8
pop ecx
@@:
lodsb
call ansi2uni_char
stosw
loop @b
mov cl, 8
@@:
cmp word [edi-2], ' '
jnz @f
sub edi, 2
loop @b
@@:
mov word [edi], '.'
add edi, 2
mov cl, 3
@@:
lodsb
call ansi2uni_char
stosw
loop @b
mov cl, 3
@@:
cmp word [edi-2], ' '
jnz @f
sub edi, 2
loop @b
sub edi, 2
@@:
and word [edi], 0 ; CF=0
pop ecx edi
ret
 
.label:
lea edi, [ebp+FAT.volumeLabel]
movsd
movsd
movsd
pop edi
.no:
stc
ret
 
.longname:
mov al, byte [edi]
and eax, 0x3F
dec eax
cmp al, 20
jae .no ; ignore invalid entries
mov word [esi+260*2], 0 ; force null-terminating for orphans
imul eax, 13*2
test byte [edi], 0x40
jz @f
mov word [esi+eax+13*2], 0
@@: ; copy name (13 chars in UTF-16)
push edi
inc edi
add esi, eax
xchg esi, edi
movsd
movsd
movsw
add esi, 3
movsd
movsd
movsd
add esi, 2
movsd
pop edi
test eax, eax
jnz .no ; if this is not first entry, more processing required
ret
 
fat_find_lfn:
; in:
; esi -> path in UTF-8
; parameters in the stack
; out:
; esi -> next name in the path
; edi -> direntry
; CF=1 -> file not found, eax = error code
lea eax, [esp+12]
call dword [eax-4]
jc .reterr
sub esp, 262*2 ; reserve place for LFN
.l1:
push esi
lea esi, [esp+4]
call fat_get_name
pop esi
jc .no
push edi esi
lea edi, [esp+8]
@@:
call utf8to16
call utf16toUpper
mov edx, eax
mov ax, [edi]
call utf16toUpper
cmp ax, dx
jnz .done
add edi, 2
test ax, ax
jnz @b
dec esi
pop eax edi
.found:
add esp, 262*2
; if this is LFN entry, advance to true entry
cmp byte [edi+11], 0xF
jnz @f
lea eax, [esp+12]
call dword[eax-8]
jc .reterr
@@:
xor eax, eax
ret
 
.done:
cmp dx, '/'
jnz @f
test ax, ax
jnz @f
mov [esp], esi
@@:
pop esi edi
jz .found
.no:
lea eax, [esp+262*2+12]
call dword[eax-8]
jnc .l1
add esp, 262*2
.reterr:
stc
ret
 
fat_time_to_bdfe:
; in: eax=FAT time
; out: eax=BDFE time
push ecx edx
mov ecx, eax
mov edx, eax
shr eax, 11
shl eax, 16 ; hours
and edx, 0x1F
add edx, edx
mov al, dl ; seconds
shr ecx, 5
and ecx, 0x3F
mov ah, cl ; minutes
pop edx ecx
ret
 
fat_date_to_bdfe:
push ecx edx
mov ecx, eax
mov edx, eax
shr eax, 9
add ax, 1980
shl eax, 16 ; year
and edx, 0x1F
mov al, dl ; day
shr ecx, 5
and ecx, 0xF
mov ah, cl ; month
pop edx ecx
ret
 
bdfe_to_fat_time:
push edx
mov edx, eax
shr eax, 16
and dh, 0x3F
shl eax, 6
or al, dh
shr dl, 1
and dl, 0x1F
shl eax, 5
or al, dl
pop edx
ret
 
bdfe_to_fat_date:
push edx
mov edx, eax
shr eax, 16
sub ax, 1980
and dh, 0xF
shl eax, 4
or al, dh
and dl, 0x1F
shl eax, 5
or al, dl
pop edx
ret
 
fat_entry_to_bdfe:
; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi
mov eax, [ebp-4]
mov [esi+4], eax ; cp866/UNICODE name
fat_entry_to_bdfe2:
movzx eax, byte [edi+11]
mov [esi], eax ; attributes
movzx eax, word [edi+14]
call fat_time_to_bdfe
mov [esi+8], eax ; creation time
movzx eax, word [edi+16]
call fat_date_to_bdfe
mov [esi+12], eax ; creation date
and dword [esi+16], 0 ; last access time is not supported on FAT
movzx eax, word [edi+18]
call fat_date_to_bdfe
mov [esi+20], eax ; last access date
movzx eax, word [edi+22]
call fat_time_to_bdfe
mov [esi+24], eax ; last write time
movzx eax, word [edi+24]
call fat_date_to_bdfe
mov [esi+28], eax ; last write date
mov eax, [edi+28]
mov [esi+32], eax ; file size (low dword)
xor eax, eax
mov [esi+36], eax ; file size (high dword)
test ebp, ebp
jz .ret
add esi, 40
push edi esi
mov edi, esi
mov esi, ebp
cmp byte [ebp-4], 2
jz .utf16
cmp byte [ebp-4], 3
jz .utf8
@@:
lodsw
call uni2ansi_char
stosb
test al, al
jnz @b
pop esi edi
add esi, 264
.ret:
ret
 
.utf8:
push ecx
mov ecx, 519
call UTF16to8_string
pop ecx
jmp @f
 
.utf16:
lodsw
stosw
test eax, eax
jnz .utf16
@@:
pop esi edi
add esi, 520
ret
 
bdfe_to_fat_entry:
; convert BDFE at edx to FAT entry at edi
; destroys eax
; attributes byte
test byte [edi+11], 8 ; volume label?
jnz @f
mov al, [edx]
and al, 0x27
and byte [edi+11], 0x10
or byte [edi+11], al
@@:
mov eax, [edx+8]
call bdfe_to_fat_time
mov [edi+14], ax ; creation time
mov eax, [edx+12]
call bdfe_to_fat_date
mov [edi+16], ax ; creation date
mov eax, [edx+20]
call bdfe_to_fat_date
mov [edi+18], ax ; last access date
mov eax, [edx+24]
call bdfe_to_fat_time
mov [edi+22], ax ; last write time
mov eax, [edx+28]
call bdfe_to_fat_date
mov [edi+24], ax ; last write date
ret
 
hd_find_lfn:
; in: esi -> path string in UTF-8
; out: CF=1 - file not found, eax=error code
; else CF=0 and edi->direntry, eax=sector
push esi edi
push 0
push 0
push fat1x_root_first
push fat1x_root_next
mov eax, [ebp+FAT.ROOT_CLUSTER]
cmp [ebp+FAT.fs_type], 32
jz .fat32
.loop:
and [ebp+FAT.longname_sec1], 0
and [ebp+FAT.longname_sec2], 0
call fat_find_lfn
jc .notfound
cmp byte [esi], 0
jz .found
test byte [edi+11], 10h
jz .notfound
and dword [esp+12], 0
mov eax, [edi+20-2]
mov ax, [edi+26] ; cluster
.fat32:
mov [esp+8], eax
mov dword [esp+4], fat_notroot_first
mov dword [esp], fat_notroot_next
jmp .loop
 
.notfound:
add esp, 16
pop edi esi
stc
ret
 
.found:
lea eax, [esp+8]
cmp dword [eax], 0
jz .root
call fat_get_sector
jmp .cmn
 
.root:
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
.cmn:
add esp, 20 ; CF=0
pop esi
ret
 
;----------------------------------------------------------------
fat_Read:
call fat_lock
call hd_find_lfn
jc .notFound
test byte [edi+11], 0x10 ; do not allow read directories
jnz .noaccess
cmp dword [ebx+8], 0
jnz .endOfFile
mov edx, [ebx+4] ; file offset
mov ecx, [ebx+12] ; size
mov ebx, [ebx+16] ; buffer
push ebx
push 0
test ecx, ecx
jz .done
mov eax, [edi+28]
sub eax, edx
jb .fileEnd
cmp eax, ecx
jae @f
mov ecx, eax
mov byte [esp], 6
@@:
mov eax, [edi+20-2]
mov ax, [edi+26]
; now eax=cluster, ebx=buffer for data, ecx=count, edx=position
mov edi, [ebp+FAT.SECTORS_PER_CLUSTER]
shl edi, 9
@@:
cmp eax, 2
jb .fileEnd
cmp eax, [ebp+FAT.fatRESERVED]
jae .fileEnd
sub edx, edi
jc @f
call get_FAT
jc .noaccess2
jmp @b
 
.notFound:
push eax
jmp .ret
 
.noaccess:
push ERROR_ACCESS_DENIED
jmp .ret
 
.endOfFile:
push ERROR_END_OF_FILE
.ret:
call fat_unlock
pop eax
xor ebx, ebx
ret
 
@@:
mov esi, eax
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add edx, edi
jz .alignedCluster
mov edi, edx
shr edi, 9
add eax, edi
and edx, 511
cmp ecx, 512
jc .sectorPiece
test edx, edx
jz .alignedSector
.sectorPiece:
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
mov eax, ebx
pop ebx
jne .noaccess3
add eax, edx
push ecx
add ecx, edx
cmp ecx, 512
jbe @f
mov ecx, 512
@@:
sub ecx, edx
call memmove
sub [esp], ecx
add ebx, ecx
pop ecx eax
xor edx, edx
inc edi
inc eax
test ecx, ecx
jz .done
.alignedSector:
shl edi, 9
add ecx, edi
mov edi, [ebp+FAT.SECTORS_PER_CLUSTER]
shl edi, 9
.alignedCluster:
cmp ecx, 512
jc .sectorPiece
mov edx, eax
mov eax, esi
@@:
sub ecx, edi
jbe .readEnd
call get_FAT
jc .noaccess4
cmp eax, 2
jb .fileEnd2
cmp eax, [ebp+FAT.fatRESERVED]
jae .fileEnd2
inc esi
cmp eax, esi
jz @b
.fragmentEnd:
xchg eax, esi
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push ecx
mov ecx, eax
mov eax, esi
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push eax
.readFragment:
sub ecx, edx
mov eax, edx
xor edx, edx
call fs_read64_app
shl ecx, 9
add ebx, ecx
test eax, eax
pop eax
jnz .noaccess3
pop ecx
xor edx, edx
jecxz .done
jmp .alignedCluster
 
.readEnd:
add ecx, edi
mov edi, ecx
and ecx, 511
shr edi, 9
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, edi
push ecx
push eax
mov ecx, eax
jmp .readFragment
 
.noaccess3:
pop eax
.noaccess2:
mov byte [esp], ERROR_DEVICE
.done:
call fat_unlock
pop eax edx
sub ebx, edx
ret
 
.fileEnd:
mov byte [esp], ERROR_END_OF_FILE
jmp .done
 
.noaccess4:
mov byte [esp], ERROR_DEVICE
jmp @f
 
.fileEnd2:
mov byte [esp], ERROR_END_OF_FILE
@@:
inc esi
xor ecx, ecx
jmp .fragmentEnd
 
;----------------------------------------------------------------
fat_ReadFolder:
call fat_lock
mov eax, [ebp+FAT.ROOT_CLUSTER]
cmp byte [esi], 0
jz .doit
call hd_find_lfn
jc .error
test byte [edi+11], 0x10 ; do not allow read files
jz .accessDenied
mov eax, [edi+20-2]
mov ax, [edi+26] ; eax=cluster
.doit:
sub esp, 262*2 ; reserve space for LFN
push dword [ebx+8] ; cp866/UNICODE name
mov edx, [ebx+16] ; pointer to buffer
; init header
push eax
mov edi, edx
mov ecx, 32/4
xor eax, eax
rep stosd
pop eax
mov byte [edx], 1 ; version
mov esi, edi ; esi points to BDFE
mov ecx, [ebx+12] ; number of blocks to read
mov ebx, [ebx+4] ; index of the first block
.new_cluster:
mov [ebp+FAT.cluster_tmp], eax
test eax, eax
jnz @f
cmp [ebp+FAT.fs_type], 32
jz .notfound
mov eax, [ebp+FAT.ROOT_START]
push [ebp+FAT.ROOT_SECTORS]
push ebx
jmp .new_sector
 
@@:
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
push [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push ebx
.new_sector:
lea ebx, [ebp+FAT.buffer]
mov edi, ebx
push eax
call fs_read32_sys
test eax, eax
pop eax
jnz .notfound2
add ebx, 512
push eax
.l1:
push esi
lea esi, [esp+20]
call fat_get_name
pop esi
jc .l2
cmp byte [edi+11], 0xF
jnz .do_bdfe
add edi, 0x20
cmp edi, ebx
jb .do_bdfe
pop eax
inc eax
dec dword [esp+4]
jnz @f
mov eax, [ebp+FAT.cluster_tmp]
test eax, eax
jz .done
call get_FAT
jc .notfound2
cmp eax, 2
jb .done
cmp eax, [ebp+FAT.fatRESERVED]
jae .done
push eax
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
mov [esp+8], eax
pop eax
mov [ebp+FAT.cluster_tmp], eax
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
@@:
lea ebx, [ebp+FAT.buffer]
mov edi, ebx
push eax
call fs_read32_sys
test eax, eax
pop eax
jnz .notfound2
add ebx, 512
push eax
.do_bdfe:
inc dword [edx+8] ; new file found
dec dword [esp+4]
jns .l2
dec ecx
js .l2
inc dword [edx+4] ; new file block copied
push ebp
lea ebp, [esp+20]
call fat_entry_to_bdfe
pop ebp
.l2:
add edi, 0x20
cmp edi, ebx
jb .l1
pop eax
inc eax
dec dword [esp+4]
jnz .new_sector
mov eax, [ebp+FAT.cluster_tmp]
test eax, eax
jz .done
call get_FAT
jc .notfound2
cmp eax, 2
jb .done
cmp eax, [ebp+FAT.fatRESERVED]
jae .done
push eax
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
mov [esp+8], eax
pop eax
pop ebx
add esp, 4
jmp .new_cluster
 
.notfound2:
add esp, 8
.notfound:
add esp, 262*2+4
push ERROR_DEVICE
jmp @f
 
.done:
add esp, 262*2+12
pushd 0
dec ecx
js @f
mov byte [esp], ERROR_END_OF_FILE
@@:
mov ebx, [edx+4]
.ret:
call fat_unlock
pop eax
ret
 
.error:
push eax
xor ebx, ebx
jmp .ret
 
.accessDenied:
push ERROR_ACCESS_DENIED
xor ebx, ebx
jmp .ret
 
fat1x_root_next:
push ecx
lea ecx, [ebp+FAT.buffer+0x200-0x20]
cmp edi, ecx
jae fat1x_root_next_sector
add edi, 0x20
@@:
pop ecx
ret
 
fat1x_root_next_write:
push ecx
lea ecx, [ebp+FAT.buffer+0x200]
cmp edi, ecx
jc @b
call fat1x_root_end_write
fat1x_root_next_sector:
push [ebp+FAT.longname_sec2]
pop [ebp+FAT.longname_sec1]
mov ecx, [eax+4]
push ecx
add ecx, [ebp+FAT.ROOT_START]
mov [ebp+FAT.longname_sec2], ecx
pop ecx
inc ecx
mov [eax+4], ecx
cmp ecx, [ebp+FAT.ROOT_SECTORS]
jnc fat_notroot_next_err
pop ecx
fat1x_root_first:
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
push ebx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
call fs_read32_sys
pop ebx
test eax, eax
jz @f
movi eax, ERROR_DEVICE
stc
@@:
ret
 
fat1x_root_begin_write:
push edi eax
call fat1x_root_first
pop eax edi
ret
 
fat1x_root_end_write:
pusha
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
popa
ret
 
fat_notroot_next:
push ecx
lea ecx, [ebp+FAT.buffer+0x200-0x20]
cmp edi, ecx
jae fat_notroot_next_sector
add edi, 0x20
@@:
pop ecx
ret
 
fat_notroot_next_write:
push ecx
lea ecx, [ebp+FAT.buffer+0x200]
cmp edi, ecx
jc @b
push eax
call fat_notroot_end_write
pop eax
fat_notroot_next_sector:
push [ebp+FAT.longname_sec2]
pop [ebp+FAT.longname_sec1]
push eax
call fat_get_sector
mov [ebp+FAT.longname_sec2], eax
pop eax
mov ecx, [eax+4]
inc ecx
cmp ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
jae fat_notroot_next_cluster
mov [eax+4], ecx
jmp @f
 
fat_notroot_next_err:
pop ecx
movi eax, ERROR_FILE_NOT_FOUND
fat1x_root_extend_dir:
stc
ret
 
fat_notroot_next_cluster:
push eax
mov eax, [eax]
call get_FAT
mov ecx, eax
pop eax
jc fat_notroot_first.deverr
cmp ecx, 2
jb fat_notroot_next_err
cmp ecx, [ebp+FAT.fatRESERVED]
jae fat_notroot_next_err
mov [eax], ecx
and dword [eax+4], 0
@@:
pop ecx
fat_notroot_first:
call fat_get_sector
push ebx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
call fs_read32_sys
pop ebx
test eax, eax
jz .ret ; CF=0
push ecx
.deverr:
pop ecx
mov eax, ERROR_DEVICE
stc
.ret:
ret
 
fat_notroot_begin_write:
push eax edi
call fat_notroot_first
pop edi eax
ret
 
fat_notroot_end_write:
call fat_get_sector
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
ret
 
fat_notroot_extend_dir.writeerr:
pop edx
@@:
pop eax
ret
 
fat_notroot_extend_dir:
push eax
call get_free_FAT
jc @b
push edx
mov edx, [ebp+FAT.fatEND]
call set_FAT
jc .writeerr
mov edx, eax
mov eax, [esp+4]
mov eax, [eax]
push edx
call set_FAT
pop edx
jc .writeerr
push ecx
or ecx, -1
call add_disk_free_space
mov ecx, 512/4
lea edi, [ebp+FAT.buffer]
push edi
xor eax, eax
rep stosd
pop edi
pop ecx
mov eax, [esp+4]
mov [eax], edx
and dword [eax+4], 0
pop edx
mov eax, [eax]
dec eax
dec eax
push ebx ecx
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
imul eax, ecx
add eax, [ebp+FAT.DATA_START]
mov ebx, edi
@@:
push eax
call fs_write32_sys
pop eax
inc eax
loop @b
pop ecx ebx eax
clc
ret
 
fat_get_sector:
push ecx
mov ecx, [eax]
dec ecx
dec ecx
imul ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
add ecx, [ebp+FAT.DATA_START]
add ecx, [eax+4]
mov eax, ecx
pop ecx
ret
 
;----------------------------------------------------------------
fat_CreateFolder:
mov [ebp+FAT.createOption], 0
jmp @f
 
fat_CreateFile:
mov [ebp+FAT.createOption], 1
@@:
call fat_lock
mov ecx, [ebx+12]
mov edx, [ebx+16]
.rename:
pushad
xor edi, edi
push esi
@@:
lodsb
test al, al
jz @f
cmp al, '/'
jnz @b
lea edi, [esi-1]
jmp @b
 
@@:
pop esi
test edi, edi
jnz .noroot
mov edx, [ebp+FAT.ROOT_CLUSTER]
cmp [ebp+FAT.fs_type], 32
jz .pushnotroot
xor edx, edx
push edx
push fat1x_root_extend_dir
push fat1x_root_end_write
push fat1x_root_next_write
push fat1x_root_begin_write
push edx
push edx
push fat1x_root_first
push fat1x_root_next
jmp .common1
 
.retNotFound:
movi eax, ERROR_FILE_NOT_FOUND
jmp .ret1
 
.noAccess:
movi eax, ERROR_ACCESS_DENIED
.ret1:
mov [esp+28], eax
call fat_unlock
popad
xor ebx, ebx
ret
 
.full:
movi eax, ERROR_DISK_FULL
jmp .ret1
 
.noroot:
cmp byte [edi+1], 0
jz .noAccess
; check existence
mov byte [edi], 0
push edi
call hd_find_lfn
pop esi
mov byte [esi], '/'
jc .retNotFound
inc esi
test byte [edi+11], 0x10
jz .noAccess ; file
mov edx, [edi+20-2]
mov dx, [edi+26]
movi eax, ERROR_FS_FAIL
cmp edx, 2
jb .ret1
.pushnotroot:
push edx
push fat_notroot_extend_dir
push fat_notroot_end_write
push fat_notroot_next_write
push fat_notroot_begin_write
push 0
push edx
push fat_notroot_first
push fat_notroot_next
.common1:
call fat_find_lfn
jc .notfound
test byte [edi+11], 10h
jz .exists_file
; found directory
add esp, 36
call fat_unlock
popad
xor eax, eax
cmp [ebp+FAT.createOption], 0
jz @f
mov al, ERROR_ACCESS_DENIED
@@:
xor ebx, ebx
ret
 
.exists_file:
cmp [ebp+FAT.createOption], 1
jz @f
add esp, 36
jmp .noAccess
 
@@: ; delete FAT chain
push edi
xor eax, eax
mov dword [edi+28], eax ; zero size
xor ecx, ecx
mov eax, [edi+20-2]
mov ax, [edi+26]
mov word [edi+20], cx
mov word [edi+26], cx
test eax, eax
jz .done1
@@:
cmp eax, [ebp+FAT.fatRESERVED]
jae .done1
xor edx, edx
call set_FAT
mov eax, edx
jc .done1
inc ecx
jmp @b
 
.short_name_found:
pop ecx edi esi
call fat_next_short_name
jnc .test_short_name_loop
.disk_full:
add esp, 12+36
jmp .full
 
.notfound: ; generate short name
call fat_name_is_legal
jc @f
add esp, 36
jmp .retNotFound
 
@@:
sub esp, 12
mov edi, esp
call fat_gen_short_name
.test_short_name_loop:
push esi edi ecx
mov esi, edi
lea eax, [esp+12+12+8]
mov edx, [eax+24]
mov [eax], edx
and dword [eax+4], 0
call dword [eax-4]
jc .found
.test_short_name_entry:
cmp byte [edi+11], 0xF
jz .test_short_name_cont
mov ecx, 11
push esi edi
repz cmpsb
pop edi esi
jz .short_name_found
.test_short_name_cont:
lea eax, [esp+12+12+8]
call dword [eax-8]
jnc .test_short_name_entry
.found:
pop ecx edi esi
; now find space in directory
; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~'
mov al, '~'
push ecx edi
mov ecx, 8
repnz scasb
movi eax, 1 ; 1 entry
jnz .notilde
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
xor ecx, ecx
push esi
@@:
call utf8to16
inc ecx
test ax, ax
jnz @b
pop esi
mov eax, ecx
add eax, 12+13-1
mov ecx, 13
cdq
div ecx
.notilde:
push -1
push -1
push -1
; find <eax> successive entries in directory
xor ecx, ecx
push eax
lea eax, [esp+16+8+12+8]
mov edx, [eax+24]
mov [eax], edx
and dword [eax+4], 0
call dword [eax-4]
pop eax
jnc .scan_dir
.fsfrfe3:
add esp, 12+8+12+36
movi eax, ERROR_DEVICE
jmp .ret1
 
.scan_dir:
cmp byte [edi], 0
jz .free
cmp byte [edi], 0xE5
jz .free
xor ecx, ecx
.scan_cont:
push eax
lea eax, [esp+16+8+12+8]
call dword [eax-8]
mov edx, eax
pop eax
jnc .scan_dir
cmp edx, ERROR_DEVICE
jz .fsfrfe3
push eax
lea eax, [esp+16+8+12+8]
call dword [eax+20] ; extend directory
pop eax
jnc .scan_dir
add esp, 12+8+12+36
jmp .full
 
.free:
test ecx, ecx
jnz @f
mov [esp], edi
mov ecx, [esp+12+8+12+8]
mov [esp+4], ecx
mov ecx, [esp+12+8+12+12]
mov [esp+8], ecx
xor ecx, ecx
@@:
inc ecx
cmp ecx, eax
jb .scan_cont
; found!
push esi ecx
; If creating a directory, allocate one data cluster or fail immediately if this is impossible.
; This prevents from creating an invalid directory entry on a full disk.
cmp [ebp+FAT.createOption], 0
jnz .notFolder
call get_free_FAT
jnc @f
add esp, 8+12+8
jmp .disk_full
 
@@:
mov [esp+8+12+8+12+36+20], eax ; store the cluster somewhere
.notFolder: ; calculate name checksum
mov esi, [esp+8+12]
mov ecx, 11
xor eax, eax
@@:
ror al, 1
add al, [esi]
inc esi
loop @b
pop ecx esi edi
pop dword [esp+8+12+12]
pop dword [esp+8+12+12]
; edi points to first entry in free chunk
dec ecx
jz .nolfn
push esi eax
lea eax, [esp+8+8+12+8]
call dword [eax+8] ; begin write
mov al, 40h
.writelfn:
or al, cl
stosb
mov esi, [esp+4]
push ecx
dec ecx
jz @f
imul ecx, 13
.scroll:
call utf8to16
loop .scroll
@@:
mov cl, 5
call fat_read_symbols
mov ax, 0xF
stosw
mov al, [esp+4]
stosb
mov cl, 6
call fat_read_symbols
xor eax, eax
stosw
mov cl, 2
call fat_read_symbols
pop ecx
lea eax, [esp+8+8+12+8]
call dword [eax+12] ; next write
xor eax, eax
loop .writelfn
pop eax esi
.nolfn:
pop esi
add esp, 16
mov ecx, 11
rep movsb
cmp [ebp+FAT.createOption], 2
jz .copy
mov word [edi], 20h ; attributes
sub edi, 11
mov byte [edi+13], 0 ; tenths of a second at file creation time
call get_time_for_file
mov [edi+14], ax ; creation time
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+16], ax ; creation date
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
mov word [edi+20], cx ; high word of cluster
mov word [edi+26], cx ; low word of cluster - to be filled
mov dword [edi+28], ecx ; file size - to be filled
cmp [ebp+FAT.createOption], 0
jnz .doit
; create directory
mov byte [edi+11], 10h ; attributes: folder
mov esi, edi
mov eax, [esp+36+20] ; extract saved cluster
mov [esp+36+20], edi ; this is needed for calculating arg of add_disk_free_space!
push ecx
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
shl ecx, 9
push ecx
push edi
jmp .doit2
 
.copy:
lea esi, [esp+72+11]
mov cl, 21
rep movsb
sub edi, 32
jmp .doit
 
.done1:
pop edi
call get_time_for_file
mov [edi+22], ax
call get_date_for_file
mov [edi+24], ax
mov [edi+18], ax
or byte [edi+11], 20h ; set 'archive' attribute
.doit:
mov esi, [esp+36+20]
lea eax, [esp+8]
call dword [eax+16] ; flush directory
push ecx
mov ecx, [esp+4+36+24]
xor eax, eax
test ecx, ecx
jz .done
push ecx edi
call get_free_FAT
jc .diskfull
.doit2:
push eax
mov [edi+26], ax
shr eax, 16
mov [edi+20], ax
lea eax, [esp+16+8]
call dword [eax+16] ; flush directory
pop eax
mov edx, [ebp+FAT.fatEND]
call set_FAT
.write_cluster:
push eax
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push [ebp+FAT.SECTORS_PER_CLUSTER]
.write_sector:
cmp [ebp+FAT.createOption], 0
jz .writedir
mov ecx, 512
cmp dword [esp+12], ecx
jb .writeshort
; we can write directly from given buffer
mov ebx, esi
add esi, ecx
jmp .writecommon
 
.writedir:
push 512
lea edi, [ebp+FAT.buffer]
mov ebx, edi
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
shl ecx, 9
cmp ecx, [esp+16]
jnz .writedircont
dec dword [esp+20]
push esi
mov ecx, 32/4
rep movsd
pop esi
mov dword [edi-32], '. '
mov dword [edi-32+4], ' '
mov dword [edi-32+8], ' '
mov byte [edi-32+11], 10h
push esi
mov ecx, 32/4
rep movsd
pop esi
mov dword [edi-32], '.. '
mov dword [edi-32+4], ' '
mov dword [edi-32+8], ' '
mov byte [edi-32+11], 10h
mov ecx, [esp+20+36]
cmp ecx, [ebp+FAT.ROOT_CLUSTER]
jnz @f
xor ecx, ecx
@@:
mov word [edi-32+26], cx
shr ecx, 16
mov [edi-32+20], cx
jmp .writedircont
 
.writeshort:
mov ecx, [esp+12]
push ecx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
rep movsb
.writedircont:
lea ecx, [ebp+FAT.buffer+0x200]
sub ecx, edi
push eax
xor eax, eax
rep stosb
pop eax
pop ecx
.writecommon:
push eax
call fs_write32_app
test eax, eax
pop eax
jnz .writeerr
inc eax
sub dword [esp+12], ecx
jz .writedone
dec dword [esp]
jnz .write_sector
pop eax
; allocate new cluster
pop eax
mov ecx, eax
call get_free_FAT
jc .diskfull
mov edx, [ebp+FAT.fatEND]
call set_FAT
xchg eax, ecx
mov edx, ecx
call set_FAT
xchg eax, ecx
jmp .write_cluster
 
.diskfull:
mov eax, ERROR_DISK_FULL
jmp .ret
 
.writeerr:
pop eax eax
sub esi, ecx
mov eax, ERROR_DEVICE
jmp .ret
 
.writedone:
pop eax eax
xor eax, eax
.ret:
pop edi ecx
inc ecx
.done:
sub esi, [esp+4+36+20]
mov [esp+4+36+28], eax
mov [esp+4+36+16], esi
jecxz @f
lea eax, [esp+12]
call dword [eax+8]
mov [edi+28], esi
call dword [eax+16]
@@:
lea eax, [esi+511]
shr eax, 9
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
lea eax, [eax+ecx-1]
xor edx, edx
div ecx
pop ecx
sub ecx, eax
call add_disk_free_space
add esp, 36
cmp [ebp+FAT.createOption], 2
jz @f
call update_disk
call fat_unlock
@@:
popad
ret
 
@@:
or eax, -1
rep stosw
ret
 
fat_read_symbols:
test esi, esi
jz @b
call utf8to16
stosw
test ax, ax
jnz @f
xor esi, esi
@@:
loop fat_read_symbols
ret
 
;----------------------------------------------------------------
fat_Write:
call fat_lock
call hd_find_lfn
jc .error
cmp dword [ebx+8], 0
jnz .eof ; FAT does not support files larger than 4GB
mov ecx, [ebx+12]
mov edx, [ebx+16]
mov ebx, [ebx+4]
; now edi points to direntry, ebx=start byte to write,
; ecx=number of bytes to write, edx=data pointer
; extend file if needed
add ecx, ebx
jc .eof ; FAT does not support files larger than 4GB
push edx
push eax ; save directory sector
push 0 ; return value=0
call get_time_for_file
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
push dword [edi+28] ; save current file size
cmp ecx, [edi+28]
jbe .length_ok
cmp ecx, ebx
jz .length_ok
call hd_extend_file
jnc .length_ok
mov [esp+4], eax
; hd_extend_file can return three error codes: FAT table error, device error or disk full.
; First two cases are fatal errors, in third case we may write some data
cmp al, ERROR_DISK_FULL
jnz @f
; correct number of bytes to write
mov ecx, [edi+28]
cmp ecx, ebx
ja .length_ok
push 0
.ret:
pop eax eax eax ecx ecx
sub edx, ecx
push eax edx
call update_disk
pop ebx
@@:
call fat_unlock
pop eax
ret
 
.error:
push eax
jmp @b
 
.eof:
push ERROR_END_OF_FILE
xor ebx, ebx
jmp @b
 
.device_err2:
pop ecx
.device_err:
mov byte [esp+8], ERROR_DEVICE
jmp .ret
 
.fat_err:
mov byte [esp+8], ERROR_FS_FAIL
jmp .ret
 
.length_ok:
mov esi, [edi+28]
mov eax, [edi+20-2]
mov ax, [edi+26]
mov edi, eax ; edi=current cluster
push 0 ; current sector in cluster
; save directory
mov eax, [esp+12]
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
test eax, eax
jnz .device_err
; now ebx=start pos, ecx=end pos, both lie inside file
sub ecx, ebx
jz .ret
.write_loop:
; skip unmodified sectors
cmp dword [esp+4], 0x200
jb .modify
sub ebx, 0x200
jae .skip
add ebx, 0x200
.modify:
; get length of data in current sector
push ecx
sub ebx, 0x200
jb .hasdata
neg ebx
xor ecx, ecx
jmp @f
.hasdata:
neg ebx
cmp ecx, ebx
jbe @f
mov ecx, ebx
@@:
; get current sector number
mov eax, edi
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, [esp+4]
; load sector if needed
cmp dword [esp+8], 0 ; we don't need to read uninitialized data
jz .noread
cmp ecx, 0x200 ; we don't need to read sector if it is fully rewritten
jz .noread
cmp ecx, esi ; (same for the last sector)
jz .noread
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
pop ebx eax
jnz .device_err2
.noread:
; zero uninitialized data if file was extended (because hd_extend_file does not this)
push eax ecx edi
xor eax, eax
mov ecx, 0x200
sub ecx, [esp+8+12]
jbe @f
lea edi, [ebp+FAT.buffer]
add edi, [esp+8+12]
rep stosb
@@:
; zero uninitialized data in the last sector
mov ecx, 0x200
sub ecx, esi
jbe @f
lea edi, [ebp+FAT.buffer+esi]
rep stosb
@@:
pop edi ecx
; copy new data
mov eax, edx
neg ebx
jecxz @f
lea ebx, [ebp+FAT.buffer+0x200+ebx]
call memmove
xor ebx, ebx
@@:
pop eax
; save sector
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_app
pop ebx
test eax, eax
jnz .device_err2
add edx, ecx
sub [esp], ecx
pop ecx
jz .ret
.skip:
; next sector
pop eax
inc eax
push eax
cmp eax, [ebp+FAT.SECTORS_PER_CLUSTER]
jb @f
and dword [esp], 0
mov eax, edi
call get_FAT
mov edi, eax
jc .device_err
cmp edi, 2
jb .fat_err
cmp edi, [ebp+FAT.fatRESERVED]
jae .fat_err
@@:
sub esi, 0x200
jae @f
xor esi, esi
@@:
sub dword [esp+4], 0x200
jae @f
and dword [esp+4], 0
@@:
jmp .write_loop
 
hd_extend_file.zero_size:
xor eax, eax
jmp hd_extend_file.start_extend
 
; extends file on hd to given size (new data area is undefined)
; in: edi->direntry, ecx=new size
; out: CF=0 => OK, eax=0
; CF=1 => error, eax=code (ERROR_FS_FAIL or ERROR_DISK_FULL or ERROR_DEVICE)
hd_extend_file:
push esi
mov esi, [ebp+FAT.SECTORS_PER_CLUSTER]
imul esi, [ebp+FAT.BYTES_PER_SECTOR]
push ecx
; find the last cluster of file
mov eax, [edi+20-2]
mov ax, [edi+26]
mov ecx, [edi+28]
jecxz .zero_size
.last_loop:
sub ecx, esi
jbe .last_found
call get_FAT
jnc @f
.device_err:
pop ecx
.device_err2:
pop esi
push ERROR_DEVICE
.ret_err:
pop eax
stc
ret
@@:
cmp eax, 2
jb .fat_err
cmp eax, [ebp+FAT.fatRESERVED]
jb .last_loop
.fat_err:
pop ecx esi
push ERROR_FS_FAIL
jmp .ret_err
.last_found:
push eax
call get_FAT
jnc @f
pop eax
jmp .device_err
@@:
cmp eax, [ebp+FAT.fatRESERVED]
pop eax
jb .fat_err
; set length to full number of clusters
sub [edi+28], ecx
.start_extend:
pop ecx
; now do extend
push edx
mov edx, 2 ; start scan from cluster 2
.extend_loop:
cmp [edi+28], ecx
jae .extend_done
; add new cluster
push eax
call get_free_FAT
jc .disk_full
mov edx, [ebp+FAT.fatEND]
call set_FAT
mov edx, eax
pop eax
test eax, eax
jz .first_cluster
push edx
call set_FAT
pop edx
jmp @f
.first_cluster:
ror edx, 16
mov [edi+20], dx
ror edx, 16
mov [edi+26], dx
@@:
push ecx
mov ecx, -1
call add_disk_free_space
pop ecx
mov eax, edx
add [edi+28], esi
jmp .extend_loop
.extend_done:
mov [edi+28], ecx
pop edx esi
xor eax, eax ; CF=0
ret
.device_err3:
pop edx
jmp .device_err2
.disk_full:
pop eax edx esi
movi eax, ERROR_DISK_FULL
stc
ret
 
;----------------------------------------------------------------
fat_SetFileEnd:
call fat_lock
call hd_find_lfn
jc .reteax
; must not be directory
test byte [edi+11], 10h
jnz .access_denied
; file size must not exceed 4 Gb
cmp dword [ebx+8], 0
jnz .endOfFile
push eax ; save directory sector
; set file modification date/time to current
call get_time_for_file
mov [edi+22], ax ; last write
call get_date_for_file
mov [edi+24], ax ; last write
mov [edi+18], ax ; last access
mov eax, [ebx+4]
cmp eax, [edi+28]
jb .truncate
ja .expand
pop eax
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
test eax, eax
jnz .errorDevice
push 0
jmp .ret
 
.access_denied:
push ERROR_ACCESS_DENIED
jmp .ret
 
.endOfFile:
push ERROR_END_OF_FILE
jmp .ret
 
.errorDevice:
push ERROR_DEVICE
jmp .ret
 
.expand:
push ebx ebp ecx
push dword [edi+28] ; save old size
mov ecx, eax
call hd_extend_file
push eax ; return code
jnc .expand_ok
cmp al, ERROR_DISK_FULL
jnz .pop_ret
.expand_ok: ; save directory
mov eax, [edi+28]
xchg eax, [esp+20]
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
test eax, eax
jnz .pop_ret11
mov eax, [esp+20]
sub eax, [esp+4]
cmp eax, 1000001h
jnc .pop_ret
mov eax, [edi+20-2]
mov ax, [edi+26]
mov edi, eax
test edi, edi
jz .pop_ret
; now zero new data
push 0
; edi=current cluster, [esp]=sector in cluster
; [esp+24]=new size, [esp+8]=old size, [esp+4]=return code
.zero_loop:
cmp edi, 2
jb .error_fat
cmp edi, [ebp+FAT.fatRESERVED]
jae .error_fat
sub dword [esp+8], 0x200
jae .next_cluster
lea eax, [edi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, [esp]
cmp dword [esp+8], -0x200
jz .noread
push eax
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
pop eax
jnz .err_next
.noread:
mov ecx, [esp+8]
neg ecx
push edi
lea edi, [ebp+FAT.buffer+0x200]
add edi, [esp+12]
push eax
xor eax, eax
mov [esp+16], eax
rep stosb
pop eax
pop edi
call fs_write32_app
test eax, eax
jz .next_cluster
.err_next:
mov byte [esp+4], ERROR_DEVICE
.next_cluster:
pop eax
sub dword [esp+20], 0x200
jbe .pop_ret
inc eax
push eax
cmp eax, [ebp+FAT.SECTORS_PER_CLUSTER]
jb .zero_loop
and dword [esp], 0
mov eax, edi
call get_FAT
mov edi, eax
jnc .zero_loop
pop eax
.pop_ret11:
mov byte [esp], ERROR_DEVICE
.pop_ret:
call update_disk
pop eax ecx ecx ebp ebx ecx
.reteax:
push eax
.ret:
call fat_unlock
pop eax
ret
 
.error_fat:
pop eax
mov byte [esp], ERROR_FS_FAIL
jmp .pop_ret
 
.error_fat2:
pop eax ecx eax
call update_disk
push ERROR_FS_FAIL
jmp .ret
 
.truncate:
mov [edi+28], eax
push ecx
mov ecx, [edi+20-2]
mov cx, [edi+26]
push eax
test eax, eax
jz .zero_size
@@: ; find new last cluster
cmp ecx, 2
jb .error_fat2
cmp ecx, [ebp+FAT.fatRESERVED]
jae .error_fat2
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
shl eax, 9
sub [esp], eax
jbe @f
mov eax, ecx
call get_FAT
mov ecx, eax
jnc @b
.device_err3:
pop eax ecx eax
call update_disk
push ERROR_DEVICE
jmp .ret
 
@@:
; we will zero data at the end of last sector - remember it
push ecx
; terminate FAT chain
push edx
mov eax, ecx
mov edx, [ebp+FAT.fatEND]
call set_FAT
mov eax, edx
pop edx
jnc @f
.device_err4:
pop ecx
jmp .device_err3
 
.zero_size:
and word [edi+20], 0
and word [edi+26], 0
push 0
mov eax, ecx
@@:
; delete FAT chain
call clear_cluster_chain
jc .device_err4
; save directory
mov eax, [esp+12]
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
test eax, eax
jnz .device_err4
; zero last sector, ignore errors
pop ecx
pop eax
dec ecx
imul ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
add ecx, [ebp+FAT.DATA_START]
push eax
sar eax, 9
add ecx, eax
pop eax
and eax, 0x1FF
jz .truncate_done
push ebx eax
mov eax, ecx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
pop eax
lea edi, [ebp+FAT.buffer+eax]
push ecx
mov ecx, 0x200
sub ecx, eax
xor eax, eax
rep stosb
pop eax
call fs_write32_app
pop ebx
.truncate_done:
pop ecx eax
call update_disk
call fat_unlock
xor eax, eax
ret
 
;----------------------------------------------------------------
fat_GetFileInfo:
cmp byte [esi], 0
jz .volume
call fat_lock
call hd_find_lfn
jc @f
push ebp
xor ebp, ebp
mov esi, [ebx+16]
mov dword [esi+4], ebp
call fat_entry_to_bdfe2
pop ebp
xor eax, eax
@@:
push eax
call fat_unlock
pop eax
@@:
ret
 
.volume:
mov eax, dword[ebp+FAT.Length]
mov edx, dword[ebp+FAT.Length+4]
mov edi, [ebx+16]
shld edx, eax, 9
shl eax, 9
mov [edi+36], edx
mov [edi+32], eax
mov eax, [ebx+8]
mov byte [edi], 8
mov [edi+4], eax
test eax, eax
jz @b
lea esi, [ebp+FAT.volumeLabel]
mov ecx, 11
@@:
mov byte [esi+ecx], 0
dec ecx
jz @f
cmp byte [esi+ecx], ' '
jz @b
@@:
mov cl, 12
add edi, 40
cmp eax, 2
jz @f
rep movsb
xor eax, eax
ret
 
@@:
lodsb
stosw
loop @b
ret
 
;----------------------------------------------------------------
fat_SetFileInfo:
call fat_lock
call hd_find_lfn
jc @f
push eax
mov edx, [ebx+16]
call bdfe_to_fat_entry
pop eax
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
call update_disk
xor eax, eax
@@:
push eax
call fat_unlock
pop eax
ret
 
;----------------------------------------------------------------
fat_Delete:
call fat_lock
and [ebp+FAT.longname_sec1], 0
and [ebp+FAT.longname_sec2], 0
call hd_find_lfn
jc .notFound
cmp dword [edi], '. '
jz .access_denied2
cmp dword [edi], '.. '
jz .access_denied2
test byte [edi+11], 10h
jz .dodel
; we can delete only empty folders!
pushad
mov esi, [edi+20-2]
mov si, [edi+26]
xor ecx, ecx
lea eax, [esi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
jnz .err1
lea eax, [ebx+0x200]
add ebx, 2*0x20
.checkempty:
cmp byte [ebx], 0
jz .empty
cmp byte [ebx], 0xE5
jnz .notempty
add ebx, 0x20
cmp ebx, eax
jb .checkempty
inc ecx
cmp ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
jb @f
mov eax, esi
call get_FAT
jc .err1
cmp eax, 2
jb .error_fat
cmp eax, [ebp+FAT.fatRESERVED]
jae .empty
mov esi, eax
xor ecx, ecx
@@:
lea eax, [esi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, ecx
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
lea eax, [ebx+0x200]
jz .checkempty
.err1:
popad
.err2:
push ERROR_DEVICE
.ret:
call fat_unlock
pop eax
ret
 
.notFound:
push ERROR_FILE_NOT_FOUND
jmp .ret
 
.error_fat:
popad
push ERROR_FS_FAIL
jmp .ret
 
.notempty:
popad
.access_denied2:
push ERROR_ACCESS_DENIED
jmp .ret
 
.empty:
popad
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
pop ebx eax
jnz .err2
.dodel:
push eax
mov eax, [edi+20-2]
mov ax, [edi+26]
xchg eax, [esp]
; delete folder entry
mov byte [edi], 0xE5
; delete LFN (if present)
.lfndel:
lea edx, [ebp+FAT.buffer]
cmp edi, edx
ja @f
cmp [ebp+FAT.longname_sec2], 0
jz .lfndone
push [ebp+FAT.longname_sec2]
push [ebp+FAT.longname_sec1]
pop [ebp+FAT.longname_sec2]
and [ebp+FAT.longname_sec1], 0
push ebx
mov ebx, edx
call fs_write32_sys
mov eax, [esp+4]
call fs_read32_sys
pop ebx
pop eax
lea edi, [ebp+FAT.buffer+0x200]
@@:
sub edi, 0x20
cmp byte [edi], 0xE5
jz .lfndone
cmp byte [edi+11], 0xF
jnz .lfndone
mov byte [edi], 0xE5
jmp .lfndel
.lfndone:
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
; delete FAT chain
pop eax
call clear_cluster_chain
call update_disk
call fat_unlock
xor eax, eax
ret
 
;----------------------------------------------------------------
fat_Rename:
; in: edi -> new path string in UTF-8
push esi edi
call fat_lock
call hd_find_lfn
pop ebx
jc .error
sub esp, 32
mov esi, edi
mov edi, esp
mov ecx, 8
rep movsd
mov [ebp+FAT.createOption], 2
mov esi, ebx
call fat_CreateFile.rename
add esp, 32
pop esi
test eax, eax
jnz .ret
push eax
mov [ebp+FAT.longname_sec1], eax
mov [ebp+FAT.longname_sec2], eax
call hd_find_lfn
jc .error
mov byte [edi], 0xE5
jmp fat_Delete.lfndel
 
.error:
push eax
call fat_unlock
pop eax ebx
.ret:
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/ext.inc
0,0 → 1,2708
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; EXT external functions
; in:
; ebx -> parameter structure of sysfunc 70
; ebp -> EXTFS structure
; esi -> path string in UTF-8
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
ext_user_functions:
dd ext_free
dd (ext_user_functions_end - ext_user_functions - 4) / 4
dd ext_ReadFile
dd ext_ReadFolder
dd ext_CreateFile
dd ext_WriteFile
dd ext_SetFileEnd
dd ext_GetFileInfo
dd ext_SetFileInfo
dd 0
dd ext_Delete
dd ext_CreateFolder
dd ext_Rename
ext_user_functions_end:
endg
 
struct DIRENTRY
inodeNumber dd ?
entryLength dw ?
nameLength db ?
fileType db ?
name db ? ; rb [nameLength]
ends
 
struct INODE
accessMode dw ?
UID dw ?
fileSize dd ?
accessedTime dd ?
inodeModified dd ?
dataModified dd ?
deletedTime dd ?
GID dw ?
linksCount dw ?
sectorsUsed dd ?
featureFlags dd ?
reserved dd ?
blockNumbers rd 12
addressBlock dd ?
doubleAddress dd ?
tripleAddress dd ?
generation dd ?
ACL dd ?
fileSizeHigh dd ?
ends
 
struct BGDESCR ; block group descriptor
blockBitmap dd ?
inodeBitmap dd ?
inodeTable dd ?
blocksFree dw ?
inodesFree dw ?
directoriesCount dw ?
reserved rb 14
ends
 
struct SUPERBLOCK
inodesTotal dd ?
blocksTotal dd ?
blocksReserved dd ?
blocksFree dd ?
inodesFree dd ?
firstGroupBlock dd ?
sectorsPerBlockLog dd ? ; shift for 1024
fragmentSizeLog dd ?
blocksPerGroup dd ?
fragmentsPerGroup dd ?
inodesPerGroup dd ?
lastMountTime dd ?
lastWriteTime dd ?
mountCount dw ?
mountMax dw ?
magic dw ?
state dw ?
errorHandling dw ?
additionalVersion dw ?
lastCheck dd ?
checkInterval dd ?
creatorOS dd ?
dynamicVersionFlag dd ?
reservedUID dw ?
reservedGID dw ?
firstInode dd ?
inodeSize dw ?
thisBlockGroup dw ?
compatibleFlags dd ?
incompatibleFlags dd ?
RO_compatibleFlags dd ?
UUID rb 16
volumeLabel rb 16
ends
 
; ext4 extent tree
struct NODEHEADER ; tree node header
magic dw ? ; 0xF30A
entriesFolow dw ?
entriesMax dw ?
currentDepth dw ?
generation dd ?
ends
 
struct INDEX ; root/branch
fileBlock dd ?
nodeBlock dd ?
nodeBlockHigh dw ?
reserved dw ?
ends
 
struct EXTENT ; leaf
fileBlock dd ?
blocksCount dw ?
fsBlockHigh dw ?
fsBlock dd ?
ends
 
ROOT_INODE = 2
EXTENTS_USED = 80000h
TYPE_MASK = 0F000h
FLAG_FILE = 8000h
DIRECTORY = 4000h
DIR_FLAG_FILE = 1
DIR_DIRECTORY = 2
KOS_HIDDEN = 2
KOS_DIRECTORY = 10h
READ_ONLY = 1
 
; Implemented "incompatible" features:
; 2 = have file type in directory entry
; 40h = extents
; 200h = flexible block groups
INCOMPATIBLE_SUPPORT = 242h
; Read only support for "incompatible" features:
INCOMPATIBLE_READ_SUPPORT = 240h
 
; Implemented "read-only" features:
; 1 = sparse superblock
; 2 = 64-bit file size
READ_ONLY_SUPPORT = 3
 
struct EXTFS PARTITION
Lock MUTEX
mountType dd ?
bytesPerBlock dd ?
sectorsPerBlock dd ?
dwordsPerBlock dd ?
dwordsPerBranch dd ? ; dwordsPerBlock ^ 2
mainBlockBuffer dd ?
tempBlockBuffer dd ?
descriptorTable dd ?
descriptorTableEnd dd ?
align0 rb 200h-EXTFS.align0
superblock SUPERBLOCK
align1 rb 400h-EXTFS.align1
rootInodeBuffer INODE
align2 rb 600h-EXTFS.align2
inodeBuffer INODE
align3 rb 800h-EXTFS.align3
ends
 
; mount if it's a valid EXT partition
ext2_create_partition:
; in:
; ebp -> PARTITION structure
; ebx -> boot sector
; ebx+512 -> buffer
; out:
; eax -> EXTFS structure, 0 = not EXT
push ebx
cmp dword [esi+DISK.MediaInfo.SectorSize], 512
jnz .fail
mov eax, 2
add ebx, 512
call fs_read32_sys
test eax, eax
jnz .fail
cmp [ebx+SUPERBLOCK.magic], 0xEF53
jne .fail
cmp [ebx+SUPERBLOCK.state], 1
ja .fail
test [ebx+SUPERBLOCK.incompatibleFlags], not INCOMPATIBLE_SUPPORT
jnz .fail
cmp [ebx+SUPERBLOCK.sectorsPerBlockLog], 6 ; 64KB
ja .fail
cmp [ebx+SUPERBLOCK.inodeSize], 512
ja .fail
cmp [ebx+SUPERBLOCK.blocksPerGroup], 0
je .fail
cmp [ebx+SUPERBLOCK.inodesPerGroup], 0
je .fail
movi eax, sizeof.EXTFS
call malloc
test eax, eax
jz .fail
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+EXTFS.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+EXTFS.FirstSector+4], ecx
mov ecx, dword [ebp+PARTITION.Length]
mov dword [eax+EXTFS.Length], ecx
mov ecx, dword [ebp+PARTITION.Length+4]
mov dword [eax+EXTFS.Length+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+EXTFS.Disk], ecx
mov [eax+EXTFS.FSUserFunctions], ext_user_functions
 
push ebp esi edi
mov ebp, eax
lea ecx, [eax+EXTFS.Lock]
call mutex_init
mov esi, ebx
lea edi, [ebp+EXTFS.superblock]
mov ecx, 512/4
rep movsd ; copy superblock
mov ecx, [ebx+SUPERBLOCK.sectorsPerBlockLog]
inc ecx
mov eax, 1
shl eax, cl
mov [ebp+EXTFS.sectorsPerBlock], eax
shl eax, 9
mov [ebp+EXTFS.bytesPerBlock], eax
shl eax, 1
push eax
shr eax, 3
mov [ebp+EXTFS.dwordsPerBlock], eax
mul eax
mov [ebp+EXTFS.dwordsPerBranch], eax
call kernel_alloc
test eax, eax
jz .error
mov [ebp+EXTFS.mainBlockBuffer], eax
add eax, [ebp+EXTFS.bytesPerBlock]
mov [ebp+EXTFS.tempBlockBuffer], eax
mov [ebp+EXTFS.mountType], 0
test [ebx+SUPERBLOCK.RO_compatibleFlags], not READ_ONLY_SUPPORT
jnz .read_only
test [ebx+SUPERBLOCK.incompatibleFlags], INCOMPATIBLE_READ_SUPPORT
jz @f
.read_only:
or [ebp+EXTFS.mountType], READ_ONLY
@@:
mov eax, [ebx+SUPERBLOCK.inodesTotal]
dec eax
xor edx, edx
div [ebx+SUPERBLOCK.inodesPerGroup]
inc eax
shl eax, 5
push eax eax
call kernel_alloc
pop ecx
test eax, eax
jz .error2
mov [ebp+EXTFS.descriptorTable], eax
mov ebx, eax
add eax, ecx
mov [ebp+EXTFS.descriptorTableEnd], eax
mov eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mul [ebp+EXTFS.sectorsPerBlock]
dec ecx
shr ecx, 9
inc ecx
call fs_read64_sys
test eax, eax
jnz @f
mov al, ROOT_INODE
lea ebx, [ebp+EXTFS.rootInodeBuffer]
call readInode
test eax, eax
jnz @f
mov eax, ebp
pop edi esi ebp ebx
ret
 
@@:
stdcall kernel_free, [ebp+EXTFS.descriptorTable]
.error2:
stdcall kernel_free, [ebp+EXTFS.mainBlockBuffer]
.error:
mov eax, ebp
call free
pop edi esi ebp
.fail:
pop ebx
xor eax, eax
ret
 
; unmount EXT partition
ext_free:
; in: eax -> EXTFS structure
push eax [eax+EXTFS.mainBlockBuffer]
stdcall kernel_free, [eax+EXTFS.descriptorTable]
call kernel_free
pop eax
jmp free
 
extfsWriteBlock:
push fs_write64_sys
jmp @f
; in: eax = block number, ebx -> buffer
extfsReadBlock:
push fs_read64_sys
@@:
push ecx edx
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
call dword[esp+8]
pop edx ecx
add esp, 4
test eax, eax
jz @f
movi eax, ERROR_DEVICE
stc
@@:
ret
 
extfsWriteDescriptor:
; in: ebx = block group descriptor
mov eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mul [ebp+EXTFS.sectorsPerBlock]
sub ebx, [ebp+EXTFS.descriptorTable]
shr ebx, 9
add eax, ebx
shl ebx, 9
add ebx, [ebp+EXTFS.descriptorTable]
call fs_write32_sys
ret
 
extfsExtentFree:
; in: eax = first block number, ecx = extent size
push ebx edx edi
sub eax, [ebp+EXTFS.superblock.firstGroupBlock]
xor edx, edx
mov ebx, [ebp+EXTFS.superblock.blocksPerGroup]
div ebx
sub ebx, edx
sub ebx, ecx
jc .ret
push edx
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
mov eax, ecx
mul [ebp+EXTFS.sectorsPerBlock]
add [ebx+BGDESCR.blocksFree], cx
add [ebp+EXTFS.superblock.blocksFree], ecx
sub [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
push [ebx+BGDESCR.blockBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
call extfsReadBlock
pop eax
jc .ret
push ebx edx
mov edi, eax
shr edi, 5
shl edi, 2
add edi, ebx
mov edx, ecx
and eax, 31
jz .aligned
mov ecx, 32
sub ecx, eax
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
or ebx, -1
shl ebx, cl
not ebx
mov ecx, eax
shl ebx, cl
not ebx
and [edi], ebx
add edi, 4
xor eax, eax
.aligned:
mov ecx, edx
shr ecx, 5
rep stosd
and edx, 31
jz @f
mov ecx, edx
not eax
shl eax, cl
and [edi], eax
@@:
pop eax ebx
call extfsWriteBlock
.ret:
pop edi edx ebx
xor eax, eax
ret
 
extfsInodeAlloc:
; in: eax = parent inode number
; out: ebx = allocated inode number
push ecx edx edi
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
push ebx
.test_block_group:
push ebx
cmp [ebx+BGDESCR.blocksFree], 0
jz .next
cmp [ebx+BGDESCR.inodesFree], 0
jz .next
dec [ebx+BGDESCR.inodesFree]
dec [ebp+EXTFS.superblock.inodesFree]
push [ebx+BGDESCR.inodeBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
mov edi, ebx
call extfsReadBlock
jc .fail
mov ecx, [ebp+EXTFS.superblock.inodesPerGroup]
or eax, -1
shr ecx, 5
repz scasd
jz .next
sub edi, 4
mov eax, [edi]
not eax
bsf eax, eax
bts [edi], eax
sub edi, [ebp+EXTFS.tempBlockBuffer]
shl edi, 3
add eax, edi
mov ecx, eax
mov eax, edx
call extfsWriteBlock
pop eax
sub eax, [ebp+EXTFS.descriptorTable]
shr eax, 5
mul [ebp+EXTFS.superblock.inodesPerGroup]
lea ebx, [eax+ecx+1]
xor eax, eax
.ret:
pop edi edi edx ecx
ret
 
.next: ; search forward, then backward
pop ebx
cmp ebx, [esp]
jc .backward
add ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTableEnd]
jc .test_block_group
mov ebx, [esp]
.backward:
sub ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTable]
jnc .test_block_group
movi eax, ERROR_DISK_FULL
push eax
.fail:
pop edi
jmp .ret
 
extfsExtentAlloc:
; in: eax = parent inode number, ecx = blocks max
; out: ebx = first block number, ecx = blocks allocated
push edx esi edi ecx
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
push ebx
.test_block_group:
push ebx
cmp [ebx+BGDESCR.blocksFree], 0
jz .next
mov eax, [ebx+BGDESCR.blockBitmap]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
mov edi, ebx
call extfsReadBlock
jc .fail
mov ecx, [ebp+EXTFS.superblock.blocksPerGroup]
shr ecx, 5
or eax, -1
repz scasd
jz .next
mov esi, edi
sub esi, 4
push edx ecx
mov eax, [esi]
not eax
bsf ecx, eax
not eax
shr eax, cl
shl eax, cl
mov ebx, 32
bsf ebx, eax
sub ebx, ecx
mov eax, [esp+16]
cmp ebx, eax
jc @f
mov ebx, eax
@@:
or eax, -1
cmp ebx, 32
jz @f
xchg ebx, ecx
shl eax, cl
not eax
xchg ebx, ecx
shl eax, cl
@@:
or [esi], eax
sub esi, [ebp+EXTFS.tempBlockBuffer]
shl esi, 3
add esi, ecx
mov eax, [esp+16]
sub eax, ebx
mov [esp+16], ebx
add ebx, ecx
pop ecx
test eax, eax
jz .done
cmp ebx, 32
jnz .done
jecxz .done
mov ebx, eax
shr eax, 5
inc eax
and ebx, 31
cmp ecx, eax
jnc @f
mov eax, ecx
mov bl, 32
@@:
mov ecx, eax
shl eax, 5
add [esp+12], eax
xor eax, eax
push edi
repz scasd
jz @f
mov eax, [edi-4]
bsf eax, eax
xchg eax, ebx
test ecx, ecx
jnz @f
cmp ebx, eax
jc @f
mov ebx, eax
@@:
inc ecx
shl ecx, 5
sub ecx, ebx
sub [esp+16], ecx
mov ecx, edi
pop edi
sub ecx, edi
shr ecx, 2
dec ecx
or eax, -1
rep stosd
mov ecx, ebx
jecxz .done
neg ecx
add ecx, 32
shr eax, cl
or [edi], eax
.done:
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
mov ebx, [esp]
mov ecx, [esp+8]
sub [ebx+BGDESCR.blocksFree], cx
jnc @f
mov [ebx+BGDESCR.blocksFree], 0
@@:
sub [ebp+EXTFS.superblock.blocksFree], ecx
call extfsWriteDescriptor
pop eax ebx
sub eax, [ebp+EXTFS.descriptorTable]
shr eax, 5
mul [ebp+EXTFS.superblock.blocksPerGroup]
mov ebx, eax
add ebx, esi
add ebx, [ebp+EXTFS.superblock.firstGroupBlock]
pop ecx
mov eax, ecx
mul [ebp+EXTFS.sectorsPerBlock]
add [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
xor eax, eax
.ret:
pop edi esi edx
ret
 
.next: ; search forward, then backward
pop ebx
cmp ebx, [esp]
jc .backward
add ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTableEnd]
jc .test_block_group
mov ebx, [esp]
.backward:
sub ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTable]
jnc .test_block_group
movi eax, ERROR_DISK_FULL
push eax
.fail:
add esp, 12
xor ecx, ecx
stc
jmp .ret
 
extfsGetExtent:
; in: ecx = starting file block
; out: eax = first block number, ecx = extent size
push ebx edx esi
lea esi, [ebp+EXTFS.inodeBuffer]
test [esi+INODE.featureFlags], EXTENTS_USED
jz .listTreeSearch
add esi, INODE.blockNumbers
.extentTreeSearch:
cmp word [esi+NODEHEADER.magic], 0xF30A
jne .fail
movzx ebx, [esi+NODEHEADER.entriesFolow]
add esi, sizeof.NODEHEADER
test ebx, ebx
jz .noBlock
cmp word [esi-sizeof.NODEHEADER+NODEHEADER.currentDepth], 0
je .leaf_block
dec ebx
jz .end_search_index
@@:
cmp ecx, [esi+sizeof.INDEX+INDEX.fileBlock]
jb .end_search_index
add esi, sizeof.INDEX
dec ebx
jnz @b
.end_search_index:
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov eax, [esi+INDEX.nodeBlock]
call extfsReadBlock
jc .fail2
mov esi, ebx
jmp .extentTreeSearch
 
.fail:
movi eax, ERROR_FS_FAIL
jmp .fail2
 
.leaf_block:
movzx edx, [esi+EXTENT.blocksCount]
add edx, [esi+EXTENT.fileBlock]
sub edx, ecx
ja .end_search_extent
add esi, sizeof.EXTENT
dec ebx
jnz .leaf_block
.noBlock:
movi eax, ERROR_END_OF_FILE
.fail2:
pop esi edx ebx
stc
ret
 
.end_search_extent:
sub ecx, [esi+EXTENT.fileBlock]
jc .fail
add ecx, [esi+EXTENT.fsBlock]
mov eax, ecx
mov ecx, edx
pop esi edx ebx
ret
 
.listTreeSearch:
cmp ecx, 12
jb .get_direct_block
sub ecx, 12
cmp ecx, [ebp+EXTFS.dwordsPerBlock]
jb .get_indirect_block
sub ecx, [ebp+EXTFS.dwordsPerBlock]
cmp ecx, [ebp+EXTFS.dwordsPerBranch]
jb .get_double_indirect_block
; triply-indirect blocks
sub ecx, [ebp+EXTFS.dwordsPerBranch]
mov eax, [esi+INODE.tripleAddress]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
xor edx, edx
mov eax, ecx
div [ebp+EXTFS.dwordsPerBranch]
; eax = number in triply-indirect block, edx = number in branch
mov eax, [ebx+eax*4]
test eax, eax
jz .noBlock
call extfsReadBlock
jc .fail2
mov eax, edx
jmp @f
 
.get_direct_block:
mov edx, ecx
mov cl, 12
lea ebx, [esi+INODE.blockNumbers]
jmp .calculateExtent
 
.get_indirect_block:
mov eax, [esi+INODE.addressBlock]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
mov edx, ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
jmp .calculateExtent
 
.get_double_indirect_block:
mov eax, [esi+INODE.doubleAddress]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
mov eax, ecx
@@:
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
; eax = number in doubly-indirect block, edx = number in indirect block
mov eax, [ebx+eax*4]
test eax, eax
jz .noBlock
call extfsReadBlock
jc .fail2
.calculateExtent:
lea esi, [ebx+edx*4]
lodsd
test eax, eax
jz .noBlock
mov ebx, eax
sub ecx, edx
xor edx, edx
@@:
inc edx
dec ecx
jz @f
lodsd
sub eax, ebx
sub eax, edx
jz @b
@@:
mov eax, ebx
mov ecx, edx
pop esi edx ebx
clc
ret
 
getInodeLocation:
; in: eax = inode number
; out: eax = inode sector, edx = offset in sector
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
shl eax, 5
add eax, [ebp+EXTFS.descriptorTable]
mov ebx, [eax+BGDESCR.inodeTable]
imul ebx, [ebp+EXTFS.sectorsPerBlock]
movzx eax, [ebp+EXTFS.superblock.inodeSize]
mul edx
mov edx, eax
shr eax, 9
and edx, 511
add eax, ebx
ret
 
writeInode:
; in: eax = inode number, ebx -> inode data
push edx edi esi ecx ebx eax
mov edi, ebx
call fsGetTime
add eax, 978307200
mov [edi+INODE.inodeModified], eax
pop eax
cmp eax, ROOT_INODE
jnz @f
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov esi, edi
lea edi, [ebp+EXTFS.rootInodeBuffer]
rep movsb
@@:
call getInodeLocation
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov ecx, eax
call fs_read32_sys
test eax, eax
jnz @f
mov eax, ecx
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov edi, edx
add edi, ebx
mov esi, [esp]
rep movsb
call fs_write32_sys
.ret:
pop ebx ecx esi edi edx
ret
 
@@:
movi eax, ERROR_DEVICE
stc
jmp .ret
 
readInode:
; in: eax = inode number, ebx -> inode buffer
push edx edi esi ecx ebx
mov edi, ebx
call getInodeLocation
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call fs_read32_sys
test eax, eax
jnz @b
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov esi, edx
add esi, ebx
rep movsb
xor eax, eax
pop ebx ecx esi edi edx
ret
 
indirectBlockAlloc:
; in:
; edi -> indirect block number
; ebx = starting extent block
; ecx = extent size
; edx = starting file block
mov eax, [edi]
test eax, eax
jz .newBlock
push edi ebx ecx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .err2
lea edi, [ebx+edx*4]
test edx, edx
jz @f
cmp dword[edi-4], 0
jnz @f
pop ecx ebx edi
.err:
mov al, ERROR_FS_FAIL
stc
ret
 
.err2:
pop ecx ebx edi
ret
 
.newBlock:
test edx, edx
jnz .err
mov [edi], ebx
inc ebx
dec ecx
push edi ebx ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, [ebp+EXTFS.tempBlockBuffer]
push edi
rep stosd
pop edi
@@:
mov ecx, [ebp+EXTFS.dwordsPerBlock]
sub ecx, edx
pop ebx eax
sub ebx, ecx
jnc @f
add ecx, ebx
xor ebx, ebx
@@:
jecxz .done
add edx, ecx
@@:
stosd
inc eax
loop @b
.done:
pop edi
push eax ebx
mov eax, [edi]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
pop ecx ebx
ret
 
doublyIndirectBlockAlloc:
; in:
; edi -> indirect block number
; edx = starting file block
; ebx = starting extent block
; ecx = extent size
; [esp+4] = rest of size
; [esp+8] = parent inode number
mov eax, [edi]
test eax, eax
jz .newBlock
push edi ecx ebx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .err2
mov eax, edx
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
lea edi, [ebx+eax*4]
pop ebx
test eax, eax
jz @f
cmp dword[edi-4], 0
jnz @f
pop ecx edi
.err:
mov al, ERROR_FS_FAIL
stc
ret
 
.err2:
pop ebx ecx edi
ret
 
.newBlock:
test edx, edx
jnz .err
mov [edi], ebx
inc ebx
dec ecx
inc dword[esp+4]
push edi ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, [ebp+EXTFS.mainBlockBuffer]
push ecx edi
rep stosd
pop edi ecx
@@:
sub ecx, eax
xchg [esp], ecx
.loop:
cmp dword[edi], 0
jnz @f
inc dword[esp+12]
@@:
jecxz .extentAlloc
call indirectBlockAlloc
jc .end
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jnz @b
add edi, 4
xor edx, edx
dec dword[esp]
jnz .loop
.end:
pop edi edi
push ebx eax
mov eax, [edi]
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsWriteBlock
pop ebx
add eax, ebx
xor ebx, ebx
cmp ebx, eax
pop ebx
ret
 
.extentAlloc:
mov ecx, [esp+12]
xor eax, eax
jecxz .end
mov eax, [esp+16]
call extfsExtentAlloc
jc .end
sub [esp+12], ecx
jmp @b
 
extfsExtendFile:
; in:
; [ebp+EXTFS.inodeBuffer] = inode
; ecx = inode number
; edx:eax = new size
push ebx esi edi ecx
lea esi, [ebp+EXTFS.inodeBuffer]
mov ebx, [esi+INODE.fileSize]
mov ecx, [esi+INODE.fileSizeHigh]
cmp ebx, eax
sbb ecx, edx
jnc .ret
mov ecx, [esi+INODE.fileSizeHigh]
mov [esi+INODE.fileSize], eax
mov [esi+INODE.fileSizeHigh], edx
sub eax, 1
sbb edx, 0
div [ebp+EXTFS.bytesPerBlock]
inc eax
xchg eax, ebx
mov edx, ecx
sub eax, 1
sbb edx, 0
jc @f
div [ebp+EXTFS.bytesPerBlock]
@@:
inc eax
sub ebx, eax
jz .ret
push ebx
mov edx, eax
@@:
mov ecx, [esp]
mov eax, [esp+4]
test ecx, ecx
jz .done
call extfsExtentAlloc
jc .errDone
sub [esp], ecx
cmp edx, 12
jc .directBlocks
sub edx, 12
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jc .indirectBlocks
sub edx, [ebp+EXTFS.dwordsPerBlock]
cmp edx, [ebp+EXTFS.dwordsPerBranch]
jc .doublyIndirectBlock
sub edx, [ebp+EXTFS.dwordsPerBranch]
jmp .triplyIndirectBlock
 
.newExtent:
jmp @b
 
.directBlocks:
lea edi, [esi+INODE.blockNumbers+edx*4]
test edx, edx
jz @f
cmp dword[edi-4], 0
jz .errDone
@@:
mov eax, ebx
mov ebx, ecx
mov ecx, 12
sub ecx, edx
sub ebx, ecx
jnc @f
add ecx, ebx
xor ebx, ebx
@@:
add edx, ecx
@@:
stosd
inc eax
loop @b
mov ecx, ebx
mov ebx, eax
jecxz .newExtent
xor edx, edx
.indirectBlocks:
lea edi, [esi+INODE.addressBlock]
cmp dword[edi], 0
jnz @f
inc dword[esp]
@@:
call indirectBlockAlloc
jc .errDone
add edx, 12
jecxz .newExtent
xor edx, edx
.doublyIndirectBlock:
lea edi, [esi+INODE.doubleAddress]
call doublyIndirectBlockAlloc
jc .errDone
mov edx, [ebp+EXTFS.dwordsPerBranch]
add edx, [ebp+EXTFS.dwordsPerBlock]
add edx, 12
jecxz .newExtent
xor edx, edx
.triplyIndirectBlock:
push ecx ebx edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
pop edx
mov esi, eax
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
test eax, eax
jz .newBlock
mov ebx, esi
call extfsReadBlock
pop ebx ecx
jc .errFree
mov eax, edx
xor edx, edx
div [ebp+EXTFS.dwordsPerBranch]
lea edi, [esi+eax*4]
test eax, eax
jz @f
cmp dword[edi-4], 0
jnz @f
mov al, ERROR_FS_FAIL
.errFree:
push ecx eax
stdcall kernel_free, esi
pop eax ecx
.errDone:
imul ecx, [ebp+EXTFS.sectorsPerBlock]
sub [ebp+EXTFS.inodeBuffer.sectorsUsed], ecx
pop ebx
imul ebx, [ebp+EXTFS.sectorsPerBlock]
add ebx, ecx
shl ebx, 9
sub [ebp+EXTFS.inodeBuffer.fileSize], ebx
stc
jmp .ret
 
.newBlock:
pop ebx ecx
mov al, ERROR_FS_FAIL
test edx, edx
jnz .errFree
mov [ebp+EXTFS.inodeBuffer.tripleAddress], ebx
inc ebx
dec ecx
inc dword[esp]
push ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, esi
xor eax, eax
rep stosd
mov edi, esi
pop ecx
@@:
jecxz .extentAlloc
call doublyIndirectBlockAlloc
jc .errSave
add edi, 4
jmp @b
 
.extentAlloc:
mov ecx, [esp]
mov eax, [esp+4]
jecxz @f
call extfsExtentAlloc
jc .errSave
sub [esp], ecx
jmp @b
 
@@:
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
mov ebx, esi
call extfsWriteBlock
stdcall kernel_free, esi
.done:
xor eax, eax
pop edi
.ret:
pop edi edi esi ebx
ret
 
.errSave:
push eax
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
mov ebx, esi
call extfsWriteBlock
pop eax
jmp .errFree
 
freeBlockList:
; in: edi -> list of blocks, edx = amount of blocks
; out: ebx=0 -> end of list
mov ebx, [edi]
test ebx, ebx
jz .ret
xor eax, eax
xor ecx, ecx
@@:
stosd
inc ecx
dec edx
jz @f
mov eax, [edi]
sub eax, ebx
sub eax, ecx
jz @b
@@:
mov eax, ebx
call extfsExtentFree
test edx, edx
jnz freeBlockList
.ret:
ret
 
freeIndirectBlock:
; in: edi -> indirect block number, edx = starting block
; out: edi = edi+4, eax=0 -> end
pushd ecx 0 edi edx
mov eax, [edi]
test eax, eax
jz .ret
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .ret
lea edi, [ebx+edx*4]
neg edx
add edx, [ebp+EXTFS.dwordsPerBlock]
call freeBlockList
test ebx, ebx
jz @f
inc dword[esp+8]
@@:
pop edx edi
mov eax, [edi]
test edx, edx
jnz @f
xor ecx, ecx
inc ecx
call extfsExtentFree
stosd
jmp .done
 
@@:
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsWriteBlock
add edi, 4
.done:
pop eax ecx
xor edx, edx
ret
 
.ret:
pop edi edi edx ecx
ret
 
freeDoublyIndirectBlock:
; in: edi -> doubly-indirect block number, edx = starting block
; out: edi = edi+4, eax=-1 -> done, eax=0 -> end
mov eax, [edi]
test eax, eax
jz .ret
push ecx eax edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
mov ebx, eax
pop edx eax
pushd 0 ebx edx
call extfsReadBlock
jc .err
mov eax, edx
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
sub ecx, eax
push edi
lea edi, [ebx+eax*4]
@@:
call freeIndirectBlock
test eax, eax
jz .end
dec ecx
jnz @b
dec dword[esp+12]
.end:
pop edi edx
mov eax, [edi]
test edx, edx
jnz @f
xor ecx, ecx
inc ecx
call extfsExtentFree
stosd
jmp .done
 
@@:
mov ebx, [esp]
call extfsWriteBlock
add edi, 4
jmp .done
 
.err:
mov [esp+8], eax
pop eax
.done:
call kernel_free
pop eax ecx
.ret:
xor edx, edx
ret
 
extfsTruncateFile:
; in: edx:eax = new size, [ebp+EXTFS.inodeBuffer] = inode
lea esi, [ebp+EXTFS.inodeBuffer]
mov ecx, edx
cmp eax, [esi+INODE.fileSize]
sbb ecx, [esi+INODE.fileSizeHigh]
jnc .ret
mov [esi+INODE.fileSize], eax
mov [esi+INODE.fileSizeHigh], edx
sub eax, 1
sbb edx, 0
jc @f
div [ebp+EXTFS.bytesPerBlock]
@@:
inc eax
mov edx, eax
cmp edx, 12
jc .directBlocks
sub edx, 12
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jc .indirectBlocks
sub edx, [ebp+EXTFS.dwordsPerBlock]
cmp edx, [ebp+EXTFS.dwordsPerBranch]
jc .doublyIndirectBlock
sub edx, [ebp+EXTFS.dwordsPerBranch]
jmp .triplyIndirectBlock
 
.directBlocks:
lea edi, [esi+INODE.blockNumbers+edx*4]
neg edx
add edx, 12
call freeBlockList
test ebx, ebx
jz .ret
.indirectBlocks:
lea edi, [esi+INODE.addressBlock]
call freeIndirectBlock
test eax, eax
jz .ret
.doublyIndirectBlock:
lea edi, [esi+INODE.doubleAddress]
call freeDoublyIndirectBlock
test eax, eax
jz .ret
.triplyIndirectBlock:
mov eax, [esi+INODE.tripleAddress]
test eax, eax
jz .ret
push eax edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
mov ebx, eax
pop edx eax
push ebx eax edx
call extfsReadBlock
jc .err
mov eax, edx
xor edx, edx
div [ebp+EXTFS.dwordsPerBranch]
mov ecx, [ebp+EXTFS.dwordsPerBlock]
sub ecx, eax
lea edi, [ebx+eax*4]
@@:
call freeDoublyIndirectBlock
test eax, eax
jz .end
dec ecx
jnz @b
.end:
pop edx eax
test edx, edx
jnz @f
xor ecx, ecx
inc ecx
call extfsExtentFree
mov [esi+INODE.tripleAddress], eax
jmp .done
 
@@:
mov ebx, [esp]
call extfsWriteBlock
jmp .done
 
.err:
pop eax eax
.done:
call kernel_free
.ret:
ret
 
linkInode:
; in:
; eax = inode on which to link
; ebx = inode to link
; esi -> name in UTF-8
; dl = file type
push esi edi ebx ecx eax edx
call strlen
push esi ebx ecx
lea esi, [ebp+EXTFS.inodeBuffer]
mov ebx, esi
call readInode
jc .error_inode_read
mov eax, [esi+INODE.fileSize]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
xor ecx, ecx
.searchBlock:
push eax ; blocks total
push ecx ; current file block number
cmp eax, ecx
jz .alloc_block
call extfsGetExtent
jc .error_get_inode_block
push eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .error_block_read
mov ecx, [esp+12]
add ecx, 8 ; directory entry size
mov edi, [ebp+EXTFS.tempBlockBuffer]
mov edx, edi
add edx, [ebp+EXTFS.bytesPerBlock]
.searchSpace:
movzx eax, [edi+DIRENTRY.entryLength]
test eax, eax
jz .zeroLength
cmp [edi+DIRENTRY.inodeNumber], 0
je .unusedEntry
movzx ebx, [edi+DIRENTRY.nameLength]
add ebx, 8+3
and ebx, -4
sub eax, ebx
add edi, ebx
cmp eax, ecx
jb .nextEntry
sub edi, ebx
mov [edi+DIRENTRY.entryLength], bx
add edi, ebx
mov [edi+DIRENTRY.entryLength], ax
jmp .found
 
.unusedEntry:
cmp eax, ecx
jge .found
.nextEntry:
add edi, eax
cmp edi, edx
jb .searchSpace
pop ecx
@@:
pop ecx eax
inc ecx
jmp .searchBlock
 
.zeroLength:
mov eax, edx
sub eax, edi
mov [edi+DIRENTRY.entryLength], ax
cmp eax, ecx
jge .found
mov [edi+DIRENTRY.inodeNumber], 0
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jmp @b
 
.alloc_block:
mov eax, [esi+INODE.fileSize]
add eax, [ebp+EXTFS.bytesPerBlock]
xor edx, edx
mov ecx, [esp+24]
call extfsExtendFile
jc .error_get_inode_block
mov eax, [esp+24]
mov ebx, esi
call writeInode
jc .error_get_inode_block
mov ecx, [esp]
call extfsGetExtent
jc .error_get_inode_block
push eax
mov edi, [ebp+EXTFS.tempBlockBuffer]
mov eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+DIRENTRY.entryLength], ax
.found:
pop edx ecx ecx ecx ebx esi
mov [edi+DIRENTRY.inodeNumber], ebx
mov word [edi+DIRENTRY.nameLength], cx
sub eax, 8
cmp ecx, eax
adc ecx, 0
test [ebp+EXTFS.superblock.incompatibleFlags], 2
jz @f
mov eax, [esp]
mov [edi+DIRENTRY.fileType], al
@@:
add edi, 8
rep movsb
mov eax, edx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
@@:
pop edx ecx ecx ebx edi esi
ret
 
.error_block_read:
pop ebx
.error_get_inode_block:
pop ebx ebx
.error_inode_read:
pop ebx ebx ebx
jmp @b
 
unlinkInode:
; in: eax = directory inode number, esi = inode to unlink
push edi
lea ebx, [ebp+EXTFS.inodeBuffer]
call readInode
jc .ret
xor ecx, ecx
.loop:
push ecx
call extfsGetExtent
jc .fail_loop
mov edi, eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail_loop
.first_dir_entry: ; edi -> block
cmp [ebx+DIRENTRY.inodeNumber], esi
jne @f
mov [ebx+DIRENTRY.inodeNumber], 0
mov word [ebx+DIRENTRY.nameLength], 0 ; fileType = 0
jmp .write_block
 
.fail:
pop edi
movi eax, ERROR_FS_FAIL
stc
.fail_loop:
pop edi
jmp .ret
 
.next:
pop ecx ecx
inc ecx
jmp .loop
 
@@:
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
push edx
@@:
movzx ecx, [ebx+DIRENTRY.entryLength]
jecxz .fail
mov edx, ebx
add ebx, ecx
cmp ebx, [esp]
jnc .next
cmp [ebx+DIRENTRY.inodeNumber], esi
jnz @b
mov cx, [ebx+DIRENTRY.entryLength]
add [edx+DIRENTRY.entryLength], cx
pop eax
.write_block:
pop eax
mov eax, edi
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
.ret:
pop edi
ret
 
findInode:
; in: esi -> path string in UTF-8
; out:
; edi -> file name in UTF-8
; esi = last inode number
; [ebp+EXTFS.inodeBuffer] = last inode
; ecx = parent inode number
; CF=1 -> file not found, edi=0 -> error
push esi
lea esi, [ebp+EXTFS.rootInodeBuffer]
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov edx, esi
rep movsb
pop esi
pushd ebx 0 ROOT_INODE
mov edi, esi
cmp [edx+INODE.fileSize], 0
jz .not_found
cmp byte [esi], 0
jnz .next_path_part
xor eax, eax
pop esi ecx ebx
ret
 
@@:
pop esi esi
.error:
pop esi ecx ebx
xor edi, edi
stc
ret
 
.next_path_part:
push [edx+INODE.fileSize]
xor ecx, ecx
.folder_block_cycle:
push ecx
call extfsGetExtent
jc @b
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc @b
push esi edx
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
.start_rec:
cmp [ebx+DIRENTRY.inodeNumber], 0
jz .next_rec
push esi
movzx ecx, [ebx+DIRENTRY.nameLength]
lea edi, [ebx+DIRENTRY.name]
repz cmpsb
jz .test_find
@@: ; doesn't match
pop esi
.next_rec:
movzx ecx, [ebx+DIRENTRY.entryLength]
jecxz .stop
add ebx, ecx
cmp ebx, edx
jb .start_rec
jmp .stop
 
.test_find:
cmp byte [esi], 0
je @f
cmp byte [esi], '/'
jne @b
inc esi
@@:
pop edx
.stop:
pop edx edi ecx eax
; ebx -> matched directory entry, esi -> name without parent, or not changed
cmp edi, esi
jnz @f
sub eax, [ebp+EXTFS.bytesPerBlock]
jle .not_found
push eax
inc ecx
jmp .folder_block_cycle
 
@@:
pop eax
mov [esp], eax
mov eax, [ebx+DIRENTRY.inodeNumber]
lea ebx, [ebp+EXTFS.inodeBuffer]
push eax
call readInode
jc .error
cmp byte [esi], 0
je .ret
mov edx, ebx
movzx eax, [ebx+INODE.accessMode]
and eax, TYPE_MASK
cmp eax, DIRECTORY
jz .next_path_part
xor edi, edi ; path folder is a file
jmp @f
 
.not_found:
mov esi, edi
call strlen
mov al, '/'
repnz scasb
mov edi, esi
jnz @f
xor edi, edi ; path folder not found
@@:
movi eax, ERROR_FILE_NOT_FOUND
stc
.ret:
pop esi ecx ebx
ret
 
writeSuperblock:
push ebx
mov eax, 2
lea ebx, [ebp+EXTFS.superblock]
call fs_write32_sys
pop ebx
ret
 
extfsWritingInit:
movi eax, ERROR_UNSUPPORTED_FS
test [ebp+EXTFS.mountType], READ_ONLY
jnz @f
ext_lock:
lea ecx, [ebp+EXTFS.Lock]
jmp mutex_lock
 
@@:
pop ebx
xor ebx, ebx
ret
 
ext_unlock:
lea ecx, [ebp+EXTFS.Lock]
jmp mutex_unlock
 
;----------------------------------------------------------------
ext_ReadFolder:
call ext_lock
cmp byte [esi], 0
jz .root_folder
call findInode
jc .error_ret
lea esi, [ebp+EXTFS.inodeBuffer]
test [esi+INODE.accessMode], FLAG_FILE
jnz .error_not_found
jmp @f
 
.root_folder:
lea esi, [ebp+EXTFS.rootInodeBuffer]
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
shr ecx, 2
push edi
rep movsd
pop esi
@@:
cmp [esi+INODE.fileSize], 0
je .error_empty_dir
mov edx, [ebx+16]
push edx ; [edi+28] result buffer
push 0 ; [edi+24] end of the current block in folder
pushd [ebx+12] ; [edi+20] files to read
pushd [ebx+4] ; [edi+16] first wanted file
pushd [ebx+8] ; [edi+12] flags
push 0 ; [edi+8] read files
push 0 ; [edi+4] files in folder
push 0 ; [edi] current block index
mov edi, esp ; edi -> local variables
add edx, 32
xor ecx, ecx
call extfsGetExtent
jc .error_get_block
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .error_get_block
mov eax, ebx
add eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+24], eax
mov ecx, [edi+16]
.find_wanted_start:
jecxz .find_wanted_end
.find_wanted_cycle:
cmp [ebx+DIRENTRY.inodeNumber], 0
jz @f
inc dword [edi+4]
dec ecx
@@:
movzx eax, [ebx+DIRENTRY.entryLength]
cmp eax, 12 ; minimum entry length
jb .error_bad_len
test eax, 3 ; length must be aligned
jnz .error_bad_len
sub [esi+INODE.fileSize], eax
add ebx, eax
cmp ebx, [edi+24]
jb .find_wanted_start
push .find_wanted_start
.end_block: ; read next block
cmp [esi+INODE.fileSize], 0
jle .end_dir
inc dword [edi]
push ecx
mov ecx, [edi]
call extfsGetExtent
jc .error_get_block
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .error_get_block
pop ecx
mov eax, ebx
add eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+24], eax
ret
 
.wanted_end:
loop .find_wanted_cycle
.find_wanted_end:
mov ecx, [edi+20]
.wanted_start:
jecxz .wanted_end
cmp [ebx+DIRENTRY.inodeNumber], 0
jz .empty_rec
inc dword [edi+8]
inc dword [edi+4]
push ebx edi ecx esi edx edi
pushd [edi+12]
mov edi, edx
xor eax, eax
mov ecx, 40 / 4
rep stosd
popd [edx+4] edi
mov eax, [ebx+DIRENTRY.inodeNumber]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call readInode
jc .error_read_subinode
mov esi, ebx
lea edi, [edx+8]
mov eax, [ebx+INODE.inodeModified]
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
 
mov eax, [esi+INODE.accessedTime]
sub eax, 978307200
call fsTime2bdfe
 
mov eax, [esi+INODE.dataModified]
sub eax, 978307200
call fsTime2bdfe
pop edx
or dword [edx], KOS_DIRECTORY
test [esi+INODE.accessMode], FLAG_FILE
jz @f
xor dword [edx], KOS_DIRECTORY ; mark as file
mov eax, [esi+INODE.fileSize]
stosd
mov eax, [esi+INODE.fileSizeHigh]
stosd
@@:
mov esi, [esp+12]
movzx ecx, [esi+DIRENTRY.nameLength]
lea esi, [esi+DIRENTRY.name]
cmp byte [esi], '.'
jnz @f
or byte [edx], KOS_HIDDEN
@@:
lea edi, [edx+40]
cmp byte [edx+4], 3
jz .utf8
add ecx, esi
cmp byte [edx+4], 2
jz .utf16
@@:
call utf8to16
call uni2ansi_char
stosb
cmp esi, ecx
jc @b
and byte [edi], 0
add edx, 40+264
@@:
pop esi ecx edi ebx
dec ecx
.empty_rec:
movzx eax, [ebx+DIRENTRY.entryLength]
cmp eax, 12
jb .error_bad_len
test eax, 3
jnz .error_bad_len
sub [esi+INODE.fileSize], eax
add ebx, eax
cmp ebx, [edi+24]
jb .wanted_start
push .wanted_start
jmp .end_block
 
.utf8:
rep movsb
mov byte [edi], 0
add edx, 40+520
jmp @b
 
.utf16:
call utf8to16
stosw
cmp esi, ecx
jc .utf16
and word [edi], 0
add edx, 40+520
jmp @b
 
.end_dir:
call ext_unlock
mov edx, [edi+28]
mov ebx, [edi+8]
mov ecx, [edi+4]
mov dword [edx], 1 ; version
mov [edx+4], ebx
mov [edx+8], ecx
lea esp, [edi+32]
mov ecx, 20/4
lea edi, [edx+12]
xor eax, eax
rep stosd
ret
 
.error_bad_len:
movi eax, ERROR_FS_FAIL
.error_read_subinode:
.error_get_block:
lea esp, [edi+32]
.error_ret:
xor ebx, ebx
push eax
call ext_unlock
pop eax
ret
 
.error_empty_dir:
movi eax, ERROR_FS_FAIL
jmp .error_ret
 
.error_not_found:
movi eax, ERROR_FILE_NOT_FOUND
jmp .error_ret
 
;----------------------------------------------------------------
ext_ReadFile:
call ext_lock
call findInode
pushd 0 eax
jc .ret
lea esi, [ebp+EXTFS.inodeBuffer]
mov byte [esp], ERROR_ACCESS_DENIED
test [esi+INODE.accessMode], FLAG_FILE
jz .ret ; not a file
mov byte [esp], ERROR_END_OF_FILE
mov eax, [esi+INODE.fileSize]
mov edx, [esi+INODE.fileSizeHigh]
sub eax, [ebx+4]
sbb edx, [ebx+8]
jc .ret
mov ecx, [ebx+12]
sub eax, ecx
sbb edx, 0
jc @f
xor eax, eax
mov [esp], eax
@@:
add ecx, eax
mov eax, [ebx+4]
mov edx, [ebx+8]
mov edi, [ebx+16]
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .aligned
.piece:
push eax ecx
mov esi, edx
mov ecx, eax
call extfsGetExtent
jc .errorGet
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call fs_read64_sys
test eax, eax
jnz .errorRead
pop eax
mov ecx, [ebp+EXTFS.bytesPerBlock]
sub ecx, esi
sub eax, ecx
jnc @f
add ecx, eax
xor eax, eax
@@:
add esi, ebx
add [esp+8], ecx
rep movsb
mov ecx, eax
pop eax
inc eax
xor edx, edx
jecxz .ret
.aligned:
xchg eax, ecx
div [ebp+EXTFS.bytesPerBlock]
push edx
mov edx, eax
.writeExtent:
test edx, edx
jz .end
push ecx
call extfsGetExtent
jc .errorGet
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
add [esp], ecx
imul ecx, [ebp+EXTFS.sectorsPerBlock]
mov ebx, edi
push edx ecx
mul [ebp+EXTFS.sectorsPerBlock]
call fs_read64_sys
pop ecx edx
test eax, eax
jnz .errorRead
shl ecx, 9
add edi, ecx
add [esp+12], ecx
pop ecx
jmp .writeExtent
 
.end:
mov eax, ecx
pop ecx
jecxz .ret
jmp .piece
 
.errorRead:
movi eax, ERROR_DEVICE
.errorGet:
pop ebx ebx
mov [esp], eax
.ret:
call ext_unlock
pop eax ebx
ret
 
;----------------------------------------------------------------
ext_GetFileInfo:
cmp byte [esi], 0
jz .volume
call ext_lock
call findInode
jc .ret
lea esi, [ebp+EXTFS.inodeBuffer]
mov edx, [ebx+16]
mov bl, [edi]
xor eax, eax
mov edi, edx
mov ecx, 40/4
rep stosd
cmp bl, '.'
jne @f
or dword [edx], KOS_HIDDEN
@@:
or dword [edx], KOS_DIRECTORY
test [esi+INODE.accessMode], FLAG_FILE
jz @f
xor dword [edx], KOS_DIRECTORY ; mark as file
mov eax, [esi+INODE.fileSize]
mov ebx, [esi+INODE.fileSizeHigh]
mov dword [edx+32], eax
mov dword [edx+36], ebx
@@:
lea edi, [edx+8]
mov eax, [esi+INODE.inodeModified]
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
 
mov eax, [esi+INODE.accessedTime]
sub eax, 978307200
call fsTime2bdfe
 
mov eax, [esi+INODE.dataModified]
sub eax, 978307200
call fsTime2bdfe
xor eax, eax
.ret:
push eax
call ext_unlock
pop eax
@@:
ret
 
.volume:
mov eax, dword[ebp+EXTFS.Length]
mov edx, dword[ebp+EXTFS.Length+4]
mov edi, [ebx+16]
shld edx, eax, 9
shl eax, 9
mov [edi+36], edx
mov [edi+32], eax
mov eax, [ebx+8]
mov byte [edi], 8
mov [edi+4], eax
test eax, eax
jz @b
lea esi, [ebp+EXTFS.superblock.volumeLabel]
mov ecx, 16
add edi, 40
cmp eax, 3
jz .utf8
add ecx, esi
cmp eax, 2
jz .utf16
@@:
call utf8to16
call uni2ansi_char
stosb
cmp esi, ecx
jc @b
jmp @f
 
.utf8:
rep movsb
jmp @f
 
.utf16:
call utf8to16
stosw
cmp esi, ecx
jc .utf16
@@:
xor eax, eax
mov [edi], ax
ret
 
;----------------------------------------------------------------
ext_SetFileInfo:
call extfsWritingInit
call findInode
jc @f
push esi
mov esi, [ebx+16]
add esi, 16
lea edi, [ebp+EXTFS.inodeBuffer]
call fsCalculateTime
add eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
mov [edi+INODE.accessedTime], eax
 
add esi, 8
call fsCalculateTime
add eax, 978307200
mov [edi+INODE.dataModified], eax
mov ebx, edi
pop eax
call writeInode
@@:
push eax
jc @f
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
@@:
call ext_unlock
pop eax
ret
 
;----------------------------------------------------------------
ext_Delete:
call extfsWritingInit
call findInode
jc .error
push ecx
movzx edi, [ebp+EXTFS.inodeBuffer.accessMode]
and edi, TYPE_MASK
cmp edi, DIRECTORY
jne .file
xor ecx, ecx
.checkDirectory:
push ecx
call extfsGetExtent
jc .empty
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .error8
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
.dir_entry:
movzx ecx, [ebx+DIRENTRY.nameLength]
mov ax, word [ebx+DIRENTRY.name]
jecxz @f
cmp al, '.'
jnz .not_empty
dec ecx
jz @f
cmp al, ah
jnz .not_empty
dec ecx
jnz .not_empty
@@:
mov cx, [ebx+DIRENTRY.entryLength]
jecxz @f
add ebx, ecx
cmp ebx, edx
jb .dir_entry
@@:
pop ecx
inc ecx
jmp .checkDirectory
 
.not_empty:
pop eax eax
push ERROR_ACCESS_DENIED
jmp .ret
 
.error8:
pop ebx
.error4:
pop ebx
.error:
push eax
jmp .ret
 
.empty:
pop ecx ecx
cmp eax, ERROR_END_OF_FILE
jnz .error
push ecx
.file:
mov eax, ecx
call unlinkInode
jc .error4
pop eax
lea ebx, [ebp+EXTFS.inodeBuffer]
cmp edi, DIRECTORY
jnz @f
dec [ebx+INODE.linksCount]
call writeInode
@@:
mov eax, esi
call readInode
jc .error
dec [ebx+INODE.linksCount]
jz @f
cmp edi, DIRECTORY
jnz .hardlinks
@@:
push esi edi
xor eax, eax
xor edx, edx
call extfsTruncateFile ; free file's data
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
lea edi, [ebp+EXTFS.inodeBuffer]
xor eax, eax
push edi
rep stosb
call fsGetTime
pop ebx edi esi
add eax, 978307200
mov [ebx+INODE.deletedTime], eax
mov eax, esi
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
push edx
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
cmp edi, DIRECTORY
jnz @f
dec [ebx+BGDESCR.directoriesCount]
@@:
inc [ebx+BGDESCR.inodesFree]
push [ebx+BGDESCR.inodeBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov ecx, eax
call extfsReadBlock
pop edx
jc .error
mov eax, edx
and edx, 31
shr eax, 5
shl eax, 2
add eax, ebx
btr [eax], edx
mov eax, ecx
call extfsWriteBlock
inc [ebp+EXTFS.superblock.inodesFree]
.hardlinks:
mov eax, esi
lea ebx, [ebp+EXTFS.inodeBuffer]
call writeInode
push eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
.ret:
call ext_unlock
xor ebx, ebx
pop eax
ret
 
;----------------------------------------------------------------
ext_CreateFolder:
call extfsWritingInit
call findInode
jnc .success ; exist
test edi, edi
jz .error
mov eax, esi
call extfsInodeAlloc
jc .error
push ebx esi edi
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
xor eax, eax
rep stosb
call fsGetTime
add eax, 978307200
lea ebx, [ebp+EXTFS.inodeBuffer]
mov [ebx+INODE.accessedTime], eax
mov [ebx+INODE.dataModified], eax
pop edi esi edx
; edx = allocated inode number, edi -> filename, esi = parent inode number
mov [ebx+INODE.accessMode], DIRECTORY or 511
mov byte [ebx+INODE.linksCount], 2
mov eax, edx
call writeInode
jc .error
; link to self
push edx esi
mov eax, edx
mov ebx, eax
mov dl, DIR_DIRECTORY
mov esi, self_link
call linkInode
pop esi edx
jc .error
; link to parent
push edx esi
mov eax, ebx
mov ebx, esi
mov dl, DIR_DIRECTORY
mov esi, parent_link
call linkInode
pop esi edx
jc .error
; link parent to child
push esi
mov eax, esi
mov ebx, edx
mov esi, edi
mov dl, DIR_DIRECTORY
call linkInode
pop edx
jc .error
push ebx
lea ebx, [ebp+EXTFS.inodeBuffer]
inc [ebx+INODE.linksCount]
mov eax, edx
call writeInode
pop ebx
jc .error
mov eax, ebx
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
inc [ebx+BGDESCR.directoriesCount]
call extfsWriteDescriptor
.success:
.error:
push eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ext_unlock
pop eax
ret
 
self_link db ".", 0
parent_link db "..", 0
 
;----------------------------------------------------------------
ext_CreateFile:
call extfsWritingInit
pushd 0 0 ebx
call findInode
jnc .exist
test edi, edi
jz .error
mov eax, esi
call extfsInodeAlloc
jc .error
push ebx ebx esi edi
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
xor eax, eax
rep stosb
call fsGetTime
add eax, 978307200
lea ebx, [ebp+EXTFS.inodeBuffer]
mov [ebx+INODE.accessedTime], eax
mov [ebx+INODE.dataModified], eax
pop edi esi edx
; edx = allocated inode number, edi -> filename, esi = parent inode number
mov [ebx+INODE.accessMode], FLAG_FILE or 110110110b
mov byte [ebx+INODE.linksCount], 1
mov eax, edx
call writeInode
jc .error2
; link parent to child
mov eax, esi
mov ebx, edx
mov esi, edi
mov dl, DIR_FLAG_FILE
call linkInode
jc .error2
mov eax, ebx
lea ebx, [ebp+EXTFS.inodeBuffer]
call readInode
jc .error2
pop esi ebx
mov eax, [ebx+12]
xor edx, edx
jmp ext_WriteFile.start
 
.exist:
movi eax, ERROR_ACCESS_DENIED
test [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
jz .error ; not a file
pop ebx
mov eax, [ebx+12]
xor edx, edx
push eax edx ebx esi
call extfsTruncateFile
pop esi ebx edx eax
jmp ext_WriteFile.start
 
.error2:
pop ebx
.error:
push eax
call ext_unlock
pop eax ebx ebx ebx
ret
 
;----------------------------------------------------------------
ext_WriteFile:
call extfsWritingInit
call findInode
pushd 0 eax
jc .ret
mov byte [esp], ERROR_ACCESS_DENIED
test [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
jz .ret ; not a file
mov byte [esp], 0
mov eax, [ebx+4]
mov edx, [ebx+8]
add eax, [ebx+12]
adc edx, 0
.start:
push esi
mov ecx, esi
call extfsExtendFile
jc .errorExtend
mov eax, [ebx+4]
mov edx, [ebx+8]
mov ecx, [ebx+12]
mov esi, [ebx+16]
.write:
jecxz .zero
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .aligned
.piece:
mov ebx, ecx
mov edi, edx
mov ecx, eax
push eax
call extfsGetExtent
jc .errorGet
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
push ecx eax ebx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call fs_read64_sys
test eax, eax
jnz .errorDevice
pop eax
mov ecx, [ebp+EXTFS.bytesPerBlock]
sub ecx, edi
sub eax, ecx
jnc @f
add ecx, eax
xor eax, eax
@@:
add edi, ebx
add [esp+20], ecx
rep movsb
mov edi, eax
pop eax ecx
xor edx, edx
call fs_write64_sys
mov ecx, edi
pop eax
inc eax
xor edx, edx
.zero:
jecxz .done
.aligned:
xchg eax, ecx
div [ebp+EXTFS.bytesPerBlock]
push edx
mov edx, eax
.writeExtent:
test edx, edx
jz .end
push ecx
call extfsGetExtent
jc .errorGet2
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
add [esp], ecx
imul ecx, [ebp+EXTFS.sectorsPerBlock]
mov ebx, esi
push edx ecx
mul [ebp+EXTFS.sectorsPerBlock]
call fs_write64_sys
test eax, eax
jnz .errorDevice
pop ebx edx ecx
shl ebx, 9
add esi, ebx
add [esp+12], ebx
jmp .writeExtent
 
.end:
mov eax, ecx
pop ecx
jecxz .done
jmp .piece
 
.errorDevice:
pop eax eax
movi eax, ERROR_DEVICE
.errorGet2:
pop ebx
.errorGet:
pop ebx
.errorExtend:
mov [esp+4], eax
.done:
lea ebx, [ebp+EXTFS.inodeBuffer]
pop eax
call writeInode
add [esp], eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
.ret:
call ext_unlock
pop eax ebx
ret
 
.erase:
push eax eax edi
mov eax, ebx
jmp .write
 
;----------------------------------------------------------------
ext_SetFileEnd:
call extfsWritingInit
call findInode
jc .error2
lea edi, [ebp+EXTFS.inodeBuffer]
movi eax, ERROR_ACCESS_DENIED
test [edi+INODE.accessMode], FLAG_FILE
jz .error2 ; not a file
mov eax, [ebx+4]
mov edx, [ebx+8]
mov ebx, [edi+INODE.fileSize]
mov ecx, [edi+INODE.fileSizeHigh]
push esi ecx
cmp ebx, eax
sbb ecx, edx
mov ecx, esi
jnc @f
call extfsExtendFile
pop esi
jc .error
mov eax, [edi+INODE.fileSize]
mov edx, [edi+INODE.fileSizeHigh]
sub eax, ebx
sbb edx, esi
jnz .done
cmp eax, 1000001h
jnc .done
push eax
stdcall kernel_alloc, eax
pop ecx
test eax, eax
jz .error
push ecx
add ecx, 3
shr ecx, 2
mov edx, esi
mov esi, eax
mov edi, eax
xor eax, eax
rep stosd
pop ecx edi
push esi
call ext_WriteFile.erase
call kernel_free
xor eax, eax
ret
 
@@:
call extfsTruncateFile
pop eax
.done:
xor eax, eax
.error:
xchg eax, [esp]
lea ebx, [ebp+EXTFS.inodeBuffer]
call writeInode
add [esp], eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
pop eax
.error2:
push eax
call ext_unlock
pop eax
ret
 
;----------------------------------------------------------------
ext_Rename:
call extfsWritingInit
push esi
mov esi, edi
call findInode
jnc .error
test edi, edi
jz .error
xchg [esp], esi
push edi
call findInode
pop edi
jc .error
xor edx, edx
inc edx
test [ebp+EXTFS.inodeBuffer.accessMode], DIRECTORY
jz @f
inc edx
@@:
mov eax, ecx
push ecx edx
call unlinkInode
pop edx ecx
jc .error
cmp edx, 1
jz @f
lea ebx, [ebp+EXTFS.inodeBuffer]
dec [ebx+INODE.linksCount]
mov eax, ecx
call writeInode
jc .error
@@:
mov ebx, esi
mov esi, edi
pop eax
push eax edx
call linkInode
pop edx
jc .error
pop eax
cmp edx, 1
jz @f
lea ebx, [ebp+EXTFS.inodeBuffer]
inc [ebx+INODE.linksCount]
call writeInode
@@:
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ext_unlock
xor eax, eax
ret
 
.error:
push eax
call ext_unlock
pop eax ebx
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/ntfs.inc
0,0 → 1,4146
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; NTFS external functions
; in:
; ebx -> parameter structure of sysfunc 70
; ebp -> NTFS structure
; esi -> path string in UTF-8
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
ntfs_user_functions:
dd ntfs_free
dd (ntfs_user_functions_end - ntfs_user_functions - 4) / 4
dd ntfs_ReadFile
dd ntfs_ReadFolder
dd ntfs_CreateFile
dd ntfs_WriteFile
dd ntfs_SetFileEnd
dd ntfs_GetFileInfo
dd ntfs_SetFileInfo
dd 0
dd ntfs_Delete
dd ntfs_CreateFolder
ntfs_user_functions_end:
endg
 
; Basic concepts:
; File is a FileRecord in the $MFT.
; $MFT is a file, that consists of FileRecords and starts with FileRecord of itself.
; FileRecord (FILE) consists of a header and attributes.
; Attribute consists of a header and a body.
; Attribute's body can be inside (resident) or outside of FileRecord.
; File's data is a body of $Data (80h) attribute.
; FileRecords is a data of the $MFT file.
; Directory is a file, that consists of index nodes.
; Resident index node is always located in a body of $IndexRoot (90h) attribute.
; Body of $IndexAllocation (A0h) attribute is always non resident
; and consists of IndexRecords.
; IndexRecord (INDX) consists of a header and an index node.
; Index node consists of a header and indexes.
; Index consists of a header and a copy of indexed attribute's body.
; Directories index $Filename (30h) attribute of all existing files.
; $IndexRoot and $IndexAllocation attributes of a directory has a name — $I30.
 
; Offsets:
; record header
magic = 0
updateSequenceOffset = 4
updateSequenceSize = 6
; FileRecord header
reuseCounter = 16
hardLinkCounter = 12h
attributeOffset = 14h
recordFlags = 16h
recordRealSize = 18h
recordAllocatedSize = 1ch
baseRecordReference = 20h ; for auxiliary records
baseRecordReuse = 26h
newAttributeID = 28h
; attribute header
attributeType = 0
sizeWithHeader = 4
nonResidentFlag = 8
nameLength = 9
nameOffset = 10
attributeFlags = 12
attributeID = 14
; resident attribute header
sizeWithoutHeader = 10h
attributeOffset = 14h
indexedFlag = 16h
; non resident attribute header
firstVCN = 10h
lastVCN = 18h
dataRunsOffset = 20h
attributeAllocatedSize = 28h
attributeRealSize = 30h
initialDataSize = 38h
; $IndexRoot
indexedAttributesType = 0
collationRule = 4
indexRecordSize = 8
indexRecordSizeClus = 12 ; in sectors if less than one cluster
rootNode = 16
; IndexRecord header
recordVCN = 16
recordNode = 18h
; node header
indexOffset = 0
nodeRealSize = 4
nodeAllocatedSize = 8
nonLeafFlag = 12
; $Filename index
fileRecordReference = 0
fileReferenceReuse = 6
indexAllocatedSize = 8
indexRawSize = 10
indexFlags = 12
directoryRecordReference = 16
directoryReferenceReuse = 16h
fileCreated = 18h
fileModified = 20h
recordModified = 28h
fileAccessed = 30h
fileAllocatedSize = 38h
fileRealSize = 40h
fileFlags = 48h
fileNameLength = 50h
namespace = 51h
fileName = 52h
 
struct NTFS PARTITION
Lock MUTEX ; Currently operations with one partition
; can not be executed in parallel since the legacy code is not ready.
sectors_per_cluster dd ?
mft_cluster dd ? ; location
mftmirr_cluster dd ? ; location
frs_size dd ? ; in bytes
frs_buffer dd ? ; MFT fileRecord buffer
mft_retrieval_end dd ?
mftSize dd ? ; in sectors
cur_index_size dd ? ; in sectors
cur_index_buf dd ? ; index node buffer
secondIndexBuffer dd ?
BitmapBuffer dd ?
BitmapTotalSize dd ? ; bytes reserved
BitmapSize dd ? ; bytes readen
BitmapLocation dd ? ; starting sector
BitmapStart dd ? ; first byte after area, reserved for MFT
mftBitmapBuffer dd ? ; one cluster
mftBitmapSize dd ? ; bytes readen
mftBitmapLocation dd ? ; starting sector
 
attr_size dq ?
attr_offs dd ?
attr_list dd ?
attr_iBaseRecord dd ?
cur_attr dd ? ; attribute type
cur_iRecord dd ? ; number of fileRecord in MFT
cur_offs dd ? ; attribute VCN in sectors
cur_size dd ? ; max sectors to read
cur_buf dd ?
cur_read dd ? ; bytes readen
cur_tail dd ?
cur_subnode_size dd ?
LastRead dd ? ; last readen block of sectors
mftLastRead dd ?
rootLastRead dd ?
nodeLastRead dd ?
indexRoot dd ?
indexPointer dd ?
newRecord dd ?
fileDataStart dd ? ; starting cluster
fileDataSize dd ? ; in clusters
fileDataBuffer dd ?
fileRealSize dd ? ; in bytes
fragmentCount db ?
bCanContinue db ?
bFolder db ?
bWriteAttr db ? ; Warning: Don't forget to turn off!!!
 
mft_retrieval rb 512
align0 rb 1024-NTFS.align0
attrlist_buf rb 1024
attrlist_mft_buf rb 1024
bitmap_buf rb 1024
ends
 
ntfs_test_bootsec:
; in: ebx -> buffer, edx = size of partition
; out: CF=1 -> invalid
; 1. Name=='NTFS '
cmp dword [ebx+3], 'NTFS'
jnz .no
cmp dword [ebx+7], ' '
jnz .no
; 2. Number of bytes per sector is the same as for physical device
; (that is, 0x200 for hard disk)
cmp word [ebx+11], 0x200
jnz .no
; 3. Number of sectors per cluster must be power of 2
movzx eax, byte [ebx+13]
dec eax
js .no
test al, [ebx+13]
jnz .no
; 4. FAT parameters must be zero
cmp word [ebx+14], 0
jnz .no
cmp dword [ebx+16], 0
jnz .no
cmp byte [ebx+20], 0
jnz .no
cmp word [ebx+22], 0
jnz .no
cmp dword [ebx+32], 0
jnz .no
; 5. Number of sectors <= partition size
cmp dword [ebx+0x2C], 0
ja .no
cmp [ebx+0x28], edx
ja .no
; 6. $MFT and $MFTMirr clusters must be within partition
cmp dword [ebx+0x34], 0
ja .no
push edx
movzx eax, byte [ebx+13]
mul dword [ebx+0x30]
test edx, edx
pop edx
jnz .no
cmp eax, edx
ja .no
cmp dword [ebx+0x3C], 0
ja .no
push edx
movzx eax, byte [ebx+13]
mul dword [ebx+0x38]
test edx, edx
pop edx
jnz .no
cmp eax, edx
ja .no
; 7. Clusters per FRS must be either power of 2 or between -31 and -9
movsx eax, byte [ebx+0x40]
cmp al, -31
jl .no
cmp al, -9
jle @f
dec eax
js .no
test [ebx+0x40], al
jnz .no
@@: ; 8. Same for clusters per IndexAllocationBuffer
movsx eax, byte [ebx+0x44]
cmp al, -31
jl .no
cmp al, -9
jle @f
dec eax
js .no
test [ebx+0x44], al
jnz .no
@@: ; OK, this is correct NTFS bootsector
clc
ret
.no: ; No, this bootsector isn't NTFS
stc
ret
 
; Mount if it's a valid NTFS partition.
ntfs_create_partition:
; in:
; ebp -> PARTITION structure
; ebx -> boot sector
; ebx+512 -> buffer
; out:
; eax -> NTFS structure, 0 = not NTFS
cmp dword [esi+DISK.MediaInfo.SectorSize], 512
jnz .nope
mov edx, dword [ebp+PARTITION.Length]
cmp dword [esp+4], 0
jz .boot_read_ok
add ebx, 512
lea eax, [edx-1]
call fs_read32_sys
test eax, eax
jnz @f
call ntfs_test_bootsec
jnc .ntfs_setup
@@:
mov eax, edx
shr eax, 1
call fs_read32_sys
test eax, eax
jnz .nope
.boot_read_ok:
call ntfs_test_bootsec
jnc .ntfs_setup
.nope:
xor eax, eax
jmp .exit
 
.ntfs_setup: ; By given bootsector, initialize some NTFS variables
stdcall kernel_alloc, 1000h
test eax, eax
jz .exit
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+NTFS.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+NTFS.FirstSector+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+NTFS.Disk], ecx
mov [eax+NTFS.FSUserFunctions], ntfs_user_functions
mov [eax+NTFS.bWriteAttr], 0
 
push ebx ebp esi
mov ebp, eax
lea ecx, [ebp+NTFS.Lock]
call mutex_init
movzx eax, byte [ebx+13]
mov [ebp+NTFS.sectors_per_cluster], eax
mov eax, [ebx+0x28]
mov dword [ebp+NTFS.Length], eax
and dword [ebp+NTFS.Length+4], 0
mov eax, [ebx+0x30]
mov [ebp+NTFS.mft_cluster], eax
mov eax, [ebx+0x38]
mov [ebp+NTFS.mftmirr_cluster], eax
movsx eax, byte [ebx+0x40]
test eax, eax
js @f
mul [ebp+NTFS.sectors_per_cluster]
shl eax, 9
jmp .1
 
@@:
neg eax
mov ecx, eax
mov eax, 1
shl eax, cl
.1:
mov [ebp+NTFS.frs_size], eax
stdcall kernel_alloc, eax
test eax, eax
jz .fail_free
mov [ebp+NTFS.frs_buffer], eax
; read $MFT disposition
mov eax, [ebp+NTFS.mft_cluster]
mul [ebp+NTFS.sectors_per_cluster]
mov ecx, [ebp+NTFS.frs_size]
shr ecx, 9
mov ebx, [ebp+NTFS.frs_buffer]
call fs_read64_sys
test eax, eax
jnz .usemirr
cmp dword [ebx], 'FILE'
jnz .usemirr
call ntfs_restore_usa_frs
jnc .mftok
.usemirr:
mov eax, [ebp+NTFS.mftmirr_cluster]
mul [ebp+NTFS.sectors_per_cluster]
mov ecx, [ebp+NTFS.frs_size]
shr ecx, 9
mov ebx, [ebp+NTFS.frs_buffer]
call fs_read64_sys
test eax, eax
jnz .fail_free_frs
cmp dword [ebx], 'FILE'
jnz .fail_free_frs
call ntfs_restore_usa_frs
jc .fail_free_frs
.mftok: ; prepare $MFT retrieval information
; search for unnamed non-resident $DATA attribute
movzx eax, word [ebx+attributeOffset]
add eax, ebx
.scandata:
cmp dword [eax], -1
jz .fail_free_frs
cmp dword [eax], 0x80
jnz @f
cmp byte [eax+nameLength], 0
jz .founddata
@@:
add eax, [eax+sizeWithHeader]
jmp .scandata
 
.founddata:
cmp byte [eax+nonResidentFlag], 0
jz .fail_free_frs
movzx esi, word [eax+dataRunsOffset]
add esi, eax
mov edx, [eax+attributeAllocatedSize+4]
mov eax, [eax+attributeAllocatedSize]
shrd eax, edx, 9
mov [ebp+NTFS.mftSize], eax
sub esp, 10h
lea ecx, [ebp+NTFS.mft_retrieval]
xor edx, edx
.scanmcb: ; load descriptions of fragments
call ntfs_decode_mcb_entry
jnc .scanmcbend
mov eax, [esp] ; block length
mov [ecx], eax
add edx, [esp+8] ; block addr
mov [ecx+4], edx
add ecx, 8
jmp .scanmcb
 
.scanmcbend:
add esp, 10h
lea eax, [ebp+NTFS.attrlist_buf]
cmp eax, ecx
jc @f
mov eax, ecx
@@:
mov [ebp+NTFS.mft_retrieval_end], eax
; allocate index buffers
stdcall kernel_alloc, 2000h
test eax, eax
jz .fail_free_frs
mov [ebp+NTFS.cur_index_buf], eax
add eax, 1000h
mov [ebp+NTFS.secondIndexBuffer], eax
mov [ebp+NTFS.cur_index_size], 8
; reserve adress space for bitmap buffer and load some part of bitmap
mov eax, dword [ebp+NTFS.Length]
xor edx, edx
div [ebp+NTFS.sectors_per_cluster]
shr eax, 3
mov [ebp+NTFS.BitmapTotalSize], eax
add eax, 7FFFh
and eax, not 7FFFh
push eax
call alloc_kernel_space
test eax, eax
jz .failFreeIndex
mov [ebp+NTFS.BitmapBuffer], eax
mov [ebp+NTFS.cur_buf], eax
mov eax, [ebp+NTFS.BitmapTotalSize]
add eax, [ebp+NTFS.mft_cluster]
shr eax, 3+2 ; reserve 1/8 of partition for $MFT
shl eax, 2
mov [ebp+NTFS.BitmapStart], eax
shr eax, 15
inc eax
shl eax, 3
push eax
push eax
shl eax, 3
mov [ebp+NTFS.cur_size], eax
call alloc_pages
test eax, eax
pop ecx
jz .failFreeBitmap
add eax, 3
mov ebx, [ebp+NTFS.BitmapBuffer]
call commit_pages
mov [ebp+NTFS.cur_iRecord], 6
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
call ntfs_read_attr
jc .failFreeBitmap
mov eax, [ebp+NTFS.cur_read]
mov [ebp+NTFS.BitmapSize], eax
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.BitmapLocation], eax
; read MFT $BITMAP attribute
mov eax, [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.cur_size], eax
shl eax, 9
stdcall kernel_alloc, eax
test eax, eax
jz .failFreeBitmap
mov [ebp+NTFS.mftBitmapBuffer], eax
mov [ebp+NTFS.cur_buf], eax
mov [ebp+NTFS.cur_iRecord], 0
mov [ebp+NTFS.cur_attr], 0xB0
mov [ebp+NTFS.cur_offs], 0
call ntfs_read_attr
mov eax, [ebp+NTFS.cur_read]
cmp eax, 4
jc .failFreeBitmapMFT
mov ecx, [ebp+NTFS.attr_offs]
cmp byte [ecx+nonResidentFlag], 1
jnz .failFreeBitmapMFT
mov [ebp+NTFS.mftBitmapSize], eax
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.mftBitmapLocation], eax
 
mov eax, ebp
.pop_exit:
pop esi ebp ebx
.exit:
cmp dword [esp+4], 0
jz @f
sub ebx, 512
@@:
ret
 
.failFreeBitmapMFT:
stdcall kernel_free, [ebp+NTFS.mftBitmapBuffer]
.failFreeBitmap:
stdcall kernel_free, [ebp+NTFS.BitmapBuffer]
.failFreeIndex:
mov eax, [ebp+NTFS.cur_index_buf]
cmp eax, [ebp+NTFS.secondIndexBuffer]
jc @f
mov eax, [ebp+NTFS.secondIndexBuffer]
@@:
stdcall kernel_free, eax
.fail_free_frs:
stdcall kernel_free, [ebp+NTFS.frs_buffer]
.fail_free:
stdcall kernel_free, ebp
xor eax, eax
jmp .pop_exit
 
ntfs_free:
push ebx
mov ebx, eax
stdcall kernel_free, [ebx+NTFS.frs_buffer]
stdcall kernel_free, [ebx+NTFS.mftBitmapBuffer]
stdcall kernel_free, [ebx+NTFS.BitmapBuffer]
mov eax, [ebx+NTFS.cur_index_buf]
cmp eax, [ebx+NTFS.secondIndexBuffer]
jc @f
mov eax, [ebx+NTFS.secondIndexBuffer]
@@:
stdcall kernel_free, eax
stdcall kernel_free, ebx
pop ebx
ret
 
ntfs_lock:
lea ecx, [ebp+NTFS.Lock]
jmp mutex_lock
 
ntfs_unlock:
lea ecx, [ebp+NTFS.Lock]
jmp mutex_unlock
 
ntfs_read_attr:
; [ebp+NTFS.bWriteAttr]=1 -> write attribute
; in:
; [ebp+NTFS.cur_iRecord] = number of fileRecord
; [ebp+NTFS.cur_attr] = attribute type
; [ebp+NTFS.cur_offs] = attribute VCN in sectors
; [ebp+NTFS.cur_buf] -> buffer for data
; [ebp+NTFS.cur_size] = max sectors to read
; out:
; [ebp+NTFS.cur_read] = bytes readen
; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
xor eax, eax
pushad
and [ebp+NTFS.cur_read], 0
cmp [ebp+NTFS.cur_iRecord], 0
jnz .nomft
cmp [ebp+NTFS.cur_attr], 0x80
jnz .nomft
; precalculated part of $Mft $DATA
mov eax, [ebp+NTFS.cur_offs]
xor edx, edx
div [ebp+NTFS.sectors_per_cluster]
mov ebx, edx
mov [ebp+NTFS.fragmentCount], 0
; eax = VCN, ebx = offset in sectors from beginning of cluster
lea esi, [ebp+NTFS.mft_retrieval]
sub esi, 8
.mftscan:
add esi, 8
cmp esi, [ebp+NTFS.mft_retrieval_end]
jz .nomft
mov ecx, [esi+4]
sub eax, [esi]
jnc .mftscan
add ecx, eax
add ecx, [esi]
neg eax
mul [ebp+NTFS.sectors_per_cluster]
xchg eax, ecx
mul [ebp+NTFS.sectors_per_cluster]
sub ecx, ebx
add eax, ebx
mov ebx, [ebp+NTFS.cur_buf]
cmp ecx, [ebp+NTFS.cur_size]
jb @f
mov ecx, [ebp+NTFS.cur_size]
@@:
mov [ebp+NTFS.LastRead], eax
mov edi, ecx
call fs_read64_sys
test eax, eax
jnz .errret
sub [ebp+NTFS.cur_size], edi
add [ebp+NTFS.cur_offs], edi
shl edi, 9
add [ebp+NTFS.cur_read], edi
add [ebp+NTFS.cur_buf], edi
inc [ebp+NTFS.fragmentCount]
xor eax, eax
xor ebx, ebx
cmp [ebp+NTFS.cur_size], eax
jz @f
jmp .mftscan
 
.errret2_pop:
xor eax, eax
.errret_pop:
pop ecx
pop ecx
.errret:
mov [esp+28], eax
stc
@@:
popad
ret
 
.nomft:
; 1. Read file record.
; N.B. This will do recursive call of read_attr for $MFT::$Data.
mov eax, [ebp+NTFS.cur_iRecord]
and [ebp+NTFS.attr_list], 0
or dword [ebp+NTFS.attr_size+4], -1
or [ebp+NTFS.attr_iBaseRecord], -1
call ntfs_read_file_record
jc .errret
; 2. Find required attribute.
mov eax, [ebp+NTFS.frs_buffer]
; a) For auxiliary records, read base record.
; If base record is present, base iRecord may be 0 (for $Mft),
; but SequenceNumber is nonzero.
cmp word [eax+baseRecordReuse], 0
jz @f
mov eax, [eax+baseRecordReference]
.beginfindattr:
call ntfs_read_file_record
jc .errret
jmp @f
 
.newAttribute:
pushad
and [ebp+NTFS.cur_read], 0
@@:
; b) Scan for required attribute and for $ATTR_LIST
mov eax, [ebp+NTFS.frs_buffer]
movzx ecx, word [eax+attributeOffset]
add eax, ecx
mov ecx, [ebp+NTFS.cur_attr]
and [ebp+NTFS.attr_offs], 0
.scanattr:
cmp dword [eax], -1
jz .scandone
cmp dword [eax], ecx
jz .okattr
cmp [ebp+NTFS.attr_iBaseRecord], -1
jnz .scancont
cmp dword [eax], 0x20 ; $ATTR_LIST
jnz .scancont
mov [ebp+NTFS.attr_list], eax
jmp .scancont
 
.okattr:
; ignore named $DATA attributes (aka NTFS streams)
cmp ecx, 0x80
jnz @f
cmp byte [eax+nameLength], 0
jnz .scancont
@@:
mov [ebp+NTFS.attr_offs], eax
.scancont:
add eax, [eax+sizeWithHeader]
jmp .scanattr
 
.continue:
pushad
and [ebp+NTFS.cur_read], 0
.scandone:
; c) Check for required offset and length
mov ecx, [ebp+NTFS.attr_offs]
jecxz .noattr
push [ebp+NTFS.cur_size]
push [ebp+NTFS.cur_read]
call .doreadattr
pop edx
pop ecx
jc .ret
cmp [ebp+NTFS.bCanContinue], 0
jz .ret
sub edx, [ebp+NTFS.cur_read]
neg edx
shr edx, 9
sub ecx, edx
mov [ebp+NTFS.cur_size], ecx
jz .ret
.noattr:
cmp [ebp+NTFS.cur_attr], 0x20
jz @f
mov ecx, [ebp+NTFS.attr_list]
test ecx, ecx
jnz .lookattr
and dword [esp+28], 0
cmp [ebp+NTFS.attr_offs], 1 ; define CF
.ret:
popad
ret
 
.lookattr:
; required attribute or required offset was not found in base record;
; it may be present in auxiliary records;
; scan $ATTR_LIST
mov eax, [ebp+NTFS.attr_iBaseRecord]
cmp eax, -1
jz @f
call ntfs_read_file_record
jc .errret
or [ebp+NTFS.attr_iBaseRecord], -1
@@:
push [ebp+NTFS.cur_offs]
push [ebp+NTFS.cur_size]
push [ebp+NTFS.cur_read]
push [ebp+NTFS.cur_buf]
push dword [ebp+NTFS.attr_size]
push dword [ebp+NTFS.attr_size+4]
or dword [ebp+NTFS.attr_size+4], -1
and [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 2
and [ebp+NTFS.cur_read], 0
lea eax, [ebp+NTFS.attrlist_buf]
cmp [ebp+NTFS.cur_iRecord], 0
jnz @f
lea eax, [ebp+NTFS.attrlist_mft_buf]
@@:
mov [ebp+NTFS.cur_buf], eax
push eax
call .doreadattr
pop esi
mov edx, 1
pop dword [ebp+NTFS.attr_size+4]
pop dword [ebp+NTFS.attr_size]
mov ecx, [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_buf]
pop [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_size]
pop [ebp+NTFS.cur_offs]
jc .errret
or edi, -1
lea ecx, [ecx+esi-1Ah]
.scanliststart:
push ecx
mov eax, [ebp+NTFS.cur_attr]
.scanlist:
cmp esi, [esp]
jae .scanlistdone
cmp eax, [esi]
jz @f
.scanlistcont:
movzx ecx, word [esi+4]
add esi, ecx
jmp .scanlist
 
@@:
; ignore named $DATA attributes (aka NTFS streams)
cmp eax, 0x80
jnz @f
cmp byte [esi+6], 0
jnz .scanlistcont
@@:
push eax
mov eax, [esi+8]
test eax, eax
jnz .testf
cmp dword [ebp+NTFS.attr_size+4], -1
jnz .testfz
; if attribute is in auxiliary records, its size is defined only in first
mov eax, [esi+10h]
call ntfs_read_file_record
jc .errret_pop
mov eax, [ebp+NTFS.frs_buffer]
movzx ecx, word [eax+14h]
add eax, ecx
mov ecx, [ebp+NTFS.cur_attr]
@@:
cmp dword [eax], -1
jz .errret2_pop
cmp dword [eax], ecx
jz @f
.l1:
add eax, [eax+4]
jmp @b
 
@@:
cmp eax, 0x80
jnz @f
cmp byte [eax+9], 0
jnz .l1
@@:
cmp byte [eax+8], 0
jnz .sdnores
mov eax, [eax+10h]
mov dword [ebp+NTFS.attr_size], eax
and dword [ebp+NTFS.attr_size+4], 0
jmp .testfz
 
.sdnores:
mov ecx, [eax+30h]
mov dword [ebp+NTFS.attr_size], ecx
mov ecx, [eax+34h]
mov dword [ebp+NTFS.attr_size+4], ecx
.testfz:
xor eax, eax
.testf:
imul eax, [ebp+NTFS.sectors_per_cluster]
cmp eax, [ebp+NTFS.cur_offs]
pop eax
ja @f
mov edi, [esi+10h] ; keep previous iRecord
jmp .scanlistcont
 
@@:
pop ecx
.scanlistfound:
cmp edi, -1
jz .ret
mov eax, [ebp+NTFS.cur_iRecord]
mov [ebp+NTFS.attr_iBaseRecord], eax
mov eax, edi
jmp .beginfindattr
 
.scanlistdone:
pop ecx
sub ecx, ebp
sub ecx, NTFS.attrlist_buf-1Ah
cmp [ebp+NTFS.cur_iRecord], 0
jnz @f
sub ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
@@:
cmp ecx, 0x400
jnz .scanlistfound
inc edx
push esi edi
lea esi, [ebp+NTFS.attrlist_buf+0x200]
lea edi, [ebp+NTFS.attrlist_buf]
cmp [ebp+NTFS.cur_iRecord], 0
jnz @f
lea esi, [ebp+NTFS.attrlist_mft_buf+0x200]
lea edi, [ebp+NTFS.attrlist_mft_buf]
@@:
mov ecx, 0x200/4
rep movsd
mov eax, edi
pop edi esi
sub esi, 0x200
push [ebp+NTFS.cur_offs]
push [ebp+NTFS.cur_size]
push [ebp+NTFS.cur_read]
push [ebp+NTFS.cur_buf]
push dword [ebp+NTFS.attr_size]
push dword [ebp+NTFS.attr_size+4]
or dword [ebp+NTFS.attr_size+4], -1
mov [ebp+NTFS.cur_offs], edx
mov [ebp+NTFS.cur_size], 1
and [ebp+NTFS.cur_read], 0
mov [ebp+NTFS.cur_buf], eax
mov ecx, [ebp+NTFS.attr_list]
push esi edx edi
call .doreadattr
pop edi edx esi
mov ecx, [ebp+NTFS.cur_read]
pop dword [ebp+NTFS.attr_size+4]
pop dword [ebp+NTFS.attr_size]
pop [ebp+NTFS.cur_buf]
pop [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_size]
pop [ebp+NTFS.cur_offs]
jc .errret
lea ecx, [ecx+ebp+NTFS.attrlist_buf+0x200-0x1A]
cmp [ebp+NTFS.cur_iRecord], 0
jnz .scanliststart
add ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
jmp .scanliststart
 
.doreadattr:
mov [ebp+NTFS.bCanContinue], 0
cmp byte [ecx+nonResidentFlag], 0
jnz .nonresident
mov eax, [ecx+sizeWithoutHeader]
mov esi, eax
mov edx, [ebp+NTFS.cur_offs]
shr eax, 9
cmp eax, edx
jb .okret
shl edx, 9
sub esi, edx
movzx eax, word [ecx+attributeOffset]
add edx, eax
add edx, ecx ; edx -> data
mov eax, [ebp+NTFS.cur_size]
cmp eax, (0xFFFFFFFF shr 9)+1
jbe @f
mov eax, (0xFFFFFFFF shr 9)+1
@@:
shl eax, 9
cmp eax, esi
jbe @f
mov eax, esi
@@:
; eax = length, edx -> data
mov [ebp+NTFS.cur_read], eax
mov ecx, eax
mov eax, edx
mov ebx, [ebp+NTFS.cur_buf]
call memmove
and [ebp+NTFS.cur_size], 0 ; CF=0
ret
 
.nonresident:
; Not all auxiliary records contain correct FileSize info
mov eax, dword [ebp+NTFS.attr_size]
mov edx, dword [ebp+NTFS.attr_size+4]
cmp edx, -1
jnz @f
mov eax, [ecx+attributeRealSize]
mov edx, [ecx+attributeRealSize+4]
mov dword [ebp+NTFS.attr_size], eax
mov dword [ebp+NTFS.attr_size+4], edx
@@:
add eax, 0x1FF
adc edx, 0
shrd eax, edx, 9
sub eax, [ebp+NTFS.cur_offs]
ja @f
; return with nothing read
and [ebp+NTFS.cur_size], 0
.okret:
clc
ret
 
@@:
; reduce read length
and [ebp+NTFS.cur_tail], 0
cmp [ebp+NTFS.cur_size], eax
jb @f
mov [ebp+NTFS.cur_size], eax
mov eax, dword [ebp+NTFS.attr_size]
and eax, 0x1FF
mov [ebp+NTFS.cur_tail], eax
@@:
mov eax, [ebp+NTFS.cur_offs]
xor edx, edx
div [ebp+NTFS.sectors_per_cluster]
sub eax, [ecx+firstVCN]
jb .okret
mov ebx, edx
; eax = starting cluster, ebx = sector in the cluster
cmp [ebp+NTFS.cur_attr], 0x80
jnz .sys
cmp [ebp+NTFS.cur_iRecord], 0
jz .sys
push fs_read64_app
cmp [ebp+NTFS.bWriteAttr], 1
jnz @f
mov dword[esp], fs_write64_app
jmp @f
 
.sys:
push fs_read64_sys
@@:
sub esp, 10h
movzx esi, word [ecx+dataRunsOffset]
add esi, ecx
xor edi, edi
mov [ebp+NTFS.fragmentCount], 0
.readloop:
call ntfs_decode_mcb_entry
jnc .break
add edi, [esp+8]
sub eax, [esp]
jae .readloop
mov ecx, edi
add ecx, eax
add ecx, [esp]
neg eax
mul [ebp+NTFS.sectors_per_cluster]
xchg eax, ecx
mul [ebp+NTFS.sectors_per_cluster]
sub ecx, ebx
add eax, ebx
mov ebx, [ebp+NTFS.cur_buf]
cmp ecx, [ebp+NTFS.cur_size]
jb @f
mov ecx, [ebp+NTFS.cur_size]
@@:
mov [ebp+NTFS.LastRead], eax
push ecx
call dword[esp+14h]
pop ecx
test eax, eax
jnz .errread2
sub [ebp+NTFS.cur_size], ecx
add [ebp+NTFS.cur_offs], ecx
shl ecx, 9
add [ebp+NTFS.cur_read], ecx
add [ebp+NTFS.cur_buf], ecx
inc [ebp+NTFS.fragmentCount]
xor eax, eax
xor ebx, ebx
cmp [ebp+NTFS.cur_size], 0
jnz .readloop
add esp, 14h
mov eax, [ebp+NTFS.cur_tail]
test eax, eax
jz @f
sub eax, 0x200
add [ebp+NTFS.cur_read], eax
@@:
clc
ret
 
.errread2:
add esp, 14h
stc
ret
 
.break:
add esp, 14h ; CF=0
mov [ebp+NTFS.bCanContinue], 1
ret
 
ntfs_read_file_record:
; in: eax = iRecord
; out: [ebp+NTFS.frs_buffer] -> file record
; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
; Read attr $DATA of $Mft, starting from eax*[ebp+NTFS.frs_size]
push ecx edx
mov ecx, [ebp+NTFS.frs_size]
mul ecx
shrd eax, edx, 9
shr edx, 9
jnz .errret
push [ebp+NTFS.attr_iBaseRecord]
push [ebp+NTFS.attr_offs]
push [ebp+NTFS.attr_list]
push dword [ebp+NTFS.attr_size+4]
push dword [ebp+NTFS.attr_size]
push [ebp+NTFS.cur_iRecord]
push [ebp+NTFS.cur_attr]
push [ebp+NTFS.cur_offs]
push [ebp+NTFS.cur_size]
push [ebp+NTFS.cur_buf]
push [ebp+NTFS.cur_read]
mov [ebp+NTFS.cur_attr], 0x80 ; $DATA
and [ebp+NTFS.cur_iRecord], 0 ; $Mft
mov [ebp+NTFS.cur_offs], eax
shr ecx, 9
mov [ebp+NTFS.cur_size], ecx
mov eax, [ebp+NTFS.frs_buffer]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr
mov edx, [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_buf]
pop [ebp+NTFS.cur_size]
pop [ebp+NTFS.cur_offs]
pop [ebp+NTFS.cur_attr]
pop [ebp+NTFS.cur_iRecord]
pop dword [ebp+NTFS.attr_size]
pop dword [ebp+NTFS.attr_size+4]
pop [ebp+NTFS.attr_list]
pop [ebp+NTFS.attr_offs]
pop [ebp+NTFS.attr_iBaseRecord]
jc .ret
cmp edx, [ebp+NTFS.frs_size]
jnz .errret
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.mftLastRead], eax
mov eax, [ebp+NTFS.frs_buffer]
cmp dword [eax], 'FILE'
jnz .errret
push ebx
mov ebx, eax
call ntfs_restore_usa_frs
pop ebx
jc .errret
.ret:
pop edx ecx
ret
 
.errret:
pop edx ecx
xor eax, eax
stc
ret
 
ntfs_restore_usa_frs:
mov eax, [ebp+NTFS.frs_size]
ntfs_restore_usa:
; in:
; ebx -> record
; eax = size in bytes
pushad
shr eax, 9
mov ecx, eax
inc eax
cmp [ebx+updateSequenceSize], ax
jnz .err
movzx eax, word [ebx+updateSequenceOffset]
lea esi, [eax+ebx]
lodsw
mov edx, eax
lea edi, [ebx+0x1FE]
@@:
cmp [edi], dx
jnz .err
lodsw
stosw
add edi, 0x1FE
loop @b
popad
clc
ret
 
.err:
popad
stc
ret
 
ntfs_decode_mcb_entry:
; in:
; esi -> MCB entry
; esp -> buffer (16 bytes)
; out:
; esi -> next MCB entry
; esp -> data run size
; esp+8 -> cluster (delta)
; CF=0 -> MCB end
push eax ecx edi
lea edi, [esp+16]
xor eax, eax
lodsb
test al, al
jz .end
mov ecx, eax
and ecx, 0xF
cmp ecx, 8
ja .end
push ecx
rep movsb
pop ecx
sub ecx, 8
neg ecx
cmp byte [esi-1], 80h
jae .end
push eax
xor eax, eax
rep stosb
pop ecx
shr ecx, 4
cmp ecx, 8
ja .end
push ecx
rep movsb
pop ecx
sub ecx, 8
neg ecx
cmp byte [esi-1], 80h
cmc
sbb eax, eax
rep stosb
stc
.end:
pop edi ecx eax
ret
 
ntfs_find_lfn:
; in: esi -> path string in UTF-8
; out:
; [ebp+NTFS.cur_iRecord] = target fileRecord
; eax -> target index in the node
; [ebp+NTFS.LastRead] = target node location
; [ebp+NTFS.indexPointer] -> index, that points the target subnode
; [ebp+NTFS.nodeLastRead] = branch node location
; [ebp+NTFS.indexRoot] -> attribute
; [ebp+NTFS.rootLastRead] = directory fileRecord location
; [ebp+NTFS.cur_size] = index record size in sectors
; [ebp+NTFS.cur_subnode_size] = index record size in clusters or sectors
; CF=1 -> file not found, eax=0 -> error
mov [ebp+NTFS.cur_iRecord], 5 ; start from root directory
.doit2:
mov [ebp+NTFS.cur_attr], 0x90 ; $INDEX_ROOT
and [ebp+NTFS.cur_offs], 0
mov eax, [ebp+NTFS.cur_index_size]
mov [ebp+NTFS.cur_size], eax
mov eax, [ebp+NTFS.cur_index_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr
mov eax, 0
jc .ret
cmp [ebp+NTFS.cur_read], 0x20
jc .ret
push esi
pushad
mov esi, [ebp+NTFS.cur_index_buf]
mov eax, [esi+indexRecordSize]
shr eax, 9
cmp [ebp+NTFS.cur_index_size], eax
jc .realloc
mov [ebp+NTFS.cur_size], eax
mov al, [esi+indexRecordSizeClus]
mov [ebp+NTFS.cur_subnode_size], eax
add esi, rootNode
mov eax, [esi+nodeRealSize]
add eax, rootNode
cmp [ebp+NTFS.cur_read], eax
jc .err
mov eax, [ebp+NTFS.mftLastRead]
mov [ebp+NTFS.rootLastRead], eax
mov eax, [ebp+NTFS.attr_offs]
mov [ebp+NTFS.indexRoot], eax
.scanloop: ; esi -> current index node
add esi, [esi+indexOffset]
.scanloopint:
push esi
test byte [esi+indexFlags], 2
jnz .subnode
movzx ecx, byte [esi+fileNameLength]
lea edi, [esi+fileName]
mov esi, [esp+8]
@@:
call utf8to16
cmp ax, '/'
jz .subnode
call utf16toUpper
push eax
mov ax, [edi]
call utf16toUpper
cmp [esp], ax
pop eax
jc .subnode
jnz .scanloopcont
add edi, 2
loop @b
call utf8to16
cmp ax, '/'
jz .found
test ax, ax
jz .found
.scanloopcont:
pop esi
movzx eax, word [esi+indexAllocatedSize]
add esi, eax
jmp .scanloopint
 
.realloc:
mov edi, eax
mov eax, [esi+indexRecordSize]
shl eax, 1
stdcall kernel_alloc, eax
test eax, eax
jz .err
mov edx, [ebp+NTFS.cur_index_buf]
cmp edx, [ebp+NTFS.secondIndexBuffer]
jc @f
mov edx, [ebp+NTFS.secondIndexBuffer]
@@:
mov [ebp+NTFS.cur_index_buf], eax
add eax, [esi+indexRecordSize]
mov [ebp+NTFS.secondIndexBuffer], eax
mov [ebp+NTFS.cur_index_size], edi
stdcall kernel_free, edx
popad
pop eax
jmp .doit2
 
.notfound:
mov [esp+28], esi
.err:
popad
stc
.ret2:
pop esi
.ret:
ret
 
.subnode:
pop esi
test byte [esi+indexFlags], 1
jz .notfound
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
mov [ebp+NTFS.indexPointer], esi
movzx eax, word [esi+indexAllocatedSize]
mov eax, [esi+eax-8]
mov edx, [ebp+NTFS.cur_size]
push edx
cmp edx, [ebp+NTFS.cur_subnode_size]
jz @f
mul [ebp+NTFS.sectors_per_cluster]
@@:
mov esi, [ebp+NTFS.cur_index_buf]
xchg [ebp+NTFS.secondIndexBuffer], esi
mov [ebp+NTFS.cur_index_buf], esi
mov [ebp+NTFS.cur_buf], esi
mov [ebp+NTFS.cur_attr], 0xA0 ; $INDEX_ALLOCATION
mov [ebp+NTFS.cur_offs], eax
call ntfs_read_attr.newAttribute
pop eax
mov [ebp+NTFS.cur_size], eax
shl eax, 9
cmp [ebp+NTFS.cur_read], eax
jnz .err
cmp dword [esi], 'INDX'
jnz .err
mov ebx, esi
call ntfs_restore_usa
jc .err
add esi, recordNode
jmp .scanloop
 
.found:
mov [esp+8], esi
pop eax
mov [esp+28], eax
mov eax, [eax+fileRecordReference]
mov [ebp+NTFS.cur_iRecord], eax
popad
cmp byte [esi-1], 0
jz .ret2
pop eax
jmp .doit2
 
;----------------------------------------------------------------
ntfs_ReadFile:
call ntfs_lock
call ntfs_find_lfn
jc ntfsNotFound
mov [ebp+NTFS.cur_attr], 0x80 ; $DATA
and [ebp+NTFS.cur_offs], 0
and [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsDenied
xor eax, eax
push eax
cmp dword [ebx+8], 0x200
jnc .eof
mov ecx, [ebx+12]
mov edx, [ebx+16]
mov eax, [ebx+4]
test eax, 0x1FF
jz .alignedstart
push edx
mov edx, [ebx+8]
shrd eax, edx, 9
pop edx
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_size], 1
lea eax, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr.continue
mov eax, [ebx+4]
and eax, 0x1FF
lea esi, [ebp+NTFS.bitmap_buf+eax]
sub eax, [ebp+NTFS.cur_read]
jae .eof
neg eax
push ecx
cmp ecx, eax
jb @f
mov ecx, eax
@@:
mov [esp+4], ecx
mov edi, edx
rep movsb
mov edx, edi
pop ecx
sub ecx, [esp]
jz .retok
cmp [ebp+NTFS.cur_read], 0x200
jnz .eof
.alignedstart:
mov eax, [ebx+4]
push edx
mov edx, [ebx+8]
add eax, 511
adc edx, 0
shrd eax, edx, 9
pop edx
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_buf], edx
mov eax, ecx
shr eax, 9
mov [ebp+NTFS.cur_size], eax
add eax, [ebp+NTFS.cur_offs]
push eax
call ntfs_read_attr.continue
pop [ebp+NTFS.cur_offs]
mov eax, [ebp+NTFS.cur_read]
add [esp], eax
mov eax, ecx
and eax, not 0x1FF
cmp [ebp+NTFS.cur_read], eax
jnz .eof
and ecx, 0x1FF
jz .retok
add edx, [ebp+NTFS.cur_read]
mov [ebp+NTFS.cur_size], 1
lea eax, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr.continue
cmp [ebp+NTFS.cur_read], ecx
jb @f
mov [ebp+NTFS.cur_read], ecx
@@:
xchg ecx, [ebp+NTFS.cur_read]
push ecx
mov edi, edx
lea esi, [ebp+NTFS.bitmap_buf]
add [esp+4], ecx
rep movsb
pop ecx
cmp ecx, [ebp+NTFS.cur_read]
jnz .eof
.retok:
pushd 0
.ret:
call ntfs_unlock
pop eax ebx
ret
 
.eof:
push ERROR_END_OF_FILE
jmp .ret
 
;----------------------------------------------------------------
ntfs_ReadFolder:
call ntfs_lock
mov [ebp+NTFS.cur_iRecord], 5 ; root directory
cmp byte [esi], 0
jz @f
call ntfs_find_lfn
jc ntfsNotFound
@@:
mov [ebp+NTFS.cur_attr], 0x10 ; $STANDARD_INFORMATION
and [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 1
lea eax, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr
jc ntfsFail
mov [ebp+NTFS.cur_attr], 0x90 ; $INDEX_ROOT
.doit:
mov eax, [ebp+NTFS.cur_index_size]
mov [ebp+NTFS.cur_size], eax
mov eax, [ebp+NTFS.cur_index_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr.newAttribute
jc ntfsFail
cmp [ebp+NTFS.cur_read], 0x20
jc ntfsFail
mov esi, [ebp+NTFS.cur_index_buf]
mov eax, [esi+indexRecordSize]
shr eax, 9
cmp [ebp+NTFS.cur_index_size], eax
jc .realloc
mov [ebp+NTFS.cur_subnode_size], eax
add esi, rootNode
mov eax, [esi+nodeRealSize]
add eax, rootNode
cmp [ebp+NTFS.cur_read], eax
jc ntfsFail
mov edi, [ebx+16]
mov ecx, [ebx+12]
pushd [ebx]
pushd [ebx+8] ; read ANSI/UNICODE name
push edi
mov edx, esp
mov ebx, [ebx+4]
; init header
xor eax, eax
mov [edi+8], eax
mov [edi+4], eax
inc eax
mov [edi], eax ; version
add edi, 32
; edi -> BDFE, esi -> current index data, ebx = first wanted block,
; ecx = number of blocks to read
; edx -> parameters block: dd <output>, dd <flags>
cmp [ebp+NTFS.cur_iRecord], 5
jz .skip_specials
; dot and dotdot entries
push esi
xor esi, esi
call .add_special_entry
inc esi
call .add_special_entry
pop esi
.skip_specials:
; at first, dump index root
add esi, [esi+indexOffset]
.dump_root:
test byte [esi+indexFlags], 2
jnz .dump_root_done
call .add_entry
movzx eax, word [esi+indexAllocatedSize]
add esi, eax
jmp .dump_root
 
.realloc:
mov edi, eax
mov eax, [esi+indexRecordSize]
shl eax, 1
stdcall kernel_alloc, eax
test eax, eax
jz ntfsFail
mov edx, [ebp+NTFS.cur_index_buf]
cmp edx, [ebp+NTFS.secondIndexBuffer]
jc @f
mov edx, [ebp+NTFS.secondIndexBuffer]
@@:
mov [ebp+NTFS.cur_index_buf], eax
add eax, [esi+indexRecordSize]
mov [ebp+NTFS.secondIndexBuffer], eax
mov [ebp+NTFS.cur_index_size], edi
stdcall kernel_free, edx
jmp .doit
 
.dump_root_done:
; now dump all subnodes
push ecx edi
lea edi, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], edi
mov ecx, 0x400/4
xor eax, eax
rep stosd
mov [ebp+NTFS.cur_attr], 0xB0 ; $BITMAP
and [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 2
call ntfs_read_attr.newAttribute
pop edi ecx
push 0 ; save offset in $BITMAP attribute
and [ebp+NTFS.cur_offs], 0
.dumploop:
mov [ebp+NTFS.cur_attr], 0xA0
mov eax, [ebp+NTFS.cur_subnode_size]
mov [ebp+NTFS.cur_size], eax
mov esi, [ebp+NTFS.cur_index_buf]
mov [ebp+NTFS.cur_buf], esi
mov eax, [ebp+NTFS.cur_offs]
push eax
imul eax, [ebp+NTFS.cur_subnode_size]
mov [ebp+NTFS.cur_offs], eax
call ntfs_read_attr.newAttribute
pop [ebp+NTFS.cur_offs]
mov eax, [ebp+NTFS.cur_subnode_size]
shl eax, 9
cmp [ebp+NTFS.cur_read], eax
jnz .done
push eax
mov eax, [ebp+NTFS.cur_offs]
and eax, 0x400*8-1
bt dword [ebp+NTFS.bitmap_buf], eax
pop eax
jnc .dump_subnode_done
cmp dword [esi], 'INDX'
jnz .dump_subnode_done
push ebx
mov ebx, esi
call ntfs_restore_usa
pop ebx
jc .dump_subnode_done
add esi, recordNode
add esi, [esi+indexOffset]
.dump_subnode:
test byte [esi+indexFlags], 2
jnz .dump_subnode_done
call .add_entry
movzx eax, word [esi+indexAllocatedSize]
add esi, eax
jmp .dump_subnode
 
.dump_subnode_done:
inc [ebp+NTFS.cur_offs]
test [ebp+NTFS.cur_offs], 0x400*8-1
jnz .dumploop
mov [ebp+NTFS.cur_attr], 0xB0
push ecx edi
lea edi, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], edi
mov ecx, 0x400/4
xor eax, eax
rep stosd
pop edi ecx
pop eax
push [ebp+NTFS.cur_offs]
inc eax
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_size], 2
push eax
call ntfs_read_attr.newAttribute
pop eax
pop [ebp+NTFS.cur_offs]
push eax
jmp .dumploop
 
.done:
pop eax
pop eax
mov ebx, [eax+4]
pop eax
pop eax
test eax, eax
jz .ret
xor eax, eax
dec ecx
js @f
mov al, ERROR_END_OF_FILE
@@:
push eax
call ntfs_unlock
pop eax
ret
 
.add_special_entry:
mov eax, [edx]
inc dword [eax+8] ; new file found
dec ebx
jns .ret
dec ecx
js .ret
inc dword [eax+4] ; new file block copied
mov eax, [edx+4]
mov [edi+4], eax
mov eax, 0x10
stosd
scasd
push ebx ecx edx
mov eax, dword [ebp+NTFS.bitmap_buf]
mov edx, dword [ebp+NTFS.bitmap_buf+4]
call ntfs_datetime_to_bdfe
mov eax, dword [ebp+NTFS.bitmap_buf+0x18]
mov edx, dword [ebp+NTFS.bitmap_buf+0x1C]
call ntfs_datetime_to_bdfe
mov eax, dword [ebp+NTFS.bitmap_buf+8]
mov edx, dword [ebp+NTFS.bitmap_buf+0xC]
call ntfs_datetime_to_bdfe
pop edx ecx ebx
xor eax, eax
stosd
stosd
mov al, '.'
push edi ecx
lea ecx, [esi+1]
cmp dword[edi-36], 2
jz .utf16sp
rep stosb
mov byte [edi], 0
pop ecx edi
cmp dword[edi-36], 3
jz @f
add edi, 264
ret
 
.utf16sp:
rep stosw
mov word [edi], 0
pop ecx edi
@@:
add edi, 520
.ret:
ret
 
.add_entry:
; do not return DOS 8.3 names
cmp byte [esi+namespace], 2
jz .ret
; do not return system files
cmp dword[esi+fileRecordReference], 16
jb .ret
cmp byte [esi+fileNameLength], 0
jz .ret
mov eax, [edx]
inc dword [eax+8] ; new file found
dec ebx
jns .ret
dec ecx
js .ret
inc dword [eax+4] ; new file block copied
mov eax, [edx+4] ; flags
call ntfs_direntry_to_bdfe
push ecx esi edi
movzx ecx, byte [esi+fileNameLength]
add esi, fileName
cmp dword[edi-36], 2
jz .utf16
cmp dword[edi-36], 3
jz .utf8
@@:
lodsw
call uni2ansi_char
stosb
loop @b
mov byte [edi], 0
pop edi esi ecx
add edi, 264
ret
 
.utf8:
push ecx
mov cx, 519
@@:
lodsw
call UTF16to8
js @f
dec dword[esp]
jnz @b
@@:
mov byte [edi], 0
pop edi
@@:
pop edi esi ecx
add edi, 520
ret
 
.utf16:
rep movsw
mov word [edi], 0
jmp @b
 
ntfs_direntry_to_bdfe:
mov [edi+4], eax ; ANSI/UNICODE name
mov eax, [esi+fileFlags]
test eax, 0x10000000
jz @f
and eax, not 0x10000000
or al, 0x10
@@:
stosd
scasd
push ebx ecx edx
mov eax, [esi+fileCreated]
mov edx, [esi+fileCreated+4]
call ntfs_datetime_to_bdfe
mov eax, [esi+fileAccessed]
mov edx, [esi+fileAccessed+4]
call ntfs_datetime_to_bdfe
mov eax, [esi+fileModified]
mov edx, [esi+fileModified+4]
call ntfs_datetime_to_bdfe
pop edx ecx ebx
mov eax, [esi+fileRealSize]
stosd
mov eax, [esi+fileRealSize+4]
stosd
ret
 
ntfs_datetime_to_bdfe:
; in: edx:eax = seconds since 01.01.1601 x10000000
; edi -> data block
; out: edi = edi+8
sub eax, 3365781504
sbb edx, 29389701
mov ecx, 10000000
cmp edx, ecx
jc @f
xor edx, edx
@@:
div ecx
jmp fsTime2bdfe
 
;----------------------------------------------------------------
ntfs_GetFileInfo:
mov edi, [ebx+16]
cmp byte [esi], 0
jz .volume
call ntfs_lock
call ntfs_find_lfn
jnc .found
test eax, eax
jz ntfsFail
jmp ntfsNotFound
 
.found:
mov esi, eax
xor eax, eax
call ntfs_direntry_to_bdfe
.end:
call ntfs_unlock
xor eax, eax
@@:
ret
 
.volume:
mov eax, dword [ebp+NTFS.Length]
mov edx, dword [ebp+NTFS.Length+4]
shld edx, eax, 9
shl eax, 9
mov [edi+36], edx
mov [edi+32], eax
mov eax, [ebx+8]
mov byte [edi], 8
mov [edi+4], eax
test eax, eax
jz @b
call ntfs_lock
add edi, 40
mov [ebp+NTFS.cur_buf], edi
mov [ebp+NTFS.cur_iRecord], 3
mov [ebp+NTFS.cur_attr], 0x60
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 1
call ntfs_read_attr
jc ntfsFail
mov ecx, [ebp+NTFS.cur_read]
mov [edi+ecx], ax
cmp byte [ebx+8], 2
jz .end
shr ecx, 1
jz .end
mov esi, edi
cmp byte [ebx+8], 3
jnz @f
shl ecx, 1
call UTF16to8_string
mov byte [edi], 0
jmp .end
 
@@:
lodsw
call uni2ansi_char
stosb
loop @b
mov byte [edi], 0
jmp .end
 
;----------------------------------------------------------------
ntfs_CreateFolder:
mov [ebp+NTFS.bFolder], 1
jmp @f
 
ntfs_CreateFile:
mov [ebp+NTFS.bFolder], 0
@@: ; 1. Search file
call ntfs_lock
call ntfs_find_lfn
jc .notFound
; found, rewrite
cmp [ebp+NTFS.cur_iRecord], 16
jc ntfsDenied
cmp [ebp+NTFS.bFolder], 1
jz .folder
test byte [eax+fileFlags], 1
jnz ntfsDenied
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
; edit directory node
mov edi, [ebp+NTFS.cur_index_buf]
cmp dword [edi], 'INDX'
jz @f
mov esi, [ebp+NTFS.frs_buffer]
mov ecx, [esi+recordRealSize]
shr ecx, 2
rep movsd
mov esi, [ebp+NTFS.attr_offs]
mov cl, [esi+attributeOffset]
sub esi, [ebp+NTFS.frs_buffer]
add eax, ecx
add eax, esi
@@:
mov edi, eax
mov eax, [ebx+12]
mov [edi+fileRealSize], eax
mov dword [edi+fileRealSize+4], 0
push ebx eax
call ntfsGetTime
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov [edi+recordModified], eax
mov [edi+recordModified+4], edx
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
pop edx ebx
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsFail
mov esi, edi
mov edi, [ebp+NTFS.frs_buffer]
cmp word [edi+baseRecordReuse], 0
jnz ntfsUnsupported ; auxiliary record
mov al, [edi+attributeOffset]
add edi, eax
mov al, [edi+attributeOffset]
add edi, eax
mov ecx, 6
add esi, fileModified
add edi, 8
rep movsd
mov eax, edx
xor edx, edx
mov ecx, [ebp+NTFS.attr_offs]
cmp word [ecx+attributeFlags], 0
jnz ntfsUnsupported
push ebx
cmp byte [ecx+nonResidentFlag], 0
jz @f
cmp [ecx+attributeRealSize+4], edx
jnz @f
cmp [ecx+attributeRealSize], eax
jz ntfs_WriteFile.writeNode
@@:
jmp ntfs_WriteFile.resizeAttribute
 
.folder:
bt dword [eax+fileFlags], 28
jnc ntfsDenied
push 0
jmp ntfsOut
 
.notFound: ; create
test eax, eax
jz ntfsFail
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
; 2. Prepare directory record
mov edi, esi
mov edx, eax
xor ecx, ecx
@@: ; count characters
call utf8to16
cmp ax, '/'
jz ntfsNotFound ; path folder not found
inc ecx
test ax, ax
jnz @b
dec ecx
push ecx ; name length in chars
push edi
shl ecx, 1
add ecx, fileName+7
and ecx, not 7
mov edi, [ebp+NTFS.cur_index_buf]
mov eax, [ebx+12]
mov [ebp+NTFS.fileRealSize], eax
mov eax, [ebx+16]
mov [ebp+NTFS.fileDataBuffer], eax
push ecx ; index length
mov eax, edx
mov edx, ecx
cmp dword [edi], 'INDX'
jz .indexRecord
mov esi, [ebp+NTFS.frs_buffer] ; indexRoot
mov ecx, [esi+recordRealSize]
add edx, ecx
cmp [esi+recordAllocatedSize], edx
jc .growTree
mov [esi+recordRealSize], edx
shr ecx, 2
rep movsd
mov edi, [ebp+NTFS.indexRoot]
sub edi, [ebp+NTFS.frs_buffer]
add edi, [ebp+NTFS.cur_index_buf]
mov esi, [esp]
add [edi+sizeWithHeader], esi
add [edi+sizeWithoutHeader], esi
mov cl, [edi+attributeOffset]
add edi, ecx
add [edi+rootNode+nodeRealSize], esi
add [edi+rootNode+nodeAllocatedSize], esi
sub eax, [ebp+NTFS.cur_index_buf]
add eax, edi
mov edi, [ebp+NTFS.cur_index_buf]
jmp .common
 
.growTree: ; create indexRecord
mov edi, [ebp+NTFS.cur_index_buf]
mov ecx, 10
xor eax, eax
rep stosd
mov esi, [ebp+NTFS.indexRoot]
mov al, [esi+attributeOffset]
add esi, eax
rdtsc
stosw
mov eax, [esi+indexRecordSize]
cmp eax, [ebp+NTFS.frs_size]
jc .errorPop3
shr eax, 9
inc eax
mov edi, [ebp+NTFS.cur_index_buf]
mov dword[edi], 'INDX'
mov byte [edi+updateSequenceOffset], 28h
mov [edi+updateSequenceSize], al
add edi, recordNode
shl eax, 1
add eax, 28h-recordNode+7
and eax, not 7
mov [edi+indexOffset], eax
mov ecx, [esi+indexRecordSize]
sub ecx, recordNode
mov [edi+nodeAllocatedSize], ecx
add esi, rootNode
push esi
mov ecx, [esi+nodeRealSize]
sub ecx, [esi+indexOffset]
add eax, ecx
mov [edi+nodeRealSize], eax
mov eax, [esi+nonLeafFlag]
mov [edi+nonLeafFlag], eax
shr ecx, 2
add esi, [esi+indexOffset]
add edi, [edi+indexOffset]
rep movsd ; copy root indexes
; clear root node
mov cl, 10
mov edi, [esp]
xor eax, eax
rep stosd
pop edi
mov byte [edi+indexOffset], 16
mov byte [edi+nodeRealSize], 28h
mov byte [edi+nodeAllocatedSize], 28h
mov byte [edi+nonLeafFlag], 1
mov byte [edi+16+indexAllocatedSize], 18h
mov byte [edi+16+indexFlags], 3
mov esi, [ebp+NTFS.indexRoot]
add edi, 28h
mov eax, edi
sub eax, esi
mov word [esi+sizeWithoutHeader], 38h
xchg [esi+sizeWithHeader], eax
add esi, eax
mov [ebp+NTFS.attr_offs], edi
cmp byte [esi], 0xA0
jnz @f
cmp dword [esi+attributeAllocatedSize], 0
jz @f
mov eax, [ebp+NTFS.frs_buffer]
mov ecx, eax
add ecx, [eax+recordRealSize]
sub ecx, esi
shr ecx, 2
rep movsd
sub edi, eax
mov [eax+recordRealSize], edi
call .ntfsNodeAlloc
jc ntfsErrorPop3
mov eax, [ebp+NTFS.newRecord]
mov edi, [ebp+NTFS.cur_index_buf]
mov [edi+recordVCN], eax
mov edi, [ebp+NTFS.attr_offs]
mov [edi-8], eax
jmp .refresh
 
@@:
mov cl, 32
xor eax, eax
rep stosd
mov eax, [ebp+NTFS.cur_subnode_size]
cmp eax, [ebp+NTFS.cur_size]
jnz @f
cmp [ebp+NTFS.sectors_per_cluster], 1
jz @f
mov al, 1
@@:
mov [ebp+NTFS.fileDataSize], eax
mov edi, [ebp+NTFS.BitmapStart]
call ntfsSpaceAlloc
movi eax, ERROR_DISK_FULL
jc ntfsErrorPop3
; create $IndexAllocation
mov edi, [ebp+NTFS.attr_offs]
mov byte [edi+attributeType], 0xA0
mov byte [edi+nonResidentFlag], 1
mov byte [edi+nameLength], 4
mov byte [edi+nameOffset], 40h
mov byte [edi+dataRunsOffset], 48h
mov byte [edi+sizeWithHeader], 50h
mov eax, [ebp+NTFS.fileDataSize]
dec eax
mov [edi+lastVCN], eax
inc eax
mul [ebp+NTFS.sectors_per_cluster]
shl eax, 9
mov [edi+attributeAllocatedSize], eax
mov [edi+attributeRealSize], eax
mov [edi+initialDataSize], eax
mov dword[edi+40h], 490024h ; unicode $I30
mov dword[edi+40h+4], 300033h
push edi
mov esi, edi
add edi, 48h
call createMcbEntry
mov esi, [ebp+NTFS.frs_buffer]
pop edi
mov al, [esi+newAttributeID]
mov [edi+attributeID], al
add edi, 50h
inc eax
; create $Bitmap
mov [edi+attributeID], al
inc eax
mov [esi+newAttributeID], al
mov byte [edi+attributeType], 0xB0
mov byte [edi+nameLength], 4
mov byte [edi+nameOffset], 18h
mov byte [edi+attributeOffset], 20h
mov byte [edi+sizeWithoutHeader], 8
mov byte [edi+sizeWithHeader], 28h
mov dword[edi+18h], 490024h ; unicode $I30
mov dword[edi+18h+4], 300033h
mov byte [edi+20h], 1
mov dword[edi+28h], -1
add edi, 30h
sub edi, esi
mov [esi+recordRealSize], edi
mov eax, [ebp+NTFS.fileDataStart]
mul [ebp+NTFS.sectors_per_cluster]
mov edx, eax
jmp @f
 
.refresh:
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr.continue
movi eax, ERROR_FS_FAIL
jc ntfsErrorPop3
mov edx, [ebp+NTFS.LastRead]
@@:
mov ebx, [ebp+NTFS.cur_index_buf]
call writeRecord
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.rootLastRead]
call writeRecord
mov esi, [esp+4]
call ntfs_find_lfn.doit2
test eax, eax
jz .errorPop3
mov edi, [ebp+NTFS.cur_index_buf]
mov edx, [esp]
.indexRecord:
add edi, recordNode
add edx, [edi+nodeRealSize]
cmp [edi+nodeAllocatedSize], edx
jc .arborizeTree
mov [edi+nodeRealSize], edx
jmp .common
 
.errorPop3:
add esp, 12
jmp ntfsUnsupported
 
.ntfsNodeAlloc:
; in: [ebp+NTFS.attr_offs] -> $IndexAllocation
; out:
; [ebp+NTFS.newRecord] = node VCN
; [ebp+NTFS.cur_offs]
; CF=1 -> eax = error code
mov esi, [ebp+NTFS.attr_offs]
add esi, [esi+sizeWithHeader]
cmp byte [esi], 0xB0
jnz .ret
movzx ecx, word [esi+sizeWithoutHeader]
shr ecx, 2
movzx edi, byte [esi+attributeOffset]
add edi, esi
mov edx, edi
or eax, -1
repz scasd
jnz @f
cmp [edi], eax
jnz .ret
; extend folder $Bitmap
add word [esi+sizeWithHeader], 8
add word [esi+sizeWithoutHeader], 8
mov esi, [ebp+NTFS.frs_buffer]
mov eax, [esi+recordRealSize]
add eax, 8
cmp [esi+recordAllocatedSize], eax
jc .ret
mov [esi+recordRealSize], eax
xor eax, eax
stosd
mov [edi], eax
mov [edi+8], eax
dec eax
mov [edi+4], eax
@@:
sub edi, 4
mov eax, [edi]
not eax
bsf eax, eax
bts [edi], eax
sub edi, edx
shl edi, 3
add eax, edi
mul [ebp+NTFS.cur_subnode_size]
mov [ebp+NTFS.newRecord], eax
mov ecx, [ebp+NTFS.cur_size]
cmp ecx, [ebp+NTFS.cur_subnode_size]
jz @f
mul [ebp+NTFS.sectors_per_cluster]
@@:
mov [ebp+NTFS.cur_offs], eax
add eax, ecx
shl eax, 9
mov esi, [ebp+NTFS.attr_offs]
cmp [esi+attributeAllocatedSize], eax
jnc @f
xor edx, edx
jmp resizeAttribute
 
.ret:
movi eax, ERROR_UNSUPPORTED_FS
stc
@@:
ret
 
.arborizeTree: ; find median index
mov ecx, [edi+nodeRealSize]
sub ecx, [edi+indexOffset]
shr ecx, 1
add edi, [edi+indexOffset]
xor eax, eax
@@:
add edi, eax
mov ax, [edi+indexAllocatedSize]
sub ecx, eax
jnc @b
add eax, 8
mov esi, [ebp+NTFS.secondIndexBuffer]
cmp dword [esi], 'INDX'
jz @f
; move index to the root node
mov esi, [ebp+NTFS.frs_buffer]
mov ecx, eax
add ecx, 8
add ecx, [esi+recordRealSize]
cmp [esi+recordAllocatedSize], ecx
jc .growTree
push edi eax
call .ntfsNodeAlloc
jc ntfsErrorPop5
pop eax
mov edi, [ebp+NTFS.indexRoot]
add [ebp+NTFS.attr_offs], eax
add [edi+sizeWithHeader], eax
add [edi+sizeWithoutHeader], eax
movzx ecx, byte [edi+attributeOffset]
add ecx, edi
add [ecx+rootNode+nodeRealSize], eax
add [ecx+rootNode+nodeAllocatedSize], eax
add ecx, [ebp+NTFS.indexPointer]
sub ecx, [ebp+NTFS.secondIndexBuffer]
mov esi, [ebp+NTFS.frs_buffer]
add [esi+recordRealSize], eax
add esi, [esi+recordRealSize]
mov edi, esi
sub esi, eax
neg ecx
add ecx, esi
shr ecx, 2
sub esi, 4
sub edi, 4
std
rep movsd ; make space
mov [edi], ecx
mov edi, esi
add edi, 4
mov esi, [esp]
add word [esi+indexAllocatedSize], 8
mov byte [esi+indexFlags], 1
mov ecx, eax
sub ecx, 8
shr ecx, 2
cld
rep movsd ; insert index
mov eax, [ebp+NTFS.newRecord]
stosd
jmp .splitNode
 
.growBranch: ; move node and replace it with empty one
mov esi, [ebp+NTFS.cur_index_buf]
mov edi, [ebp+NTFS.secondIndexBuffer]
mov eax, [esi+recordVCN]
mov [edi+recordVCN], eax
add edi, recordNode
mov eax, [edi+indexOffset]
add eax, 18h
mov [edi+nodeRealSize], eax
add edi, [edi+indexOffset]
mov ecx, 6
xor eax, eax
mov [ebp+NTFS.indexPointer], edi
push edi
rep stosd
pop edi
mov eax, [ebp+NTFS.newRecord]
mov byte [edi+indexAllocatedSize], 18h
mov byte [edi+indexFlags], 3
mov [edi+16], eax
mov [esi+recordVCN], eax
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
push [ebp+NTFS.cur_size]
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr.continue
pop [ebp+NTFS.cur_size]
movi eax, ERROR_FS_FAIL
jc ntfsErrorPop5
pop eax edi
@@: ; move index to the branch node
push edi eax
call .ntfsNodeAlloc
jc ntfsErrorPop5
mov eax, [esp]
mov esi, [ebp+NTFS.secondIndexBuffer]
add esi, recordNode
mov ecx, [esi+nodeRealSize]
add eax, ecx
cmp [esi+nodeAllocatedSize], eax
jc .growBranch
mov [esi+nodeRealSize], eax
lea edi, [esi+eax-4]
add esi, ecx
mov ecx, esi
sub ecx, [ebp+NTFS.indexPointer]
shr ecx, 2
sub esi, 4
std
rep movsd ; make space
mov [edi], ecx
pop ecx
sub ecx, 8
shr ecx, 2
mov edi, esi
add edi, 4
mov esi, [esp]
add word [esi+indexAllocatedSize], 8
mov byte [esi+indexFlags], 1
cld
rep movsd ; insert index
mov eax, [ebp+NTFS.newRecord]
stosd
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov edx, [ebp+NTFS.nodeLastRead]
push esi
call writeRecord
pop esi
.splitNode:
mov edi, [ebp+NTFS.cur_index_buf]
mov eax, edi
add eax, recordNode
add eax, [edi+recordNode+nodeRealSize]
sub eax, esi
push eax
mov ecx, [edi+recordNode+indexOffset]
add eax, ecx
add ecx, recordNode
shr ecx, 2
push esi
mov esi, edi
mov edi, [ebp+NTFS.secondIndexBuffer]
rep movsd
pop esi
pop ecx
shr ecx, 2
rep movsd
mov edi, [ebp+NTFS.secondIndexBuffer]
mov [edi+recordNode+nodeRealSize], eax
pop edi
mov cl, 4
xor eax, eax
mov esi, edi
rep stosd
mov byte [esi+indexAllocatedSize], 16
mov byte [esi+indexFlags], 2
mov esi, [ebp+NTFS.cur_index_buf]
mov eax, [ebp+NTFS.newRecord]
mov [esi+recordVCN], eax
add esi, recordNode
sub edi, esi
mov [esi+nodeRealSize], edi
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov edx, [ebp+NTFS.LastRead]
call writeRecord
jmp .refresh
 
.common:
add edi, edx
sub edi, 4
mov esi, edi
sub esi, [esp]
mov ecx, esi
sub ecx, eax ; eax = pointer in the record
shr ecx, 2
inc ecx
std
rep movsd ; move forward, make space
mov ecx, [esp]
shr ecx, 2
xor eax, eax
rep stosd
cld
add edi, 4
call ntfsGetTime
mov [edi+fileCreated], eax
mov [edi+fileCreated+4], edx
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov [edi+recordModified], eax
mov [edi+recordModified+4], edx
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
pop ecx
pop esi
mov [edi+indexAllocatedSize], cx ; fill index with data
mov eax, [esp]
shl eax, 1
add eax, 42h
mov [edi+indexRawSize], ax
mov eax, [ebp+NTFS.cur_iRecord]
mov [edi+directoryRecordReference], eax
mov eax, [ebp+NTFS.frs_buffer]
mov eax, [eax+reuseCounter]
mov [edi+directoryReferenceReuse], ax
mov eax, [ebp+NTFS.frs_size]
shr eax, 8
add ecx, 30h+48h+8+18h+8
add ecx, eax
mov eax, [ebp+NTFS.fileRealSize]
add ecx, eax
mov [edi+fileRealSize], eax
cmp [ebp+NTFS.frs_size], ecx
jc @f
xor eax, eax
@@:
mov ecx, [ebp+NTFS.sectors_per_cluster]
shl ecx, 9
add eax, ecx
dec eax
xor edx, edx
div ecx
mov [ebp+NTFS.fileDataSize], eax
mul ecx
mov [edi+fileAllocatedSize], eax
pop ecx
mov [ebp+NTFS.indexPointer], edi
mov [edi+fileNameLength], cl
add edi, fileName
@@: ; record filename
call utf8to16
stosw
loop @b
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
cmp [ebp+NTFS.bFolder], 0
jz @f
mov edi, [ebp+NTFS.indexPointer]
bts dword [edi+fileFlags], 28
jmp .mftBitmap
 
@@: ; 3. File data
cmp [ebp+NTFS.fileDataSize], 0
jz .mftBitmap
mov edi, [ebp+NTFS.BitmapStart]
call ntfsSpaceAlloc
jc ntfsDiskFull
mov eax, [ebp+NTFS.fileDataStart]
mul [ebp+NTFS.sectors_per_cluster]
mov ecx, [ebp+NTFS.fileRealSize]
add ecx, 511
shr ecx, 9
mov ebx, [ebp+NTFS.fileDataBuffer]
call fs_write64_app
test eax, eax
jnz ntfsDevice
; 4. MFT record
.mftBitmap: ; search for free record
mov edi, [ebp+NTFS.mftBitmapBuffer]
mov ecx, [ebp+NTFS.mftBitmapSize]
mov al, -1
add edi, 3
sub ecx, 3
repz scasb
dec edi
movzx eax, byte [edi]
not al
bsf ecx, eax
jz .extendBitmapMFT ; no free records
bts [edi], ecx
; get record location
sub edi, [ebp+NTFS.mftBitmapBuffer]
shl edi, 3
add edi, ecx
mov [ebp+NTFS.newRecord], edi
mov eax, [ebp+NTFS.frs_size]
shr eax, 9
mul edi
mov [ebp+NTFS.cur_iRecord], 0
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], eax
push eax
mov [ebp+NTFS.cur_size], 0
mov eax, [ebp+NTFS.frs_buffer]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr
pop eax
jc ntfsFail
cmp eax, [ebp+NTFS.mftSize]
jnc .extendMFT
jmp .mftRecord
 
.extendBitmapMFT:
mov eax, [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.cur_offs], eax
shl eax, 9
cmp [ebp+NTFS.mftBitmapSize], eax
jnc ntfsUnsupported
mov [ebp+NTFS.cur_iRecord], 0
mov [ebp+NTFS.cur_attr], 0xB0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsFail
mov eax, [ebp+NTFS.mft_cluster]
mul [ebp+NTFS.sectors_per_cluster]
cmp eax, [ebp+NTFS.LastRead]
jnz ntfsUnsupported ; auxiliary record
mov edi, [ebp+NTFS.mftBitmapBuffer]
mov ecx, [ebp+NTFS.mftBitmapSize]
add edi, ecx
mov eax, ecx
mov edx, [ebp+NTFS.attr_offs]
add ecx, 8
mov [edx+attributeRealSize], ecx
mov [edx+initialDataSize], ecx
shl eax, 3
mov [ebp+NTFS.newRecord], eax
mov dword [edi], 1
mov dword [edi+4], 0
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
call ntfs_read_attr.newAttribute
jc ntfsFail
mov [ebp+NTFS.mftBitmapSize], ecx
.extendMFT:
mov eax, [ebp+NTFS.mft_cluster]
mul [ebp+NTFS.sectors_per_cluster]
cmp eax, [ebp+NTFS.LastRead]
jnz ntfsUnsupported ; auxiliary record
mov ecx, [ebp+NTFS.attr_offs]
mov eax, [ecx+attributeRealSize]
mov edx, [ecx+attributeRealSize+4]
xor ax, ax
add eax, 10000h
adc edx, 0
push [ebp+NTFS.fileDataStart]
push [ebp+NTFS.fileDataSize]
call resizeAttribute
jc ntfsErrorPop2
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.LastRead]
call writeRecord ; $MFT
mov eax, [ebp+NTFS.mftmirr_cluster]
mul [ebp+NTFS.sectors_per_cluster]
mov ecx, [ebp+NTFS.frs_size]
shr ecx, 9
call fs_write64_sys ; $MFTMirr
; update $MFT retrieval information
mov edi, [ebp+NTFS.mft_retrieval_end]
mov eax, [edi-4]
add eax, [edi-8]
mov edx, [ebp+NTFS.fileDataSize]
cmp eax, [ebp+NTFS.fileDataStart]
jnz .newFragment
add [edi-8], edx
jmp @f
.newFragment:
lea eax, [ebp+NTFS.attrlist_buf]
cmp eax, edi
jz @f
mov [edi], edx
mov eax, [ebp+NTFS.fileDataStart]
mov [edi+4], eax
add [ebp+NTFS.mft_retrieval_end], 8
@@:
mov eax, [ebp+NTFS.fileDataSize]
mul [ebp+NTFS.sectors_per_cluster]
add [ebp+NTFS.mftSize], eax
call ntfsSpaceClean
pop [ebp+NTFS.fileDataSize]
pop [ebp+NTFS.fileDataStart]
.mftRecord:
mov ecx, [ebp+NTFS.frs_size]
shr ecx, 2
mov edi, [ebp+NTFS.frs_buffer]
xor eax, eax
rep stosd
mov esi, [ebp+NTFS.indexPointer]
mov eax, [ebp+NTFS.newRecord]
mov [esi+fileRecordReference], eax
rdtsc
mov [esi+fileReferenceReuse], ax
mov edi, [ebp+NTFS.frs_buffer]
; record header
mov [edi+reuseCounter], ax
mov [edi+2ah], ax
mov eax, [ebp+NTFS.frs_size]
mov [edi+recordAllocatedSize], eax
shr eax, 9
inc eax
mov [edi+updateSequenceSize], al
shl eax, 1
add eax, 2ah+7
and eax, not 7
mov dword[edi], 'FILE'
mov byte [edi+updateSequenceOffset], 2ah
mov byte [edi+hardLinkCounter], 1
mov byte [edi+newAttributeID], 3
mov [edi+attributeOffset], al
add edi, eax
; $StandardInformation
mov byte [edi+attributeType], 10h
mov byte [edi+sizeWithHeader], 48h
mov byte [edi+sizeWithoutHeader], 30h
mov byte [edi+attributeOffset], 18h
mov cl, 8
add esi, fileCreated
add edi, 18h
rep movsd
add edi, 16
mov esi, [ebp+NTFS.indexPointer]
; $FileName
mov byte [edi+attributeType], 30h
mov byte [edi+attributeID], 1
mov byte [edi+attributeOffset], 18h
mov byte [edi+indexedFlag], 1
mov cx, [esi+indexRawSize]
mov [edi+sizeWithoutHeader], ecx
mov cx, [esi+indexAllocatedSize]
add ecx, 8
mov [edi+sizeWithHeader], ecx
add edi, 18h
add esi, 16
sub ecx, 18h
shr ecx, 2
rep movsd
mov byte [edi+sizeWithHeader], 50h
mov byte [edi+attributeID], 2
cmp [ebp+NTFS.bFolder], 1
jz .indexRoot
; $Data
mov byte [edi+attributeType], 80h
mov eax, [ebp+NTFS.fileDataSize]
test eax, eax
jz .resident
mov esi, [ebp+NTFS.indexPointer]
dec eax
mov [edi+lastVCN], eax
mov byte [edi+nonResidentFlag], 1
mov byte [edi+dataRunsOffset], 40h
mov eax, [esi+fileAllocatedSize]
mov [edi+attributeAllocatedSize], eax
mov eax, [esi+fileRealSize]
mov [edi+attributeRealSize], eax
mov [edi+initialDataSize], eax
push edi
mov esi, edi
add edi, 40h
call createMcbEntry
inc edi
jmp @f
 
.resident:
mov ecx, [ebp+NTFS.fileRealSize]
mov [edi+sizeWithoutHeader], ecx
mov byte [edi+attributeOffset], 18h
push edi
mov esi, [ebp+NTFS.fileDataBuffer]
add edi, 18h
rep movsb
@@:
mov eax, edi
pop edi
sub eax, edi
add eax, 7
and eax, not 7
mov [edi+sizeWithHeader], eax
add edi, eax
mov al, 1
jmp .end
 
.indexRoot:
mov byte [edi+attributeType], 90h
mov byte [edi+nameLength], 4
mov byte [edi+nameOffset], 18h
mov byte [edi+sizeWithoutHeader], 30h
mov byte [edi+attributeOffset], 20h
mov dword[edi+18h], 490024h ; unicode $I30
mov dword[edi+18h+4], 300033h
mov byte [edi+20h+indexedAttributesType], 30h
mov byte [edi+20h+collationRule], 1
mov eax, [ebp+NTFS.sectors_per_cluster]
mov dl, 1
shl eax, 8
@@:
shl eax, 1
shl edx, 1
cmp eax, [ebp+NTFS.frs_size]
jc @b
shr edx, 1
mov [edi+20h+indexRecordSize], eax
mov [edi+20h+indexRecordSizeClus], dl
mov byte [edi+30h+indexOffset], 16
mov byte [edi+30h+nodeRealSize], 32
mov byte [edi+30h+nodeAllocatedSize], 32
mov byte [edi+40h+indexAllocatedSize], 16
mov byte [edi+40h+indexFlags], 2
add edi, 50h
mov al, 3
.end:
mov ebx, [ebp+NTFS.frs_buffer]
mov dword [edi], -1
mov dword [edi+4], 0
add edi, 8
sub edi, ebx
mov [ebx+recordFlags], al
mov [ebx+recordRealSize], edi
mov edx, [ebp+NTFS.LastRead]
call writeRecord
; write MFT bitmap
mov eax, [ebp+NTFS.newRecord]
shr eax, 3+9
mov ebx, eax
shl ebx, 9
add eax, [ebp+NTFS.mftBitmapLocation]
add ebx, [ebp+NTFS.mftBitmapBuffer]
mov ecx, 1
xor edx, edx
call fs_write64_sys
; 5. Write directory node
mov ebx, [ebp+NTFS.cur_index_buf]
mov edx, [ebp+NTFS.nodeLastRead]
call writeRecord
mov ebx, [ebp+NTFS.fileRealSize]
ntfsDone:
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ntfs_unlock
xor eax, eax
ret
 
writeRecord:
; make updateSequence and write to disk
; in:
; ebx -> record
; edx = partition sector
mov esi, ebx
mov edi, ebx
movzx ecx, word [esi+updateSequenceOffset]
add edi, ecx
mov ax, [edi]
inc ax
stosw
mov cx, [esi+updateSequenceSize]
dec ecx
push ecx
@@:
add esi, 510
movsw
mov [esi-2], ax
loop @b
mov eax, edx
xor edx, edx
pop ecx
jmp fs_write64_sys
 
createMcbEntry:
; in:
; [ebp+NTFS.fileDataStart] = position value
; [ebp+NTFS.fileDataSize] = size value
; edi -> destination
; esi -> attribute header
mov eax, [ebp+NTFS.fileDataStart]
xor edx, edx
shl eax, 1
jnc @f
not eax
@@:
inc edx
shr eax, 8
jnz @b
mov eax, [ebp+NTFS.fileDataSize]
shl eax, 1
xor ecx, ecx
@@:
inc ecx
shr eax, 8
jnz @b
lea eax, [edi+edx+1]
add eax, ecx
sub eax, esi
sub eax, [esi+sizeWithHeader]
jc @f
add word [esi+sizeWithHeader], 8 ; extend attribute
mov esi, [ebp+NTFS.frs_buffer]
mov eax, [esi+recordRealSize]
add eax, 8
cmp [esi+recordAllocatedSize], eax
jc .end ; no space in the record
mov [esi+recordRealSize], eax
push ecx edi
add esi, eax
mov ecx, esi
sub ecx, edi
sub ecx, 8
shr ecx, 2
mov edi, esi
sub edi, 4
sub esi, 12
std
rep movsd
cld
pop edi ecx
@@:
mov eax, edx
shl eax, 4
add eax, ecx
stosb
lea esi, [ebp+NTFS.fileDataSize]
rep movsb
lea esi, [ebp+NTFS.fileDataStart]
mov ecx, edx
rep movsb
mov [edi], cl
.end:
ret
 
resizeAttribute:
; in:
; [ebp+NTFS.frs_buffer] -> file record
; [ebp+NTFS.attr_offs] -> attribute
; edx:eax = new size
; out:
; [ebp+NTFS.fileDataSize] = clusters added (positive)
; [ebp+NTFS.fileDataStart] = added block
; CF=1 -> eax = error code
mov esi, [ebp+NTFS.attr_offs]
mov dword [ebp+NTFS.attr_size], eax
mov dword [ebp+NTFS.attr_size+4], edx
cmp byte [esi+nonResidentFlag], 0
jz .resident
mov ecx, [ebp+NTFS.sectors_per_cluster]
shl ecx, 9
mov [esi+attributeRealSize], eax
mov [esi+attributeRealSize+4], edx
mov [esi+initialDataSize], eax
mov [esi+initialDataSize+4], edx
sub eax, 1
sbb edx, 0
jc .makeResident
div ecx
mov edi, eax
inc eax
mul ecx
mov [esi+attributeAllocatedSize], eax
mov [esi+attributeAllocatedSize+4], edx
mov ecx, [esi+lastVCN]
mov [esi+lastVCN], edi
movzx eax, byte [esi+dataRunsOffset]
sub edi, ecx
mov [ebp+NTFS.fileDataSize], edi
jz .done
jc .shrinkAttribute
; extend attribute
xor edi, edi
add esi, eax
push edi edi edi edi
@@:
mov edx, eax
mov eax, esi
add edi, [esp+8]
call ntfs_decode_mcb_entry
jc @b
mov [esp+4], edx
mov [esp+12], edi
add edi, [esp]
push edi
shr edi, 5
shl edi, 2
push eax
cmp edi, [ebp+NTFS.BitmapStart]
jnc @f
cmp [ebp+NTFS.cur_iRecord], 0
jz @f
mov edi, [ebp+NTFS.BitmapStart]
@@:
call ntfsSpaceAlloc
jc .err1
mov eax, [ebp+NTFS.fileDataStart]
pop edi
pop edx
cmp edx, eax
jnz .newEntry
pop edx
pop edi
pop [ebp+NTFS.fileDataStart]
mov [esp], eax
push [ebp+NTFS.fileDataSize]
add [ebp+NTFS.fileDataSize], edx
jmp @f
 
.newEntry:
add esp, 12
pop edx
push eax
push [ebp+NTFS.fileDataSize]
sub eax, edx
mov [ebp+NTFS.fileDataStart], eax
@@:
mov esi, [ebp+NTFS.attr_offs]
call createMcbEntry
pop [ebp+NTFS.fileDataSize]
pop [ebp+NTFS.fileDataStart]
movi eax, ERROR_UNSUPPORTED_FS
.done:
ret
 
.err1:
add esp, 24
stc
.err2:
movi eax, ERROR_DISK_FULL
ret
 
.err3:
movi eax, ERROR_FS_FAIL
add esp, 20
stc
ret
 
.shrinkAttribute:
add ecx, edi
inc ecx
add esi, eax
xor edi, edi
sub esp, 20
@@:
mov [esp+16], esi
call ntfs_decode_mcb_entry
jnc .err3
add edi, [esp+8]
sub ecx, [esp]
jnc @b
mov ebx, ecx
add ecx, [esp]
mov eax, [esp+8]
mov [ebp+NTFS.fileDataSize], ecx
mov [ebp+NTFS.fileDataStart], eax
push edi
add edi, ecx
neg ebx
call ntfsSpaceFree
pop edi
jc .end
@@:
call ntfs_decode_mcb_entry
jnc .end
cmp dword[esp+8], 0
jz @b
add edi, [esp+8]
mov ebx, [esp]
call ntfsSpaceFree
jnc @b
.end:
add esp, 16
pop edi
cmp [ebp+NTFS.fileDataSize], 0
jz @f
mov esi, [ebp+NTFS.attr_offs]
call createMcbEntry
mov [ebp+NTFS.fileDataSize], 0
@@:
ret
 
.resident:
test edx, edx
jnz .nonResident
cmp eax, 8000h
jnc .nonResident
add ax, [esi+attributeOffset]
sub eax, [esi+sizeWithHeader]
jc @f
mov edi, [ebp+NTFS.frs_buffer]
mov ecx, eax
add ecx, [edi+recordRealSize]
cmp [edi+recordAllocatedSize], ecx
jc .nonResident
add eax, 7
and eax, not 7
add [edi+recordRealSize], eax
add edi, [edi+recordRealSize]
add [esi+sizeWithHeader], eax
add esi, [esi+sizeWithHeader]
mov ecx, edi
sub ecx, esi
shr ecx, 2
sub edi, 4
mov esi, edi
sub esi, eax
std
rep movsd
mov ecx, eax
shr ecx, 2
xor eax, eax
rep stosd
cld
mov esi, [ebp+NTFS.attr_offs]
@@:
mov eax, dword [ebp+NTFS.attr_size]
mov [esi+sizeWithoutHeader], eax
mov [ebp+NTFS.fileDataSize], 0
clc
ret
 
.nonResident: ; convert resident to non-resident
mov eax, dword [ebp+NTFS.attr_size]
sub eax, 1
sbb edx, 0
mov ecx, [ebp+NTFS.sectors_per_cluster]
shl ecx, 9
div ecx
inc eax
mov [ebp+NTFS.fileDataSize], eax
mov edi, [ebp+NTFS.BitmapStart]
push ecx
call ntfsSpaceAlloc
pop ecx
jc .err2
mov esi, [ebp+NTFS.attr_offs]
xor eax, eax
xor edx, edx
@@:
add eax, ecx
inc edx
cmp eax, [esi+sizeWithoutHeader]
jc @b
push edx
push eax
stdcall kernel_alloc, eax
mov ecx, [esp]
shr ecx, 2
mov edi, eax
mov ebx, eax
xor eax, eax
rep stosd
mov al, [esi+attributeOffset]
mov ecx, [esi+sizeWithoutHeader]
add esi, eax
mov edi, ebx
rep movsb
mov eax, [ebp+NTFS.fileDataStart]
mul [ebp+NTFS.sectors_per_cluster]
pop ecx
shr ecx, 9
call fs_write64_app
stdcall kernel_free, ebx
mov esi, [ebp+NTFS.attr_offs]
add esi, [esi+sizeWithHeader]
mov ecx, [ebp+NTFS.frs_buffer]
add ecx, [ecx+recordRealSize]
sub ecx, esi
shr ecx, 2
lea edi, [ebp+NTFS.bitmap_buf]
push ecx
rep movsd
mov edi, [ebp+NTFS.attr_offs]
add edi, 16
mov cl, 6
xor eax, eax
rep stosd
mov edi, [ebp+NTFS.attr_offs]
mov eax, [ebp+NTFS.fileDataSize]
dec eax
mov [edi+lastVCN], eax
inc eax
mov ecx, [ebp+NTFS.sectors_per_cluster]
shl ecx, 9
mul ecx
mov byte [edi+sizeWithHeader], 50h
mov byte [edi+nonResidentFlag], 1
mov byte [edi+dataRunsOffset], 40h
mov [edi+attributeAllocatedSize], eax
mov [edi+attributeAllocatedSize+4], edx
mov eax, dword [ebp+NTFS.attr_size]
mov edx, dword [ebp+NTFS.attr_size+4]
mov [edi+attributeRealSize], eax
mov [edi+attributeRealSize+4], edx
mov [edi+initialDataSize], eax
mov [edi+initialDataSize+4], edx
mov esi, edi
add edi, 40h
call createMcbEntry
mov eax, edi
mov edi, [ebp+NTFS.attr_offs]
sub eax, edi
add eax, 8
and eax, not 7
mov [edi+sizeWithHeader], eax
pop ecx
lea esi, [ebp+NTFS.bitmap_buf]
add edi, eax
rep movsd
mov esi, [ebp+NTFS.frs_buffer]
sub edi, esi
mov [esi+recordRealSize], edi
pop edx
sub [ebp+NTFS.fileDataSize], edx
add [ebp+NTFS.fileDataStart], edx
ret
 
.makeResident: ; convert non-resident to empty resident
movzx eax, byte [esi+dataRunsOffset]
mov byte [esi+nonResidentFlag], 0
mov dword [esi+sizeWithoutHeader], 0
mov dword [esi+attributeOffset], 18h
add esi, eax
xor edi, edi
sub esp, 16
@@:
call ntfs_decode_mcb_entry
jnc @f
cmp dword[esp+8], 0
jz @b
add edi, [esp+8]
mov ebx, [esp]
call ntfsSpaceFree
jnc @b
@@:
add esp, 16
mov [ebp+NTFS.fileDataSize], 0
ret
 
ntfsSpaceClean:
; clean up to 16 Mb of disk space
; in:
; [ebp+NTFS.fileDataStart] = block to clean
; [ebp+NTFS.fileDataSize] = block size
mov eax, [ebp+NTFS.fileDataSize]
test eax, eax
jz @f
mul [ebp+NTFS.sectors_per_cluster]
cmp eax, 8001h
jnc @f
push eax
shl eax, 9
stdcall kernel_alloc, eax
pop ecx
test eax, eax
jz @f
push ecx
shl ecx, 7
mov edi, eax
mov ebx, eax
xor eax, eax
rep stosd
mov eax, [ebp+NTFS.fileDataStart]
mul [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.LastRead], eax
pop ecx
call fs_write64_app
stdcall kernel_free, ebx
@@:
ret
 
ntfsSpaceAlloc:
; allocate disk space
; in:
; edi = offset in bitmap to start search from
; [ebp+NTFS.fileDataSize] = block size in clusters
; out:
; [ebp+NTFS.fileDataStart] = allocated block starting cluster
; CF=1 -> disk full
mov ecx, [ebp+NTFS.BitmapBuffer]
add edi, ecx
add ecx, [ebp+NTFS.BitmapSize]
sub ecx, edi
ja @f
push eax
call bitmapBuffering
pop eax
shl ecx, 2
@@:
shr ecx, 2
push ecx
mov eax, [ebp+NTFS.fileDataSize]
shr eax, 5
jz .small
mov ebx, eax ; bitmap dwords
.start:
mov ecx, [ebp+NTFS.BitmapBuffer]
add ecx, [ebp+NTFS.BitmapSize]
sub ecx, edi
shr ecx, 2
@@:
xor eax, eax
repnz scasd ; search for empty dword
jz @f
call bitmapBuffering
jmp @b
@@:
cmp ecx, ebx
jnc @f
call bitmapBuffering
jmp @b
@@:
sub edi, 4
mov ecx, ebx
mov esi, edi
xor eax, eax
repz scasd ; check following dwords
jnz .start
sub esi, 4
mov eax, [esi]
xor edx, edx
bsr edx, eax
inc edx
push edx ; starting bit
push esi ; starting dword
add esi, 4
neg edx
add edx, 32
mov eax, [ebp+NTFS.fileDataSize]
sub eax, edx
mov edx, eax
shr eax, 5
shl eax, 2
add esi, eax
mov eax, [esi]
bsf ecx, eax ; check last dword
jz .done
and edx, 31
cmp ecx, edx
jnc .done
add esp, 8
jmp .start
 
@@:
sub edi, 4
call bitmapBuffering
push ecx
.small: ; less than 32 clusters
pop ecx
or eax, -1
repz scasd
jecxz @b
push ecx
mov eax, [edi-4]
not eax
@@:
bsf ecx, eax ; first 0
jz .small
not eax
shr eax, cl
shl eax, cl
bsf edx, eax ; next 1
jz @f
sub edx, ecx
cmp edx, [ebp+NTFS.fileDataSize]
jnc .got ; fits inside
bsf ecx, eax
not eax
shr eax, cl
shl eax, cl
jmp @b
 
@@: ; next dword
mov eax, [edi]
bsf edx, eax
jz .got ; empty
add edx, 32
sub edx, ecx
cmp edx, [ebp+NTFS.fileDataSize]
jc .small
.got:
sub edi, 4
push ecx ; starting bit
push edi ; starting dword
.done: ; mark space
pop edi ecx
cmp ecx, 32
jc @f
xor ecx, ecx
add edi, 4
@@:
push ecx edi
or eax, -1
shr eax, cl
shl eax, cl
neg ecx
add ecx, 32
sub ecx, [ebp+NTFS.fileDataSize]
jc @f
shl eax, cl ; fits inside dword
shr eax, cl
or [edi], eax
jmp .end
 
@@:
or [edi], eax
neg ecx
push ecx
shr ecx, 5
add edi, 4
or eax, -1
rep stosd
pop ecx
and ecx, 31
shr eax, cl
shl eax, cl
not eax
or [edi], eax
.end:
pop eax
pop ecx
sub eax, [ebp+NTFS.BitmapBuffer]
shl eax, 3
add eax, ecx
pop ecx
mov ecx, [ebp+NTFS.fileDataSize]
mov [ebp+NTFS.fileDataStart], eax
add ecx, eax
add ecx, 4095
shr ecx, 3+9
shr eax, 3+9
sub ecx, eax
mov ebx, eax
shl ebx, 9
add eax, [ebp+NTFS.BitmapLocation]
add ebx, [ebp+NTFS.BitmapBuffer]
xor edx, edx
jmp fs_write64_app
 
ntfsSpaceFree:
; free disk space
; in:
; edi = starting cluster
; ebx = size in clusters
mov eax, edi
add eax, ebx
shr eax, 3
cmp eax, [ebp+NTFS.BitmapSize]
jc @f
add eax, [ebp+NTFS.BitmapBuffer]
push edi
mov edi, eax
call bitmapBuffering
pop edi
@@:
push edi
mov ecx, edi
shr edi, 5
shl edi, 2
add edi, [ebp+NTFS.BitmapBuffer]
and ecx, 31
xor eax, eax
dec eax
shr eax, cl
shl eax, cl
neg ecx
add ecx, 32
sub ecx, ebx
jc @f
shl eax, cl ; fits inside dword
shr eax, cl
not eax
and [edi], eax
jmp .writeBitmap
 
@@:
not eax
and [edi], eax
neg ecx
push ecx
shr ecx, 5
add edi, 4
xor eax, eax
rep stosd
pop ecx
and ecx, 31
dec eax
shr eax, cl
shl eax, cl
and [edi], eax
.writeBitmap:
pop eax
mov edi, eax
lea ecx, [eax+ebx+4095]
shr eax, 3+9
shr ecx, 3+9
sub ecx, eax
mov ebx, eax
shl ebx, 9
add eax, [ebp+NTFS.BitmapLocation]
add ebx, [ebp+NTFS.BitmapBuffer]
xor edx, edx
jmp fs_write64_app
 
bitmapBuffering:
; Extend BitmapBuffer and read next 32kb of bitmap
; Warning: $Bitmap fragmentation is not foreseen
; in: edi -> position in bitmap buffer
; out: ecx = number of buffered dwords left
push ebx
mov eax, [ebp+NTFS.BitmapTotalSize]
cmp eax, [ebp+NTFS.BitmapSize]
jz .end
stdcall alloc_pages, 8
test eax, eax
jz .end
add eax, 3
mov ebx, [ebp+NTFS.BitmapBuffer]
add ebx, [ebp+NTFS.BitmapSize]
push ebx
mov ecx, 8
call commit_pages
mov eax, [ebp+NTFS.BitmapSize]
shr eax, 9
add eax, [ebp+NTFS.BitmapLocation]
pop ebx
mov ecx, 64
xor edx, edx
call fs_read64_app
test eax, eax
jnz .err
mov eax, [ebp+NTFS.BitmapSize]
add eax, 8000h
cmp [ebp+NTFS.BitmapTotalSize], eax
jnc @f
mov eax, [ebp+NTFS.BitmapTotalSize]
@@:
mov [ebp+NTFS.BitmapSize], eax
pop ebx
mov ecx, [ebp+NTFS.BitmapBuffer]
add ecx, eax
sub ecx, edi
jbe bitmapBuffering
shr ecx, 2
ret
 
.err:
mov eax, [ebp+NTFS.BitmapBuffer]
add eax, [ebp+NTFS.BitmapSize]
mov ecx, 8
call release_pages
.end:
add esp, 12 ; ret
stc
ret
 
;----------------------------------------------------------------
ntfs_WriteFile:
call ntfs_lock
call ntfs_find_lfn
jc ntfsNotFound
cmp [ebp+NTFS.cur_iRecord], 16
jc ntfsDenied
test dword [eax+fileFlags], 10000001h
jnz ntfsDenied
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
; edit directory node
mov edi, [ebp+NTFS.cur_index_buf]
cmp dword [edi], 'INDX'
jz @f
mov esi, [ebp+NTFS.frs_buffer]
mov ecx, [esi+recordRealSize]
shr ecx, 2
rep movsd
mov esi, [ebp+NTFS.attr_offs]
mov cl, [esi+attributeOffset]
sub esi, [ebp+NTFS.frs_buffer]
add eax, ecx
add eax, esi
@@:
mov edi, eax
mov eax, [ebx+4]
mov edx, [ebx+8]
add eax, [ebx+12]
adc edx, 0
mov [edi+fileRealSize], eax
mov [edi+fileRealSize+4], edx
push edx eax ebx
call ntfsGetTime
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov [edi+recordModified], eax
mov [edi+recordModified+4], edx
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
pop ebx ecx edx
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsFail
mov esi, edi
mov edi, [ebp+NTFS.frs_buffer]
cmp word [edi+baseRecordReuse], 0
jnz ntfsUnsupported ; auxiliary record
mov al, [edi+attributeOffset]
add edi, eax
mov al, [edi+attributeOffset]
add edi, eax
mov eax, ecx
mov ecx, 6
add esi, fileModified
add edi, 8
rep movsd
mov ecx, [ebp+NTFS.attr_offs]
cmp word [ecx+attributeFlags], 0
jnz ntfsUnsupported
push ebx
cmp byte [ecx+nonResidentFlag], 0
jz .resizeAttribute
cmp edx, [ecx+attributeRealSize+4]
jc .writeNode
jnz .resizeAttribute
cmp [ecx+attributeRealSize], eax
jnc .writeNode
.resizeAttribute:
call resizeAttribute
jc ntfsErrorPop
mov ecx, [ebp+NTFS.attr_offs]
cmp byte [ecx+nonResidentFlag], 1
jz @f
mov ebx, [esp]
movzx edi, byte [ecx+attributeOffset]
add edi, ecx
add edi, [ebx+4]
mov ecx, [ebx+12]
mov esi, [ebx+16]
rep movsb
@@:
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.mftLastRead]
call writeRecord ; file
call ntfs_restore_usa_frs
.writeNode:
mov ebx, [ebp+NTFS.cur_index_buf]
mov edx, [ebp+NTFS.nodeLastRead]
call writeRecord ; directory
pop ebx
mov ecx, [ebp+NTFS.attr_offs]
cmp byte [ecx+nonResidentFlag], 0
jz .done
mov ecx, [ebx+12]
test ecx, ecx
jz .done
mov eax, [ebx+4]
mov edx, [ebx+8]
mov esi, [ebx+16]
shrd eax, edx, 9
test dword[ebx+4], 1FFh
jz .aligned
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_size], 1
lea edi, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], edi
call ntfs_read_attr.continue
jc ntfsDevice
mov eax, [ebx+4]
and eax, 1FFh
add edi, eax
sub eax, [ebp+NTFS.cur_read]
neg eax
push ecx
cmp ecx, eax
jb @f
mov ecx, eax
@@:
sub [esp], ecx
rep movsb
push ebx
mov eax, [ebp+NTFS.LastRead]
lea ebx, [ebp+NTFS.bitmap_buf]
mov ecx, 1
xor edx, edx
call fs_write64_app
pop ebx
pop ecx
test ecx, ecx
jz .done
mov eax, [ebx+4]
mov edx, [ebx+8]
shrd eax, edx, 9
inc eax
.aligned:
push ecx
shr ecx, 9
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_size], ecx
mov [ebp+NTFS.cur_buf], esi
add eax, ecx
push eax
mov [ebp+NTFS.bWriteAttr], 1
call ntfs_read_attr.continue
mov [ebp+NTFS.bWriteAttr], 0
pop [ebp+NTFS.cur_offs]
pop ecx
jc ntfsDevice
and ecx, 1FFh
jz .done
add esi, [ebp+NTFS.cur_read]
mov [ebp+NTFS.cur_size], 1
lea edi, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], edi
call ntfs_read_attr.continue
jc ntfsDevice
rep movsb
push ebx
mov eax, [ebp+NTFS.LastRead]
lea ebx, [ebp+NTFS.bitmap_buf]
mov ecx, 1
xor edx, edx
call fs_write64_app
pop ebx
.done:
mov ebx, [ebx+12]
jmp ntfsDone
 
;----------------------------------------------------------------
ntfs_Delete:
call ntfs_lock
call ntfs_find_lfn
jc ntfsNotFound
cmp [ebp+NTFS.cur_iRecord], 16
jc ntfsDenied
test byte [eax+fileFlags], 1
jnz ntfsDenied
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
mov ebx, [eax+directoryRecordReference]
mov [ebp+NTFS.newRecord], ebx
mov bx, [eax+fileReferenceReuse]
mov [ebp+NTFS.indexPointer], esi
mov eax, [ebp+NTFS.cur_iRecord]
shr eax, 3
cmp eax, [ebp+NTFS.mftBitmapSize]
jnc ntfsUnsupported
; examine file record
mov [ebp+NTFS.cur_attr], 0x80 ; file?
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jnc @f
xor eax, eax
push ebx eax eax eax eax
mov [esp+12], esp
push eax
mov ebx, esp
mov [ebp+NTFS.cur_attr], 0x90 ; folder?
call ntfs_ReadFolder.doit
mov edx, [esp+12]
add esp, 20
pop ebx
test eax, eax
jnz .ret
cmp edx, 2
jnz ntfsDenied ; folder is not empty
mov [ebp+NTFS.cur_attr], 0xA0
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr.newAttribute
jc .deleteFileRecord
@@:
mov esi, [ebp+NTFS.frs_buffer]
cmp word [esi+baseRecordReuse], 0
jnz ntfsUnsupported ; auxiliary record
cmp word [esi+reuseCounter], bx
jnz .backToIndex ; broken index
test byte [esi+recordFlags], 1
jz .writeBitmapMFT ; record deleted
cmp byte [esi+hardLinkCounter], 3
jnc ntfsUnsupported
mov esi, [ebp+NTFS.attr_offs]
cmp byte [esi+nonResidentFlag], 0
jz .deleteFileRecord
movzx eax, byte [esi+dataRunsOffset]
add esi, eax
xor edi, edi
sub esp, 16
@@:
call ntfs_decode_mcb_entry
jnc @f
cmp dword[esp+8], 0
jz @b
add edi, [esp+8]
mov ebx, [esp]
call ntfsSpaceFree
jnc @b
@@:
add esp, 16
.deleteFileRecord:
mov ebx, [ebp+NTFS.frs_buffer]
mov byte [ebx+recordFlags], 0
mov edx, [ebp+NTFS.mftLastRead]
call writeRecord
.writeBitmapMFT:
mov eax, [ebp+NTFS.cur_iRecord]
mov ecx, eax
shr eax, 3
and ecx, 7
mov edi, [ebp+NTFS.mftBitmapBuffer]
btr [edi+eax], ecx
shr eax, 9
mov ebx, eax
shl ebx, 9
add eax, [ebp+NTFS.mftBitmapLocation]
add ebx, edi
mov ecx, 1
xor edx, edx
call fs_write64_sys
.backToIndex:
mov eax, [ebp+NTFS.newRecord]
mov [ebp+NTFS.cur_iRecord], eax
mov esi, [ebp+NTFS.indexPointer]
call ntfs_find_lfn.doit2
jc ntfsFail
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov byte [ebx], 0
mov ebx, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], ebx
xor ebx, ebx
test byte [eax+indexFlags], 1
jz .deleteIndex ; no subnode
mov edi, eax
call .findSubindex
jc ntfsFail
movzx edx, word [edi+indexAllocatedSize]
test esi, esi
jz @f
sub edx, eax
sub edx, 8
@@:
mov eax, edi
mov ebx, esi
jmp @f
 
.deleteIndex:
movzx edx, word [eax+indexAllocatedSize]
mov ecx, [eax+fileRecordReference]
cmp [eax+edx+fileRecordReference], ecx
jnz @f
add dx, [eax+edx+indexAllocatedSize]
@@:
mov edi, [ebp+NTFS.cur_index_buf]
cmp dword [edi], 'INDX'
jz .indexRecord
sub eax, edi
mov edi, [ebp+NTFS.indexRoot]
sub [edi+sizeWithHeader], edx
sub [edi+sizeWithoutHeader], edx
movzx ecx, byte [edi+attributeOffset]
add edi, ecx
add eax, edi
sub [edi+rootNode+nodeRealSize], edx
sub [edi+rootNode+nodeAllocatedSize], edx
mov edi, [ebp+NTFS.frs_buffer]
sub [edi+recordRealSize], edx
mov ecx, [edi+recordRealSize]
cmp [edi+recordAllocatedSize], ecx
jmp @f
 
.indexRecord:
add edi, recordNode
sub [edi+nodeRealSize], edx
mov ecx, [edi+nodeRealSize]
cmp [edi+nodeAllocatedSize], ecx
@@:
jc ntfsUnsupported
add ecx, edi
sub ecx, eax
mov esi, eax
add esi, edx
mov edi, eax
test edx, edx
jns @f
neg edx
add edx, ecx
sub edx, 4
add esi, edx
add edi, edx
std
@@:
jz @f
shr ecx, 2
rep movsd
cld
@@:
test ebx, ebx
jz .done
; copy index from the subnode to replace deleted pointing index
movzx ecx, word [ebx+indexAllocatedSize]
mov edx, ecx
test byte [ebx+indexFlags], 1
jz @f
sub ecx, 8
movzx edi, word [ebx+edx+indexAllocatedSize]
add edi, edx
mov esi, [ebx+ecx]
mov [ebx+edi-8], esi
mov [ebx+indexAllocatedSize], cx
@@:
shr ecx, 2
mov esi, ebx
mov edi, eax
rep movsd
add word [eax+indexAllocatedSize], 8
mov byte [eax+indexFlags], 1
mov edi, [ebp+NTFS.secondIndexBuffer]
mov eax, ebx
xor ebx, ebx
jmp .indexRecord
 
.done:
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.rootLastRead]
call writeRecord
mov ebx, [ebp+NTFS.cur_index_buf]
cmp dword [ebx], 'INDX'
jnz @f
mov edx, [ebp+NTFS.nodeLastRead]
call writeRecord
@@:
mov ebx, [ebp+NTFS.secondIndexBuffer]
cmp byte [ebx], 0
jz ntfsDone
mov edx, [ebp+NTFS.LastRead]
call writeRecord
jmp ntfsDone
 
.findSubindex:
; in: eax -> index
; out:
; CF=1 -> error
; esi=0 -> subnode deleted
; esi -> replacement index
; eax = index effective size
movzx edx, word [eax+indexAllocatedSize]
mov eax, [eax+edx-8]
mov edx, [ebp+NTFS.cur_size]
push edx
cmp edx, [ebp+NTFS.cur_subnode_size]
jz @f
mul [ebp+NTFS.sectors_per_cluster]
@@:
mov [ebp+NTFS.cur_attr], 0xA0
mov [ebp+NTFS.cur_offs], eax
push eax
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov esi, ebx
mov [ebp+NTFS.cur_buf], ebx
call ntfs_read_attr.newAttribute
pop [ebp+NTFS.cur_offs]
pop eax
jc .ret
cmp dword [esi], 'INDX'
stc
jnz .ret
mov [ebp+NTFS.cur_size], eax
shl eax, 9
call ntfs_restore_usa
jc .ret
add esi, recordNode
add esi, [esi+indexOffset]
test byte [esi+indexFlags], 2
jnz .emptyNode
cmp [ebp+NTFS.fragmentCount], 1
stc
jnz .ret ; record fragmented
xor eax, eax
@@:
add esi, eax
mov ax, [esi+indexAllocatedSize]
test byte [esi+eax+indexFlags], 2
jz @b
test byte [esi+indexFlags], 1
jz .ret
add eax, esi
push esi
push [ebp+NTFS.cur_offs]
call .findSubindex
pop [ebp+NTFS.cur_offs]
pop edx
jc .ret
test esi, esi
jnz .ret
mov esi, edx
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov [ebp+NTFS.cur_buf], ebx
push [ebp+NTFS.cur_size]
call ntfs_read_attr.continue
pop eax
jc .ret
shl eax, 9
call ntfs_restore_usa
jc .ret
movzx eax, word [esi+indexAllocatedSize]
sub eax, 8
.ret:
ret
 
.emptyNode:
test byte [esi+indexFlags], 1
jz @f
mov eax, esi
push [ebp+NTFS.cur_offs]
call .findSubindex
pop [ebp+NTFS.cur_offs]
jc .ret
test esi, esi
jnz .ret
@@: ; delete node
mov esi, [ebp+NTFS.attr_offs]
add esi, [esi+sizeWithHeader]
cmp byte [esi], 0xB0
stc
jnz .ret
movzx eax, byte [esi+attributeOffset]
add esi, eax
mov eax, [ebp+NTFS.cur_offs]
xor edx, edx
div [ebp+NTFS.cur_size]
mov edx, eax
shr eax, 3
and edx, 7
btr [esi+eax], edx
mov esi, [ebp+NTFS.secondIndexBuffer]
mov byte [esi], 0
xor esi, esi
ret
 
;----------------------------------------------------------------
ntfs_SetFileEnd:
call ntfs_lock
call ntfs_find_lfn
jc ntfsNotFound
cmp [ebp+NTFS.cur_iRecord], 16
jc ntfsDenied
test dword [eax+fileFlags], 10000001h
jnz ntfsDenied
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
; edit directory node
mov edi, [ebp+NTFS.cur_index_buf]
cmp dword [edi], 'INDX'
jz @f
mov esi, [ebp+NTFS.frs_buffer]
mov ecx, [esi+recordRealSize]
shr ecx, 2
rep movsd
mov esi, [ebp+NTFS.attr_offs]
mov cl, [esi+attributeOffset]
sub esi, [ebp+NTFS.frs_buffer]
add eax, ecx
add eax, esi
@@:
mov edi, eax
mov eax, [ebx+4]
mov edx, [ebx+8]
mov [edi+fileRealSize], eax
mov [edi+fileRealSize+4], edx
push edx eax ebx
call ntfsGetTime
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov [edi+recordModified], eax
mov [edi+recordModified+4], edx
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
pop ebx ecx edx
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsFail
mov esi, edi
mov edi, [ebp+NTFS.frs_buffer]
cmp word [edi+baseRecordReuse], 0
jnz ntfsUnsupported ; auxiliary record
mov al, [edi+attributeOffset]
add edi, eax
mov al, [edi+attributeOffset]
add edi, eax
mov eax, ecx
mov ecx, 6
add esi, fileModified
add edi, 8
rep movsd
mov ecx, [ebp+NTFS.attr_offs]
cmp word [ecx+attributeFlags], 0
jnz ntfsUnsupported
cmp byte [ecx+nonResidentFlag], 0
jz .resizeAttribute
cmp [ecx+attributeRealSize+4], edx
jnz .resizeAttribute
cmp [ecx+attributeRealSize], eax
jnc .resizeAttribute
mov eax, [ecx+attributeRealSize]
mov ecx, [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.cur_size], ecx
shl ecx, 9
div ecx
test edx, edx
jz .aligned
push edx
push ecx
mul [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.cur_offs], eax
stdcall kernel_alloc, ecx
pop ecx
pop edi
mov esi, eax
sub ecx, edi
add edi, eax
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr.continue
jc @f
xor eax, eax
rep stosb
push ebx
mov eax, [ebp+NTFS.LastRead]
mov ebx, esi
mov ecx, [ebp+NTFS.sectors_per_cluster]
xor edx, edx
call fs_write64_app
pop ebx
@@:
stdcall kernel_free, esi
.aligned:
mov eax, [ebx+4]
mov edx, [ebx+8]
.resizeAttribute:
call resizeAttribute
jc ntfsError
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.mftLastRead]
call writeRecord ; file
mov ebx, [ebp+NTFS.cur_index_buf]
mov edx, [ebp+NTFS.nodeLastRead]
call writeRecord ; directory
call ntfsSpaceClean
jmp ntfsDone
 
ntfsGetTime:
call fsGetTime
jmp @f
 
ntfsCalculateTime:
; in: esi -> data block
; out: edx:eax = seconds since 01.01.1601 x10000000
call fsCalculateTime
@@:
mov edx, 10000000
mul edx
add eax, 3365781504
adc edx, 29389701
ret
 
;----------------------------------------------------------------
ntfs_SetFileInfo:
call ntfs_lock
call ntfs_find_lfn
jnc @f
test eax, eax
jz ntfsFail
jmp ntfsNotFound
 
@@:
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
mov esi, [ebp+NTFS.cur_index_buf]
cmp dword [esi], 'INDX'
jz @f
sub eax, esi
mov esi, [ebp+NTFS.indexRoot]
movzx edx, byte [esi+attributeOffset]
add eax, esi
add eax, edx
@@:
mov esi, [ebx+16]
mov edi, eax
mov eax, [esi]
and eax, 27h
and byte [edi+fileFlags], -28h
or [edi+fileFlags], al
add esi, 8
call ntfsCalculateTime
mov [edi+fileCreated], eax
mov [edi+fileCreated+4], edx
add esi, 8
call ntfsCalculateTime
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
add esi, 8
call ntfsCalculateTime
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov ebx, [ebp+NTFS.cur_index_buf]
cmp dword [ebx], 'INDX'
jz @f
mov ebx, [ebp+NTFS.frs_buffer]
@@:
mov edx, [ebp+NTFS.LastRead]
call writeRecord
jmp ntfsDone
 
ntfsUnsupported:
push ERROR_UNSUPPORTED_FS
jmp ntfsOut
ntfsDevice:
push ERROR_DEVICE
jmp ntfsOut
ntfsNotFound:
push ERROR_FILE_NOT_FOUND
jmp ntfsOut
ntfsDenied:
push ERROR_ACCESS_DENIED
jmp ntfsOut
ntfsFail:
push ERROR_FS_FAIL
jmp ntfsOut
ntfsDiskFull:
push ERROR_DISK_FULL
jmp ntfsOut
ntfsErrorPop5:
pop ebx
pop ebx
ntfsErrorPop3:
pop ebx
ntfsErrorPop2:
pop ebx
ntfsErrorPop:
pop ebx
ntfsError:
push eax
ntfsOut:
call ntfs_unlock
xor ebx, ebx
pop eax
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/fs_common.inc
0,0 → 1,142
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
fsReadCMOS:
out 70h, al
in al, 71h
xor ah, ah
shl ax, 4
shr al, 4
aad
ret
 
fsGetTime:
mov al, 7
call fsReadCMOS
ror eax, 8
mov al, 8
call fsReadCMOS
ror eax, 8
mov al, 9
call fsReadCMOS
add eax, 2000
ror eax, 16
push eax
xor eax, eax
call fsReadCMOS
ror eax, 8
mov al, 2
call fsReadCMOS
ror eax, 8
mov al, 4
call fsReadCMOS
ror eax, 16
push eax
mov esi, esp
add esp, 8
fsCalculateTime:
; in: esi -> data block
; out: eax = seconds since 01.01.2001
movzx eax, word [esi+6]
sub eax, 2001
jnc @f
xor eax, eax
@@:
mov edx, months
mov ebx, eax
inc eax
test eax, 3
jnz @f
add edx, 12
@@:
movzx eax, byte [esi+5]
dec eax
xor ecx, ecx
@@:
dec eax
js @f
add cl, [edx+eax]
adc ch, 0
jmp @b
@@:
mov eax, ebx ; years
mov edx, 365
mul edx
shr ebx, 2
add eax, ebx
add eax, ecx
mov bl, [esi+4]
dec eax
add eax, ebx ; days
mov dl, 24
mul edx
mov bl, [esi+2]
add eax, ebx ; hours
mov ecx, 60
mul ecx
mov bl, [esi+1]
add eax, ebx ; minutes
mul ecx
mov bl, [esi]
add eax, ebx
ret
 
iglobal
months db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
months2 db 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
endg
 
fsTime2bdfe:
; in: eax = seconds since 01.01.2001
; edi -> data block
; out: edi = edi+8
xor edx, edx
mov ecx, 60
div ecx
mov [edi], dl
xor edx, edx
div ecx
mov [edi+1], dl
xor edx, edx
mov cl, 24
div ecx
mov [edi+2], dx
xor edx, edx
mov cx, 365
div ecx
mov ebx, eax
add ebx, 2001
shr eax, 2
sub edx, eax
jns @f
dec ebx
add edx, 365
test ebx, 3
jnz @f
inc edx
@@:
xor eax, eax
mov ecx, months-1
test ebx, 3
jnz @f
add ecx, 12
@@:
inc ecx
inc eax
sub dl, [ecx]
jnc @b
dec dh
jns @b
add dl, [ecx]
inc edx
mov [edi+4], dl
mov [edi+5], al
mov [edi+6], bx
add edi, 8
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/gui/window.inc
0,0 → 1,2496
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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$
 
;==============================================================================
;///// public functions ///////////////////////////////////////////////////////
;==============================================================================
 
window.BORDER_SIZE = 5
 
uglobal
common_colours rd 48
draw_limits RECT
endg
 
;------------------------------------------------------------------------------
syscall_draw_window: ;///// system function 0 /////////////////////////////////
;------------------------------------------------------------------------------
mov eax, edx
shr eax, 24
and al, 0x0f
cmp al, 5
jae .exit
 
push eax
call window._.sys_set_window
pop eax
 
or al, al
jnz @f
 
; type I - original style
call drawwindow_I
jmp window._.draw_window_caption.2
;--------------------------------------
@@:
dec al
jnz @f
 
; type II - only reserve area, no draw
call __sys_draw_pointer
jmp .exit
;--------------------------------------
@@:
dec al
jnz @f
 
; type III - new style
call drawwindow_III
jmp window._.draw_window_caption.2
;--------------------------------------
@@:
; type IV & V - skinned window (resizable & not)
mov eax, [thread_count]
movzx eax, word[WIN_POS + eax * 2]
cmp eax, [current_slot_idx]
setz al
movzx eax, al
push eax
call drawwindow_IV
jmp window._.draw_window_caption.2
;--------------------------------------
.exit:
ret
;------------------------------------------------------------------------------
syscall_display_settings: ;///// system function 48 ///////////////////////////
;------------------------------------------------------------------------------
cmp ebx, 13
ja .ret
jmp dword[.ftable + ebx*4]
 
align 4
.ftable:
dd .redrawWholeScreen
dd .setButtonStyle
dd .setSystemColors
dd .getSystemColors
dd .getCaptionHeight
dd .getScreenWorkingArea
dd .setScreenWorkingArea
dd .getSkinMargins
dd .setSkin
dd .getFontSmoothing
dd .setFontSmoothing
dd .getFontSize
dd .setFontSize
dd .setSkinUnicode
 
.redrawWholeScreen:
xor eax, eax
inc ebx
cmp [windowtypechanged], ebx
jne .ret
mov [windowtypechanged], eax
.redrawScreen:
xor eax, eax
mov [draw_limits.left], eax
mov [draw_limits.top], eax
mov eax, [_display.width]
dec eax
mov [draw_limits.right], eax
mov eax, [_display.height]
dec eax
mov [draw_limits.bottom], eax
mov eax, window_data
jmp redrawscreen
 
.setButtonStyle:
; in: ecx: 0 = flat, 1 = with gradient
and ecx, 1
cmp ecx, [buttontype]
je .ret
mov [buttontype], ecx
mov [windowtypechanged], ebx
.ret:
ret
 
.setSystemColors:
; in: ecx = pointer to color table, edx = size of color table
dec ebx
mov esi, ecx
cmp edx, 192
jnae @f
mov edx, 192 ; max size
@@:
stdcall is_region_userspace, esi, edx ;
jz @f ;
ret ;
@@:
mov edi, common_colours
mov ecx, edx
rep movsb
mov [windowtypechanged], ebx
ret
 
.getSystemColors:
; in: ecx = pointer to color table, edx = size of color table
mov edi, ecx
cmp edx, 192
jnae @f
mov edx, 192 ; max size
@@:
stdcall is_region_userspace, edi, edx
jz @f
ret
@@:
mov esi, common_colours
mov ecx, edx
rep movsb
ret
 
.getCaptionHeight:
mov eax, [_skinh]
mov [esp + 32], eax
ret
 
.getScreenWorkingArea:
; out: eax = pack[left, right], ebx = pack[top, bottom]
mov eax, [screen_workarea.left - 2]
mov ax, word[screen_workarea.right]
mov [esp + 32], eax
mov eax, [screen_workarea.top - 2]
mov ax, word[screen_workarea.bottom]
mov [esp + 20], eax
ret
 
.setScreenWorkingArea:
; in: ecx = pack[left, right], edx = pack[top, bottom]
xor esi, esi
mov edi, [_display.width]
dec edi
mov eax, ecx
movsx ebx, ax
sar eax, 16
cmp eax, ebx
jge .check_horizontal
inc esi
or eax, eax
jge @f
xor eax, eax
@@:
mov [screen_workarea.left], eax
cmp ebx, edi
jle @f
mov ebx, edi
@@:
mov [screen_workarea.right], ebx
.check_horizontal:
mov edi, [_display.height]
dec edi
mov eax, edx
movsx ebx, ax
sar eax, 16
cmp eax, ebx
jge .check_if_redraw_needed
inc esi
or eax, eax
jge @f
xor eax, eax
@@:
mov [screen_workarea.top], eax
cmp ebx, edi
jle @f
mov ebx, edi
@@:
mov [screen_workarea.bottom], ebx
.check_if_redraw_needed:
or esi, esi
jz @f
call repos_windows
.calculateScreen:
xor eax, eax
xor ebx, ebx
mov ecx, [_display.width]
mov edx, [_display.height]
dec ecx
dec edx
jmp calculatescreen
 
.getSkinMargins:
; out: eax = pack[left, right], ebx = pack[top, bottom]
mov eax, [_skinmargins + 0]
mov [esp + 32], eax
mov eax, [_skinmargins + 4]
mov [esp + 20], eax
ret
 
.setSkin:
; in: ecx -> file path string
mov ebx, ecx
call read_skin_file
mov [esp + 32], eax
test eax, eax
jnz .ret
call .calculateScreen
jmp .redrawScreen
 
.getFontSmoothing:
xor eax, eax
mov al, [fontSmoothing]
mov [esp + 32], eax
ret
 
.setFontSmoothing:
mov [fontSmoothing], cl
ret
 
.getFontSize:
xor eax, eax
mov al, [fontSize]
mov [esp + 32], eax
ret
 
.setFontSize:
mov [fontSize], cl
ret
 
.setSkinUnicode:
; in: ecx -> file path string, edx = string encoding
push ecx edx
stdcall kernel_alloc, maxPathLength
mov edi, eax
pop eax esi
push edi
call getFullPath
test eax, eax
jz @f
mov ebx, [esp]
call read_skin_file
mov [esp + 32 + 4], eax
@@:
call kernel_free
call .calculateScreen
jmp .redrawScreen
 
;------------------------------------------------------------------------------
syscall_set_window_shape: ;///// system function 50 ///////////////////////////
;------------------------------------------------------------------------------
;; Set window shape address:
;> ebx = 0
;> ecx = shape data address
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Set window shape scale:
;> ebx = 1
;> ecx = scale power (resulting scale is 2^ebx)
;------------------------------------------------------------------------------
mov edi, [current_slot]
 
test ebx, ebx
jne .shape_scale
mov [edi + APPDATA.wnd_shape], ecx
;--------------------------------------
align 4
.shape_scale:
dec ebx
jnz .exit
mov [edi + APPDATA.wnd_shape_scale], ecx
;--------------------------------------
align 4
.exit:
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
syscall_move_window: ;///// system function 67 ////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
mov edi, [current_slot_idx]
shl edi, 5
add edi, window_data
 
test [edi + WDATA.fl_wdrawn], 1
jz .exit
 
test [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
jnz .exit
 
cmp ebx, -1
jne @f
mov ebx, [edi + WDATA.box.left]
;--------------------------------------
align 4
@@:
cmp ecx, -1
jne @f
mov ecx, [edi + WDATA.box.top]
;--------------------------------------
align 4
@@:
cmp edx, -1
jne @f
mov edx, [edi + WDATA.box.width]
;--------------------------------------
align 4
@@:
cmp esi, -1
jne @f
mov esi, [edi + WDATA.box.height]
;--------------------------------------
align 4
@@:
push esi edx ecx ebx
mov eax, esp
mov bl, [edi + WDATA.fl_wstate]
;--------------------------------------
align 4
@@:
cmp [REDRAW_BACKGROUND], byte 0
jz @f
call change_task
jmp @b
;--------------------------------------
align 4
@@:
call window._.set_window_box
add esp, sizeof.BOX
 
.exit:
ret
;------------------------------------------------------------------------------
syscall_window_settings: ;///// system function 71 ////////////////////////////
;------------------------------------------------------------------------------
mov edi, [current_slot_idx]
shl edi, 5
or [edi + window_data + WDATA.fl_wstyle], WSTYLE_HASCAPTION
cmp ebx, 2
jz @f
xor edx, edx
@@:
cmp dl, 4
jc @f
xor edx, edx
@@:
mov [edi*8 + SLOT_BASE + APPDATA.wnd_caption], ecx
mov [edi*8 + SLOT_BASE + APPDATA.captionEncoding], dl
jmp window._.draw_window_caption
;------------------------------------------------------------------------------
align 4
set_window_defaults: ;/////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
mov byte [window_data + 0x20 + WDATA.cl_titlebar + 3], 1 ; desktop is not movable
push eax ecx
xor eax, eax
mov ecx, WIN_STACK
;--------------------------------------
align 4
@@:
inc eax
add ecx, 2
; process no
mov [ecx + 0x000], ax
; positions in stack
mov [ecx + 0x400], ax
cmp ecx, WIN_POS - 2
jne @b
pop ecx eax
ret
;------------------------------------------------------------------------------
 
align 4
;------------------------------------------------------------------------------
calculatescreen: ;/////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Scan all windows from bottom to top, calling `setscreen` for each one
;? intersecting given screen area
;------------------------------------------------------------------------------
;> eax = left
;> ebx = top
;> ecx = right
;> edx = bottom
;------------------------------------------------------------------------------
push esi
pushfd
cli
 
mov esi, 1
call window._.set_screen
 
push ebp
 
mov ebp, [thread_count]
cmp ebp, 1
jbe .exit
 
push eax ;for num layout
 
push edx ecx ebx eax
 
mov dword[esp+10h], ZPOS_DESKTOP
;--------------------------------------
align 4
.layout:
mov esi, 1 ; = num in window stack
mov ebp, [thread_count]
;--------------------------------------
align 4
.next_window:
movzx edi, word[WIN_POS + esi * 2]
shl edi, 5 ;size of TASKDATA and WDATA = 32 bytes
 
cmp byte [TASK_TABLE + edi + TASKDATA.state], TSTATE_FREE
je .skip_window
 
add edi, window_data
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jnz .skip_window
 
mov eax, [esp+10h]
cmp [edi + WDATA.z_modif], al
jne .skip_window
 
mov eax, [edi + WDATA.box.left]
cmp eax, [esp + RECT.right]
jg .skip_window
mov ebx, [edi + WDATA.box.top]
cmp ebx, [esp + RECT.bottom]
jg .skip_window
mov ecx, [edi + WDATA.box.width]
add ecx, eax
cmp ecx, [esp + RECT.left]
jl .skip_window
mov edx, [edi + WDATA.box.height]
add edx, ebx
cmp edx, [esp + RECT.top]
jl .skip_window
 
cmp eax, [esp + RECT.left]
jae @f
mov eax, [esp + RECT.left]
;--------------------------------------
align 4
@@:
cmp ebx, [esp + RECT.top]
jae @f
mov ebx, [esp + RECT.top]
;--------------------------------------
align 4
@@:
cmp ecx, [esp + RECT.right]
jbe @f
mov ecx, [esp + RECT.right]
;--------------------------------------
align 4
@@:
cmp edx, [esp + RECT.bottom]
jbe @f
mov edx, [esp + RECT.bottom]
;--------------------------------------
align 4
@@:
push esi
movzx esi, word[WIN_POS + esi * 2]
call window._.set_screen
pop esi
;--------------------------------------
align 4
.skip_window:
inc esi
dec ebp
jnz .next_window
;---------------------------------------------
inc dword[esp+10h]
cmp dword[esp+10h], ZPOS_ALWAYS_TOP
jle .layout
;---------------------------------------------
mov esi, [thread_count]
movzx edi, word[WIN_POS + esi * 2]
shl edi, 5
add edi, window_data
 
pop eax ebx ecx edx
pop ebp ;del num layout
;--------------------------------------
align 4
.exit:
pop ebp
inc [_display.mask_seqno]
popfd
pop esi
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
repos_windows: ;///////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
mov ecx, [thread_count]
mov edi, window_data + sizeof.WDATA * 2
call force_redraw_background
dec ecx
jle .exit
;--------------------------------------
align 4
.next_window:
mov [edi + WDATA.fl_redraw], 1
test [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
jnz .fix_maximized
 
mov eax, [edi + WDATA.box.left]
add eax, [edi + WDATA.box.width]
mov ebx, [_display.width]
cmp eax, ebx
jl .fix_vertical
mov eax, [edi + WDATA.box.width]
sub eax, ebx
jl @f
mov [edi + WDATA.box.width], ebx
;--------------------------------------
align 4
@@:
sub ebx, [edi + WDATA.box.width]
mov [edi + WDATA.box.left], ebx
;--------------------------------------
align 4
.fix_vertical:
mov eax, [edi + WDATA.box.top]
add eax, [edi + WDATA.box.height]
mov ebx, [_display.height]
cmp eax, ebx
jl .fix_client_box
mov eax, [edi + WDATA.box.height]
sub eax, ebx
jl @f
mov [edi + WDATA.box.height], ebx
;--------------------------------------
align 4
@@:
sub ebx, [edi + WDATA.box.height]
mov [edi + WDATA.box.top], ebx
;--------------------------------------
align 4
.fix_client_box:
call window._.set_window_clientbox
add edi, sizeof.WDATA
loop .next_window
;--------------------------------------
align 4
.exit:
ret
;--------------------------------------
align 4
.fix_maximized:
mov eax, [screen_workarea.left]
mov [edi + WDATA.box.left], eax
sub eax, [screen_workarea.right]
neg eax
mov [edi + WDATA.box.width], eax
mov eax, [screen_workarea.top]
mov [edi + WDATA.box.top], eax
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
jnz .fix_client_box
sub eax, [screen_workarea.bottom]
neg eax
mov [edi + WDATA.box.height], eax
jmp .fix_client_box
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
draw_rectangle: ;//////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;> eax = pack[16(left), 16(right)]
;> ebx = pack[16(top), 16(bottom)]
;> esi = color
; ?? RR GG BB ; 0x01000000 negation
; ; 0x02000000 used for draw_rectangle without top line
; ; for example drawwindow_III and drawwindow_IV
;------------------------------------------------------------------------------
push eax ebx ecx edi
 
xor edi, edi
;--------------------------------------
align 4
.flags_set:
push ebx
 
; set line color
mov ecx, esi
; draw top border
rol ebx, 16
push ebx
rol ebx, 16
pop bx
test ecx, 1 shl 25
jnz @f
sub ecx, 1 shl 25
; call [draw_line]
call __sys_draw_line
;--------------------------------------
align 4
@@:
; draw bottom border
mov ebx, [esp - 2]
pop bx
; call [draw_line]
call __sys_draw_line
 
pop ebx
add ebx, 1 * 65536 - 1
 
; draw left border
rol eax, 16
push eax
rol eax, 16
pop ax
; call [draw_line]
call __sys_draw_line
 
; draw right border
mov eax, [esp - 2]
pop ax
; call [draw_line]
call __sys_draw_line
 
pop edi ecx ebx eax
ret
;--------------------------------------
align 4
.forced:
push eax ebx ecx edi
xor edi, edi
inc edi
jmp .flags_set
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
drawwindow_I_caption: ;////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
push [edx + WDATA.cl_titlebar]
mov esi, edx
 
mov edx, [esi + WDATA.box.top]
mov eax, edx
lea ebx, [edx + 21]
inc edx
add eax, [esi + WDATA.box.height]
 
cmp ebx, eax
jbe @f
mov ebx, eax
;--------------------------------------
align 4
@@:
push ebx
 
xor edi, edi
;--------------------------------------
align 4
.next_line:
mov ebx, edx
shl ebx, 16
add ebx, edx
mov eax, [esi + WDATA.box.left]
inc eax
shl eax, 16
add eax, [esi + WDATA.box.left]
add eax, [esi + WDATA.box.width]
dec eax
mov ecx, [esi + WDATA.cl_titlebar]
test ecx, 0x80000000
jz @f
sub ecx, 0x00040404
mov [esi + WDATA.cl_titlebar], ecx
;--------------------------------------
align 4
@@:
and ecx, 0x00ffffff
; call [draw_line]
call __sys_draw_line
inc edx
cmp edx, [esp]
jb .next_line
 
add esp, 4
pop [esi + WDATA.cl_titlebar]
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
drawwindow_I: ;////////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
pushad
 
; window border
 
mov eax, [edx + WDATA.box.left - 2]
mov ax, word[edx + WDATA.box.left]
add ax, word[edx + WDATA.box.width]
mov ebx, [edx + WDATA.box.top - 2]
mov bx, word[edx + WDATA.box.top]
add bx, word[edx + WDATA.box.height]
 
mov esi, [edx + WDATA.cl_frames]
call draw_rectangle
 
; window caption
 
call drawwindow_I_caption
 
; window client area
 
; do we need to draw it?
mov edi, [esi + WDATA.cl_workarea]
test edi, 0x40000000
jnz .exit
 
; does client area have a positive size on screen?
cmp [esi + WDATA.box.height], 21
jle .exit
 
; okay, let's draw it
mov eax, 1
mov ebx, 21
mov ecx, [esi + WDATA.box.width]
mov edx, [esi + WDATA.box.height]
; call [drawbar]
call vesa20_drawbar
;--------------------------------------
align 4
.exit:
popad
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
drawwindow_III_caption: ;/////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
mov ecx, [edx + WDATA.cl_titlebar]
push ecx
mov esi, edx
mov edx, [esi + WDATA.box.top]
add edx, 4
mov ebx, [esi + WDATA.box.top]
add ebx, 20
mov eax, [esi + WDATA.box.top]
add eax, [esi + WDATA.box.height]
 
cmp ebx, eax
jb @f
mov ebx, eax
;--------------------------------------
align 4
@@:
push ebx
 
xor edi, edi
;--------------------------------------
align 4
.next_line:
mov ebx, edx
shl ebx, 16
add ebx, edx
mov eax, [esi + WDATA.box.left]
shl eax, 16
add eax, [esi + WDATA.box.left]
add eax, [esi + WDATA.box.width]
add eax, 4 * 65536 - 4
mov ecx, [esi + WDATA.cl_titlebar]
test ecx, 0x40000000
jz @f
add ecx, 0x00040404
;--------------------------------------
align 4
@@:
test ecx, 0x80000000
jz @f
sub ecx, 0x00040404
;--------------------------------------
align 4
@@:
mov [esi + WDATA.cl_titlebar], ecx
and ecx, 0x00ffffff
; call [draw_line]
call __sys_draw_line
inc edx
cmp edx, [esp]
jb .next_line
 
add esp, 4
pop [esi + WDATA.cl_titlebar]
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
drawwindow_III: ;//////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
pushad
 
; window border
 
mov eax, [edx + WDATA.box.left - 2]
mov ax, word[edx + WDATA.box.left]
add ax, word[edx + WDATA.box.width]
mov ebx, [edx + WDATA.box.top - 2]
mov bx, word[edx + WDATA.box.top]
add bx, word[edx + WDATA.box.height]
 
mov esi, [edx + WDATA.cl_frames]
shr esi, 1
and esi, 0x007f7f7f
call draw_rectangle
 
push esi
mov ecx, 3
mov esi, [edx + WDATA.cl_frames]
;--------------------------------------
align 4
.next_frame:
add eax, 1 * 65536 - 1
add ebx, 1 * 65536 - 1
call draw_rectangle
dec ecx
jnz .next_frame
 
pop esi
add eax, 1 * 65536 - 1
add ebx, 1 * 65536 - 1
call draw_rectangle
 
; window caption
 
call drawwindow_III_caption
 
; window client area
 
; do we need to draw it?
mov edi, [esi + WDATA.cl_workarea]
test edi, 0x40000000
jnz .exit
 
; does client area have a positive size on screen?
mov edx, [esi + WDATA.box.top]
add edx, 21 + 5
mov ebx, [esi + WDATA.box.top]
add ebx, [esi + WDATA.box.height]
cmp edx, ebx
jg .exit
 
; okay, let's draw it
mov eax, 5
mov ebx, 20
mov ecx, [esi + WDATA.box.width]
mov edx, [esi + WDATA.box.height]
sub ecx, 4
sub edx, 4
; call [drawbar]
call vesa20_drawbar
;--------------------------------------
align 4
.exit:
popad
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
waredraw: ;////////////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Activate window, redrawing if necessary
;------------------------------------------------------------------------------
push -1
mov eax, [thread_count]
lea eax, [WIN_POS + eax * 2]
cmp eax, esi
pop eax
je .exit
 
; is it overlapped by another window now?
push ecx
call window._.check_window_draw
test ecx, ecx
pop ecx
jz .do_not_draw
 
; yes it is, activate and update screen buffer
call window._.window_activate
 
pushad
mov edi, [thread_count]
movzx esi, word[WIN_POS + edi * 2]
shl esi, 5
add esi, window_data
 
mov eax, [esi + WDATA.box.left]
mov ebx, [esi + WDATA.box.top]
mov ecx, [esi + WDATA.box.width]
mov edx, [esi + WDATA.box.height]
 
add ecx, eax
add edx, ebx
 
mov edi, [thread_count]
movzx esi, word[WIN_POS + edi * 2]
call window._.set_screen
 
call window._.set_top_wnd
 
inc [_display.mask_seqno]
popad
 
; tell application to redraw itself
mov [edi + WDATA.fl_redraw], 1
xor eax, eax
jmp .exit
;--------------------------------------
align 4
.do_not_draw:
; no it's not, just activate the window
call window._.window_activate
xor eax, eax
ret
 
;--------------------------------------
align 4
.exit:
inc eax
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
minimize_all_window:
push ebx ecx edx esi edi
pushfd
cli
xor edx, edx
mov eax, 2 ; we do not minimize the kernel thread N1
mov ebx, [thread_count]
;--------------------------------------
align 4
.loop:
movzx edi, word[WIN_POS + eax * 2]
shl edi, 5
; it is a unused slot?
cmp byte [edi+TASK_TABLE+TASKDATA.state], TSTATE_FREE
je @f
; it is a hidden thread?
lea esi, [edi*8+SLOT_BASE+APPDATA.app_name]
cmp [esi], byte '@'
je @f
; is it already minimized?
test [edi + window_data+WDATA.fl_wstate], WSTATE_MINIMIZED
jnz @f
; no it's not, let's do that
or [edi + window_data+WDATA.fl_wstate], WSTATE_MINIMIZED
inc edx
;--------------------------------------
align 4
@@:
inc eax
cmp eax, ebx
jbe .loop
; If nothing has changed
test edx, edx
jz @f
 
push edx
call syscall_display_settings.calculateScreen
call syscall_display_settings.redrawScreen
pop edx
;--------------------------------------
align 4
@@:
mov eax, edx
popfd
pop edi esi edx ecx ebx
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
minimize_window: ;/////////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;> eax = window number on screen
;------------------------------------------------------------------------------
;# corrupts [dl*]
;------------------------------------------------------------------------------
push edi
pushfd
cli
 
; is it already minimized?
movzx edi, word[WIN_POS + eax * 2]
shl edi, 5
add edi, window_data
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jnz .exit
 
push eax ebx ecx edx esi
 
; no it's not, let's do that
or [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
; If the window width is 0, then the action is not needed.
cmp [edi + WDATA.box.width], dword 0
je @f
; If the window height is 0, then the action is not needed.
cmp [edi + WDATA.box.height], dword 0
je @f
 
mov eax, [edi + WDATA.box.left]
mov [draw_limits.left], eax
mov ecx, eax
add ecx, [edi + WDATA.box.width]
mov [draw_limits.right], ecx
mov ebx, [edi + WDATA.box.top]
mov [draw_limits.top], ebx
mov edx, ebx
add edx, [edi + WDATA.box.height]
mov [draw_limits.bottom], edx
 
; DEBUGF 1, "K : minimize_window\n"
; DEBUGF 1, "K : dl_left %x\n",[draw_limits.left]
; DEBUGF 1, "K : dl_right %x\n",[draw_limits.right]
; DEBUGF 1, "K : dl_top %x\n",[draw_limits.top]
; DEBUGF 1, "K : dl_bottom %x\n",[draw_limits.bottom]
call calculatescreen
; xor esi, esi
; xor eax, eax
mov eax, edi
call redrawscreen
;--------------------------------------
align 4
@@:
pop esi edx ecx ebx eax
;--------------------------------------
align 4
.exit:
popfd
pop edi
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
restore_minimized_window: ;////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;> eax = window number on screen
;------------------------------------------------------------------------------
;# corrupts [dl*]
;------------------------------------------------------------------------------
pushad
pushfd
cli
 
; is it already restored?
movzx esi, word[WIN_POS + eax * 2]
mov edi, esi
shl edi, 5
add edi, window_data
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jz .exit
 
; no it's not, let's do that
mov [edi + WDATA.fl_redraw], 1
and [edi + WDATA.fl_wstate], not WSTATE_MINIMIZED
mov ebp, window._.set_screen
cmp eax, [thread_count]
jz @f
mov ebp, calculatescreen
;--------------------------------------
align 4
@@:
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.top]
mov ecx, [edi + WDATA.box.width]
mov edx, [edi + WDATA.box.height]
add ecx, eax
add edx, ebx
call ebp
 
cmp ebp, window._.set_screen
jne @f
call window._.set_top_wnd
@@:
inc [_display.mask_seqno]
;--------------------------------------
align 4
.exit:
popfd
popad
ret
;------------------------------------------------------------------------------
align 4
; TODO: remove this proc
;------------------------------------------------------------------------------
window_check_events: ;/////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
; do we have window minimize/restore request?
cmp [window_minimize], 0
je .exit
 
; okay, minimize or restore top-most window and exit
mov eax, [thread_count]
mov bl, 0
xchg [window_minimize], bl
dec bl
jnz @f
call minimize_window
jmp .exit
;--------------------------------------
align 4
@@:
call restore_minimized_window
;--------------------------------------
align 4
.exit:
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
sys_window_maximize_handler: ;/////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> esi = process slot
;------------------------------------------------------------------------------
mov edi, esi
shl edi, 5
add edi, window_data
 
; can window change its height?
; only types 2 and 3 can be resized
mov dl, [edi + WDATA.fl_wstyle]
test dl, 2
jz .exit
 
; toggle normal/maximized window state
mov bl, [edi + WDATA.fl_wstate]
xor bl, WSTATE_MAXIMIZED
 
; calculate and set appropriate window bounds
test bl, WSTATE_MAXIMIZED
jz .restore_size
 
mov eax, [screen_workarea.left]
mov ecx, [screen_workarea.top]
push [screen_workarea.bottom] \
[screen_workarea.right] \
ecx \
eax
sub [esp + BOX.width], eax
sub [esp + BOX.height], ecx
mov eax, esp
jmp .set_box
;--------------------------------------
align 4
.restore_size:
mov eax, esi
shl eax, 8
add eax, SLOT_BASE + APPDATA.saved_box
push [eax + BOX.height] \
[eax + BOX.width] \
[eax + BOX.top] \
[eax + BOX.left]
mov eax, esp
;--------------------------------------
align 4
.set_box:
test bl, WSTATE_ROLLEDUP
jz @f
 
xchg eax, ecx
call window._.get_rolledup_height
mov [ecx + BOX.height], eax
xchg eax, ecx
;--------------------------------------
align 4
@@:
call window._.set_window_box
add esp, sizeof.BOX
;--------------------------------------
align 4
.exit:
inc [_display.mask_seqno]
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
sys_window_rollup_handler: ;///////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> esi = process slot
;------------------------------------------------------------------------------
mov edx, esi
shl edx, 8
add edx, SLOT_BASE
 
; toggle normal/rolled up window state
mov bl, [edi + WDATA.fl_wstate]
xor bl, WSTATE_ROLLEDUP
 
; calculate and set appropriate window bounds
test bl, WSTATE_ROLLEDUP
jz .restore_size
 
call window._.get_rolledup_height
push eax \
[edi + WDATA.box.width] \
[edi + WDATA.box.top] \
[edi + WDATA.box.left]
mov eax, esp
jmp .set_box
;--------------------------------------
align 4
.restore_size:
test bl, WSTATE_MAXIMIZED
jnz @f
add esp, -sizeof.BOX
lea eax, [edx + APPDATA.saved_box]
jmp .set_box
;--------------------------------------
align 4
@@:
mov eax, [screen_workarea.top]
push [screen_workarea.bottom] \
[edi + WDATA.box.width] \
eax \
[edi + WDATA.box.left]
sub [esp + BOX.height], eax
mov eax, esp
;--------------------------------------
align 4
.set_box:
call window._.set_window_box
add esp, sizeof.BOX
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
;sys_window_start_moving_handler: ;/////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> eax = old (original) window box
;> esi = process slot
;------------------------------------------------------------------------------
; mov edi, eax
; call window._.draw_negative_box
; ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
sys_window_end_moving_handler: ;///////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> eax = old (original) window box
;> ebx = new (final) window box
;> esi = process slot
;------------------------------------------------------------------------------
; mov edi, ebx
; call window._.end_moving__box
 
mov edi, esi
shl edi, 5
add edi, window_data
 
test [fl_moving], 1
jz @f
 
push edi
mov edi, ebx
call window._.draw_negative_box
pop edi
@@:
 
mov eax, ebx
mov bl, [edi + WDATA.fl_wstate]
call window._.set_window_box
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
sys_window_moving_handler: ;///////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> eax = old (from previous call) window box
;> ebx = new (current) window box
;> esi = process_slot
;------------------------------------------------------------------------------
mov edi, eax
call window._.draw_negative_box
mov edi, ebx
call window._.draw_negative_box
ret
;==============================================================================
;///// private functions //////////////////////////////////////////////////////
;==============================================================================
 
iglobal
align 4
window_topleft dd \
1, 21, \ ;type 0
0, 0, \ ;type 1
5, 20, \ ;type 2
5, ?, \ ;type 3 {set by skin}
5, ? ;type 4 {set by skin}
endg
 
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.invalidate_screen: ;//////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> eax = old (original) window box
;> ebx = new (final) window box
;> edi = pointer to WDATA struct
;------------------------------------------------------------------------------
push eax ebx
 
; TODO: do we really need `draw_limits`?
; Yes, they are used by background drawing code.
 
; we need only to restore the background windows at the old place!
mov ecx, [ebx + BOX.left]
mov [draw_limits.left], ecx
add ecx, [ebx + BOX.width]
mov [draw_limits.right], ecx
mov ecx, [ebx + BOX.top]
mov [draw_limits.top], ecx
add ecx, [ebx + BOX.height]
mov [draw_limits.bottom], ecx
; recalculate screen buffer at old position
push ebx
mov edx, [eax + BOX.height]
mov ecx, [eax + BOX.width]
mov ebx, [eax + BOX.top]
mov eax, [eax + BOX.left]
add ecx, eax
add edx, ebx
call calculatescreen
pop eax
; recalculate screen buffer at new position
mov edx, [eax + BOX.height]
mov ecx, [eax + BOX.width]
mov ebx, [eax + BOX.top]
mov eax, [eax + BOX.left]
add ecx, eax
add edx, ebx
call calculatescreen
 
mov eax, edi
call redrawscreen
 
; tell window to redraw itself
mov [edi + WDATA.fl_redraw], 1
 
pop ebx eax
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.set_window_box: ;/////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> eax = pointer to BOX struct
;> bl = new window state flags
;> edi = pointer to WDATA struct
;------------------------------------------------------------------------------
push eax ebx esi
 
; don't do anything if the new box is identical to the old
cmp bl, [edi + WDATA.fl_wstate]
jnz @f
mov esi, eax
push edi
if WDATA.box
add edi, WDATA.box
end if
mov ecx, 4
repz cmpsd
pop edi
jz .exit
;--------------------------------------
align 4
@@:
add esp, -sizeof.BOX
mov ebx, esp
if WDATA.box
lea esi, [edi + WDATA.box]
else
mov esi, edi ; optimization for WDATA.box = 0
end if
xchg eax, esi
mov ecx, sizeof.BOX
call memmove
xchg eax, esi
xchg ebx, esi
call memmove
mov eax, ebx
mov ebx, esi
call window._.check_window_position
call window._.set_window_clientbox
call window._.invalidate_screen
 
add esp, sizeof.BOX
 
mov cl, [esp + 4]
mov ch, cl
xchg cl, [edi + WDATA.fl_wstate]
 
or cl, ch
test cl, WSTATE_MAXIMIZED
jnz .exit
 
mov eax, edi
sub eax, window_data
shl eax, 3
add eax, SLOT_BASE
 
lea ebx, [edi + WDATA.box]
xchg esp, ebx
 
pop [eax + APPDATA.saved_box.left] \
[eax + APPDATA.saved_box.top] \
[eax + APPDATA.saved_box.width] \
edx
 
xchg esp, ebx
 
test ch, WSTATE_ROLLEDUP
jnz .exit
 
mov [eax + APPDATA.saved_box.height], edx
;--------------------------------------
align 4
.exit:
pop esi ebx eax
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.set_window_clientbox: ;///////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> edi = pointer to WDATA struct
;------------------------------------------------------------------------------
push eax ecx edi
 
mov eax, [_skinh]
mov [window_topleft + 8 * 3 + 4], eax
mov [window_topleft + 8 * 4 + 4], eax
 
mov ecx, edi
sub edi, window_data
shl edi, 3
test [ecx + WDATA.fl_wstyle], WSTYLE_CLIENTRELATIVE
jz .whole_window
 
movzx eax, [ecx + WDATA.fl_wstyle]
and eax, 0x0F
mov eax, [eax * 8 + window_topleft + 0]
mov [edi + SLOT_BASE + APPDATA.wnd_clientbox.left], eax
shl eax, 1
neg eax
add eax, [ecx + WDATA.box.width]
inc eax ;Leency: as window is created width+1 so client the same
mov [edi + SLOT_BASE + APPDATA.wnd_clientbox.width], eax
 
movzx eax, [ecx + WDATA.fl_wstyle]
and eax, 0x0F
push [eax * 8 + window_topleft + 0]
mov eax, [eax * 8 + window_topleft + 4]
mov [edi + SLOT_BASE + APPDATA.wnd_clientbox.top], eax
neg eax
sub eax, [esp]
add eax, [ecx + WDATA.box.height]
inc eax ;Leency: as window is created height+1 so client the same
mov [edi + SLOT_BASE + APPDATA.wnd_clientbox.height], eax
add esp, 4
jmp .exit
;--------------------------------------
align 4
.whole_window:
xor eax, eax
mov [edi + SLOT_BASE + APPDATA.wnd_clientbox.left], eax
mov [edi + SLOT_BASE + APPDATA.wnd_clientbox.top], eax
mov eax, [ecx + WDATA.box.width]
mov [edi + SLOT_BASE + APPDATA.wnd_clientbox.width], eax
mov eax, [ecx + WDATA.box.height]
mov [edi + SLOT_BASE + APPDATA.wnd_clientbox.height], eax
;--------------------------------------
align 4
.exit:
pop edi ecx eax
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.sys_set_window: ;/////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;< edx = pointer to WDATA struct
;------------------------------------------------------------------------------
mov eax, [current_slot_idx]
shl eax, 5
add eax, window_data
; save window colors
mov [eax + WDATA.cl_workarea], edx
mov [eax + WDATA.cl_titlebar], esi
mov [eax + WDATA.cl_frames], edi
mov edi, eax
; Was it already defined before?
test [edi + WDATA.fl_wdrawn], 1
jnz .set_client_box
; No, it wasn't. After first draw_window we need redraw mouse necessarily!
; Otherwise the user can see cursor specified by f.37.5 from another window.
; He will be really unhappy! Usually, he will be enraged!
or [edi + WDATA.fl_wdrawn], 1
mov [redrawmouse_unconditional], 1
call wakeup_osloop
; performing initial window definition
movzx eax, bx
mov [edi + WDATA.box.width], eax
movzx eax, cx
mov [edi + WDATA.box.height], eax
sar ebx, 16
sar ecx, 16
mov [edi + WDATA.box.left], ebx
mov [edi + WDATA.box.top], ecx
 
call window._.check_window_position
 
push ecx edi
 
mov cl, [edi + WDATA.fl_wstyle]
mov eax, [edi + WDATA.cl_frames]
 
sub edi, window_data
shl edi, 3
add edi, SLOT_BASE
 
and cl, 0x0F
cmp cl, 3
je @f
cmp cl, 4
je @f
 
xor eax, eax
;--------------------------------------
align 4
@@:
mov [edi + APPDATA.wnd_caption], eax
 
mov esi, [esp]
add edi, APPDATA.saved_box
movsd
movsd
movsd
movsd
 
pop edi ecx
 
mov esi, [current_slot_idx]
movzx esi, word[WIN_STACK + esi * 2]
lea esi, [WIN_POS + esi * 2]
call waredraw
 
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.top]
mov ecx, [edi + WDATA.box.width]
mov edx, [edi + WDATA.box.height]
add ecx, eax
add edx, ebx
call calculatescreen
 
mov byte[KEY_COUNT], 0 ; empty keyboard buffer
mov byte[BTN_COUNT], 0 ; empty button buffer
;--------------------------------------
align 4
.set_client_box:
; update window client box coordinates
call window._.set_window_clientbox
 
; reset window redraw flag and exit
mov [edi + WDATA.fl_redraw], 0
mov edx, edi
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.check_window_position: ;//////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Check if window is inside screen area
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
push eax ebx ecx edx esi
 
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.top]
mov ecx, [edi + WDATA.box.width]
mov edx, [edi + WDATA.box.height]
 
mov esi, [_display.width]
cmp ecx, esi
jae .fix_width_high
;--------------------------------------
align 4
.check_left:
or eax, eax
jl .fix_left_low
add eax, ecx
cmp eax, esi
jge .fix_left_high
;--------------------------------------
align 4
.check_height:
mov esi, [_display.height]
cmp edx, esi
jae .fix_height_high
;--------------------------------------
align 4
.check_top:
or ebx, ebx
jl .fix_top_low
add ebx, edx
cmp ebx, esi
jge .fix_top_high
;--------------------------------------
align 4
.exit:
pop esi edx ecx ebx eax
ret
;--------------------------------------
align 4
.fix_width_high:
mov ecx, esi
dec ecx
mov [edi + WDATA.box.width], ecx
jmp .check_left
;--------------------------------------
align 4
.fix_left_low:
xor eax, eax
mov [edi + WDATA.box.left], eax
jmp .check_height
;--------------------------------------
align 4
.fix_left_high:
mov eax, esi
sub eax, ecx
dec eax
mov [edi + WDATA.box.left], eax
jmp .check_height
;--------------------------------------
align 4
.fix_height_high:
mov edx, esi
dec edx
mov [edi + WDATA.box.height], edx
jmp .check_top
;--------------------------------------
align 4
.fix_top_low:
xor ebx, ebx
mov [edi + WDATA.box.top], ebx
jmp .exit
;--------------------------------------
align 4
.fix_top_high:
mov ebx, esi
sub ebx, edx
dec ebx
mov [edi + WDATA.box.top], ebx
jmp .exit
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.get_titlebar_height: ;////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
mov al, [edi + WDATA.fl_wstyle]
and al, 0x0f
cmp al, 0x03
jne @f
mov eax, [_skinh]
ret
;--------------------------------------
align 4
@@:
mov eax, 21
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.get_rolledup_height: ;////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
mov al, [edi + WDATA.fl_wstyle]
and al, 0x0f
cmp al, 0x03
jb @f
mov eax, [_skinh]
add eax, 3
ret
;--------------------------------------
align 4
@@:
or al, al
jnz @f
mov eax, 21
ret
;--------------------------------------
align 4
@@:
mov eax, 21 + 2
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.set_screen: ;/////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Reserve window area in screen buffer
;------------------------------------------------------------------------------
;> eax = left
;> ebx = top
;> ecx = right
;> edx = bottom
;> esi = process number
;------------------------------------------------------------------------------
virtual at esp
ff_x dd ?
ff_y dd ?
ff_width dd ?
ff_xsz dd ?
ff_ysz dd ?
ff_scale dd ?
end virtual
 
pushad
 
cmp esi, 1
jz .check_for_shaped_window
mov edi, esi
shl edi, 5
cmp [window_data + edi + WDATA.box.width], 0
jnz .check_for_shaped_window
cmp [window_data + edi + WDATA.box.height], 0
jz .exit
;--------------------------------------
align 4
.check_for_shaped_window:
mov edi, esi
shl edi, 8
add edi, SLOT_BASE
cmp [edi + APPDATA.wnd_shape], 0
jne .shaped_window
 
; get x&y size
sub ecx, eax
sub edx, ebx
inc ecx
inc edx
 
; get WinMap start
push esi
mov esi, [_display.width]
mov edi, [d_width_calc_area + ebx*4]
 
add edi, eax
add edi, [_display.win_map]
pop eax
mov ah, al
push ax
shl eax, 16
pop ax
;--------------------------------------
align 4
.next_line:
push ecx
shr ecx, 2
rep stosd
mov ecx, [esp]
and ecx, 3
rep stosb
pop ecx
add edi, esi
sub edi, ecx
dec edx
jnz .next_line
 
jmp .exit
;--------------------------------------
align 4
.shaped_window:
; for (y=0; y <= x_size; y++)
; for (x=0; x <= x_size; x++)
; if (shape[coord(x,y,scale)]==1)
; set_pixel(x, y, process_number);
 
sub ecx, eax
sub edx, ebx
inc ecx
inc edx
 
push [edi + APPDATA.wnd_shape_scale] ; push scale first -> for loop
 
; get WinMap start -> ebp
push eax
mov eax, [d_width_calc_area + ebx*4]
 
add eax, [esp]
add eax, [_display.win_map]
mov ebp, eax
 
mov edi, [edi + APPDATA.wnd_shape]
pop eax
 
; eax = x_start
; ebx = y_start
; ecx = x_size
; edx = y_size
; esi = process_number
; edi = &shape
; [scale]
push edx ecx ; for loop - x,y size
 
mov ecx, esi
shl ecx, 5
mov edx, [window_data + ecx + WDATA.box.top]
push [window_data + ecx + WDATA.box.width] ; for loop - width
mov ecx, [window_data + ecx + WDATA.box.left]
sub ebx, edx
sub eax, ecx
push ebx eax ; for loop - x,y
 
add [ff_xsz], eax
add [ff_ysz], ebx
 
mov ebx, [ff_y]
;--------------------------------------
align 4
.ff_new_y:
mov edx, [ff_x]
;--------------------------------------
align 4
.ff_new_x:
; -- body --
mov ecx, [ff_scale]
mov eax, [ff_width]
inc eax
shr eax, cl
push ebx edx
shr ebx, cl
shr edx, cl
imul eax, ebx
add eax, edx
pop edx ebx
add eax, edi
call .read_byte
test al, al
jz @f
mov eax, esi
mov [ebp], al
; -- end body --
;--------------------------------------
align 4
@@:
inc ebp
inc edx
cmp edx, [ff_xsz]
jb .ff_new_x
 
sub ebp, [ff_xsz]
add ebp, [ff_x]
add ebp, [_display.width] ; screen.x
inc ebx
cmp ebx, [ff_ysz]
jb .ff_new_y
 
add esp, 24
;--------------------------------------
align 4
.exit:
popad
inc [_display.mask_seqno]
ret
;--------------------------------------
align 4
.read_byte:
; eax - address
; esi - slot
push eax ecx edx esi
xchg eax, esi
lea ecx, [esp + 12]
mov edx, 1
call read_process_memory
pop esi edx ecx eax
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.window_activate: ;////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Activate window
;------------------------------------------------------------------------------
;> esi = pointer to WIN_POS+ window data
;------------------------------------------------------------------------------
push eax ebx
 
; if type of current active window is 3 or 4, it must be redrawn
mov ebx, [thread_count]
 
; DEBUGF 1, "K : thread_count (0x%x)\n", ebx
 
movzx ebx, word[WIN_POS + ebx * 2]
shl ebx, 5
add eax, window_data
mov al, [window_data + ebx + WDATA.fl_wstyle]
and al, 0x0f
cmp al, 0x03
je .set_window_redraw_flag
cmp al, 0x04
jne .move_others_down
;--------------------------------------
align 4
.set_window_redraw_flag:
mov [window_data + ebx + WDATA.fl_redraw], 1
;--------------------------------------
align 4
.move_others_down:
; bx <- process no
movzx ebx, word[esi]
; bx <- position in window stack
movzx ebx, word[WIN_STACK + ebx * 2]
 
; drop others
xor eax, eax
;--------------------------------------
align 4
.next_stack_window:
cmp eax, [thread_count]
jae .move_self_up
inc eax
 
; push ebx
; xor ebx,ebx
; mov bx,[WIN_STACK + eax * 2]
; DEBUGF 1, "K : DEC WIN_STACK (0x%x)\n",ebx
; pop ebx
 
cmp [WIN_STACK + eax * 2], bx
jbe .next_stack_window
dec word[WIN_STACK + eax * 2]
jmp .next_stack_window
;--------------------------------------
align 4
.move_self_up:
movzx ebx, word[esi]
; number of thread
mov ax, word [thread_count]
; this is the last (and the upper)
mov [WIN_STACK + ebx * 2], ax
 
; update on screen - window stack
xor eax, eax
;--------------------------------------
align 4
.next_window_pos:
cmp eax, [thread_count]
jae .reset_vars
inc eax
movzx ebx, word[WIN_STACK + eax * 2]
mov [WIN_POS + ebx * 2], ax
jmp .next_window_pos
;--------------------------------------
align 4
.reset_vars:
mov byte[KEY_COUNT], 0
mov byte[BTN_COUNT], 0
mov word[MOUSE_SCROLL_H], 0
mov word[MOUSE_SCROLL_V], 0
 
pop ebx eax
ret
;------------------------------------------------------------------------------
window._.window_deactivate: ;////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Deactivate window
;------------------------------------------------------------------------------
;> esi = pointer to WIN_POS+ window data
;------------------------------------------------------------------------------
push eax ebx
;--------------------------------------
align 4
.move_others_up:
; ax <- process no
movzx ebx, word[esi]
; ax <- position in window stack
movzx ebx, word[WIN_STACK + ebx * 2]
; up others
xor eax, eax
;--------------------------------------
align 4
.next_stack_window:
cmp eax, [thread_count]
jae .move_self_down
inc eax
cmp [WIN_STACK + eax * 2], bx
jae .next_stack_window
inc word[WIN_STACK + eax * 2]
jmp .next_stack_window
;--------------------------------------
align 4
.move_self_down:
movzx ebx, word[esi]
; this is the last (and the low)
mov [WIN_STACK + ebx * 2], word 1
; update on screen - window stack
xor eax, eax
;--------------------------------------
align 4
.next_window_pos:
cmp eax, [thread_count]
jae .reset_vars
inc eax
movzx ebx, word[WIN_STACK + eax * 2]
mov [WIN_POS + ebx * 2], ax
jmp .next_window_pos
;--------------------------------------
align 4
.reset_vars:
mov byte[KEY_COUNT], 0
mov byte[BTN_COUNT], 0
mov word[MOUSE_SCROLL_H], 0
mov word[MOUSE_SCROLL_V], 0
pop ebx eax
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.check_window_draw: ;//////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Check if window is necessary to draw
;------------------------------------------------------------------------------
;> edi = pointer to WDATA
;------------------------------------------------------------------------------
mov cl, [edi + WDATA.fl_wstyle]
and cl, 0x0f
cmp cl, 3
je .exit.redraw ; window type 3
cmp cl, 4
je .exit.redraw ; window type 4
 
push eax ebx edx esi
 
mov eax, edi
sub eax, window_data
shr eax, 5
 
movzx eax, word[WIN_STACK + eax * 2] ; get value of the curr process
lea esi, [WIN_POS + eax * 2] ; get address of this process at 0xC400
;--------------------------------------
align 4
.next_window:
add esi, 2
 
mov eax, [thread_count]
lea eax, word[WIN_POS + eax * 2] ; number of the upper window
 
cmp esi, eax
ja .exit.no_redraw
 
movzx edx, word[esi]
shl edx, 5 ; size of TASKDATA and WDATA is 32 bytes
cmp byte [TASK_TABLE + edx + TASKDATA.state], TSTATE_FREE
je .next_window
 
mov eax, [edi + WDATA.box.top]
mov ebx, [edi + WDATA.box.height]
add ebx, eax
 
mov ecx, [window_data + edx + WDATA.box.top]
cmp ecx, ebx
jge .next_window
add ecx, [window_data + edx + WDATA.box.height]
cmp eax, ecx
jge .next_window
 
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.width]
add ebx, eax
 
mov ecx, [window_data + edx + WDATA.box.left]
cmp ecx, ebx
jge .next_window
add ecx, [window_data + edx + WDATA.box.width]
cmp eax, ecx
jge .next_window
 
pop esi edx ebx eax
;--------------------------------------
align 4
.exit.redraw:
xor ecx, ecx
inc ecx
ret
;--------------------------------------
align 4
.exit.no_redraw:
pop esi edx ebx eax
xor ecx, ecx
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.draw_window_caption: ;////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description>
;------------------------------------------------------------------------------
xor eax, eax
mov edx, [thread_count]
movzx edx, word[WIN_POS + edx * 2]
cmp edx, [current_slot_idx]
jne @f
inc eax
;--------------------------------------
align 4
@@:
mov edx, [current_slot_idx]
shl edx, 5
add edx, window_data
movzx ebx, [edx + WDATA.fl_wstyle]
and bl, 0x0F
cmp bl, 3
je .draw_caption_style_3
cmp bl, 4
je .draw_caption_style_3
 
jmp .not_style_3
;--------------------------------------
align 4
.draw_caption_style_3:
push edx
call drawwindow_IV_caption
add esp, 4
jmp .2
;--------------------------------------
align 4
.not_style_3:
cmp bl, 2
jne .not_style_2
 
call drawwindow_III_caption
jmp .2
;--------------------------------------
align 4
.not_style_2:
cmp bl, 0
jne .2
 
call drawwindow_I_caption
;--------------------------------------
align 4
.2:
mov edi, [current_slot_idx]
shl edi, 5
test [edi + window_data + WDATA.fl_wstyle], WSTYLE_HASCAPTION
jz .exit
mov edx, [edi * 8 + SLOT_BASE + APPDATA.wnd_caption]
or edx, edx
jz .exit
 
mov ebp, [edi + window_data + WDATA.box.left - 2]
mov bp, word[edi + window_data + WDATA.box.top]
movzx eax, [edi + window_data + WDATA.fl_wstyle]
and al, 0x0F
cmp al, 3
je .skinned
cmp al, 4
je .skinned
 
jmp .not_skinned
;--------------------------------------
align 4
.skinned:
movzx eax, word[edi + window_data + WDATA.box.width]
sub ax, [_skinmargins.left]
sub ax, [_skinmargins.right]
js .exit
mov ebx, dword[_skinmargins.left - 2]
mov bx, word[_skinh]
sub bx, [_skinmargins.bottom]
sub bx, [_skinmargins.top]
sar bx, 1
add bx, [_skinmargins.top]
sub bx, 8
jmp .dodraw
;--------------------------------------
align 4
.not_skinned:
cmp al, 1
je .exit
movzx eax, word[edi + window_data + WDATA.box.width]
sub eax, 16
js .exit
mov ebx, 80002h
.dodraw:
shr eax, 3
mov esi, eax
add ebx, ebp
mov ecx, [common_colours + 16]
mov al, [edi*8 + SLOT_BASE + APPDATA.captionEncoding]
test al, al
jnz @f
mov al, 1
cmp byte [edx], 4
jnc @f
mov al, [edx]
test al, al
jz .exit
inc edx
@@:
shl eax, 28
or ecx, eax
xor edi, edi
stc
call dtext._
.exit:
jmp __sys_draw_pointer
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.draw_negative_box: ;//////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Draw negative box
;------------------------------------------------------------------------------
;> edi = pointer to BOX struct
;------------------------------------------------------------------------------
push eax ebx esi
mov esi, 0x01000000
;--------------------------------------
align 4
.1:
mov eax, [edi + BOX.left - 2]
mov ax, word[edi + BOX.left]
add ax, word[edi + BOX.width]
mov ebx, [edi + BOX.top - 2]
mov bx, word[edi + BOX.top]
add bx, word[edi + BOX.height]
call draw_rectangle.forced
pop esi ebx eax
ret
;------------------------------------------------------------------------------
;align 4
;------------------------------------------------------------------------------
;window._.end_moving__box: ;//////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? Draw positive box
;------------------------------------------------------------------------------
;> edi = pointer to BOX struct
;------------------------------------------------------------------------------
; push eax ebx esi
; xor esi, esi
; jmp window._.draw_negative_box.1
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.get_rect: ;/////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? <description> void __fastcall get_window_rect(struct RECT* rc);
;------------------------------------------------------------------------------
;> ecx = pointer to RECT
;------------------------------------------------------------------------------
mov eax, [TASK_BASE]
 
mov edx, [eax-twdw + WDATA.box.left]
mov [ecx+RECT.left], edx
 
add edx, [eax-twdw + WDATA.box.width]
mov [ecx+RECT.right], edx
 
mov edx, [eax-twdw + WDATA.box.top]
mov [ecx+RECT.top], edx
 
add edx, [eax-twdw + WDATA.box.height]
mov [ecx+RECT.bottom], edx
ret
;------------------------------------------------------------------------------
align 4
;------------------------------------------------------------------------------
window._.redraw_top_wnd: ;////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? redraw all windows one above the window
;------------------------------------------------------------------------------
;> eax = left
;> ebx = top
;> ecx = right
;> edx = bottom
;> esi = process number
;! corrupted edi
;------------------------------------------------------------------------------
push 0
jmp window._.set_top_wnd.go
 
align 4
;------------------------------------------------------------------------------
window._.set_top_wnd: ;////////////////////////////////////////////////////////
;------------------------------------------------------------------------------
;? call set_screen for all windows one above the window
;------------------------------------------------------------------------------
;> eax = left
;> ebx = top
;> ecx = right
;> edx = bottom
;> esi = process number
;! corrupted edi
;------------------------------------------------------------------------------
 
push 1
.go:
push esi
pushfd
cli
 
push ebp
mov ebp, [thread_count]
cmp ebp, 1
jbe .exit
 
shl esi, 5
cmp [esi + window_data + WDATA.z_modif], ZPOS_ALWAYS_TOP
je .exit
 
push eax ;for num layout
push edx ecx ebx eax
 
movsx eax, byte [esi + window_data + WDATA.z_modif]
inc eax
mov dword[esp+10h], eax
;--------------------------------------
align 4
.layout:
mov esi, 1 ; = num in window stack
mov ebp, [thread_count]
;--------------------------------------
align 4
.next_window:
movzx edi, word[WIN_POS + esi * 2]
shl edi, 5 ;size of TASKDATA and WDATA = 32 bytes
 
cmp byte [TASK_TABLE + edi + TASKDATA.state], TSTATE_FREE
je .skip_window
 
add edi, window_data
test [edi + WDATA.fl_wstate], WSTATE_MINIMIZED
jnz .skip_window
 
mov eax, [esp+10h]
cmp [edi + WDATA.z_modif], al
jne .skip_window
 
mov eax, [edi + WDATA.box.left]
cmp eax, [esp + RECT.right]
jg .skip_window
mov ebx, [edi + WDATA.box.top]
cmp ebx, [esp + RECT.bottom]
jg .skip_window
mov ecx, [edi + WDATA.box.width]
add ecx, eax
cmp ecx, [esp + RECT.left]
jl .skip_window
mov edx, [edi + WDATA.box.height]
add edx, ebx
cmp edx, [esp + RECT.top]
jl .skip_window
 
cmp eax, [esp + RECT.left]
jae @f
mov eax, [esp + RECT.left]
;--------------------------------------
align 4
@@:
cmp ebx, [esp + RECT.top]
jae @f
mov ebx, [esp + RECT.top]
;--------------------------------------
align 4
@@:
cmp ecx, [esp + RECT.right]
jbe @f
mov ecx, [esp + RECT.right]
;--------------------------------------
align 4
@@:
cmp edx, [esp + RECT.bottom]
jbe @f
mov edx, [esp + RECT.bottom]
;--------------------------------------
align 4
@@:
cmp dword[esp+32], 0
je .set_fl_redraw
 
push esi
movzx esi, word[WIN_POS + esi * 2]
call window._.set_screen
pop esi
jmp @f
.set_fl_redraw:
mov [edi + WDATA.fl_redraw], 1 ;set redraw flag
@@:
;--------------------------------------
align 4
.skip_window:
inc esi
dec ebp
jnz .next_window
;--------------------------------------
inc dword[esp+10h]
cmp byte[esp+10h], ZPOS_ALWAYS_TOP
jle .layout
;-------------------------------------
 
pop eax ebx ecx edx
pop ebp ;del num layout
;-------------------------------------
align 4
.exit:
 
pop ebp
popfd
pop esi
 
add esp, 4 ;dword for 0/1 - set_screen/fl_redraw
ret
 
 
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/mouse.inc
0,0 → 1,687
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2010-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
include 'mousepointer.inc'
 
;================================
;/////// public functions ///////
;================================
 
mouse.LEFT_BUTTON_FLAG = 0001b
mouse.RIGHT_BUTTON_FLAG = 0010b
mouse.MIDDLE_BUTTON_FLAG = 0100b
 
mouse.BUTTONS_MASK = \
mouse.LEFT_BUTTON_FLAG or \
mouse.RIGHT_BUTTON_FLAG or \
mouse.MIDDLE_BUTTON_FLAG
 
mouse.WINDOW_RESIZE_N_FLAG = 000001b
mouse.WINDOW_RESIZE_W_FLAG = 000010b
mouse.WINDOW_RESIZE_S_FLAG = 000100b
mouse.WINDOW_RESIZE_E_FLAG = 001000b
mouse.WINDOW_MOVE_FLAG = 010000b
 
mouse.WINDOW_RESIZE_SW_FLAG = \
mouse.WINDOW_RESIZE_S_FLAG or \
mouse.WINDOW_RESIZE_W_FLAG
mouse.WINDOW_RESIZE_SE_FLAG = \
mouse.WINDOW_RESIZE_S_FLAG or \
mouse.WINDOW_RESIZE_E_FLAG
 
align 4
;-----------------------------------------------------------------
mouse_check_events:
; Check if mouse buttons state or cursor position has changed
push eax ebx
mov al, [BTN_DOWN]
mov bl, [mouse.state.buttons]
and al, mouse.BUTTONS_MASK
mov cl, al
xchg cl, [mouse.state.buttons]
xor bl, al
push eax ebx
 
; did any mouse button changed its state?
or bl, bl
jz .check_position
 
; yes it did, is that the first button of all pressed down?
or cl, cl
jnz .check_buttons_released
 
; yes it is, activate window user is pointing at, if needed
call mouse._.activate_sys_window_under_cursor
 
; is there any system button under cursor?
call mouse._.find_sys_button_under_cursor
or eax, eax
jz .check_buttons_released
 
; yes there is, activate it and exit
mov [mouse.active_sys_button.pbid], eax
mov [mouse.active_sys_button.coord], ebx
mov cl, [mouse.state.buttons]
mov [mouse.active_sys_button.buttons], cl
call sys_button_activate_handler
jmp .exit
 
.check_buttons_released:
cmp [mouse.state.buttons], 0
jnz .buttons_changed
 
; did we press some button earlier?
cmp [mouse.active_sys_button.pbid], 0
je .buttons_changed
 
; yes we did, deactivate it
xor eax, eax
xchg eax, [mouse.active_sys_button.pbid]
mov ebx, [mouse.active_sys_button.coord]
mov cl, [mouse.active_sys_button.buttons]
push eax ebx
call sys_button_deactivate_handler
pop edx ecx
 
; is the button under cursor the one we deactivated?
call mouse._.find_sys_button_under_cursor
cmp eax, ecx
jne .exit
cmp ebx, edx
jne .exit
 
; yes it is, perform associated action
mov cl, [mouse.active_sys_button.buttons]
call sys_button_perform_handler
jmp .exit
 
.buttons_changed:
test byte[esp], mouse.LEFT_BUTTON_FLAG
jz @f
mov eax, [esp + 4]
call .call_left_button_handler
 
@@:
test byte[esp], mouse.RIGHT_BUTTON_FLAG
jz @f
mov eax, [esp + 4]
call .call_right_button_handler
 
@@:
test byte[esp], mouse.MIDDLE_BUTTON_FLAG
jz .check_position
mov eax, [esp + 4]
call .call_middle_button_handler
 
.check_position:
movzx eax, word[MOUSE_X]
movzx ebx, word[MOUSE_Y]
cmp eax, [mouse.state.pos.x]
jne .position_changed
cmp ebx, [mouse.state.pos.y]
je .exit
 
.position_changed:
xchg eax, [mouse.state.pos.x]
xchg ebx, [mouse.state.pos.y]
 
call mouse._.move_handler
 
.exit:
add esp, 8
pop ebx eax
ret
 
.call_left_button_handler:
test eax, mouse.LEFT_BUTTON_FLAG
jnz mouse._.left_button_press_handler
jmp mouse._.left_button_release_handler
 
.call_right_button_handler:
test eax, mouse.RIGHT_BUTTON_FLAG
jnz mouse._.right_button_press_handler
jmp mouse._.right_button_release_handler
 
.call_middle_button_handler:
test eax, mouse.MIDDLE_BUTTON_FLAG
jnz mouse._.middle_button_press_handler
jmp mouse._.middle_button_release_handler
 
;===============================
;////// private functions //////
;===============================
 
uglobal
mouse.state:
.pos POINT
.buttons db ?
 
; NOTE: since there's no unique and lifetime-constant button identifiers,
; we are using two dwords to identify each of them:
; * pbid - process slot (high 8 bits) and button id (low 24 bits) pack
; * coord - left (high 16 bits) and top (low 16 bits) coordinates pack
align 4
mouse.active_sys_button:
.pbid dd ?
.coord dd ?
.buttons db ?
 
align 4
mouse.active_sys_window:
.pslot dd ?
.old_box BOX
.new_box BOX
.delta POINT
.last_ticks dd ?
.action db ?
endg
 
iglobal
fl_moving db 0
rb 3
endg
 
align 4
;-----------------------------------------------------------------
mouse._.left_button_press_handler:
; Called when left mouse button has been pressed down
bts word [BTN_DOWN], 8
mov eax, [timer_ticks]
mov ebx, eax
xchg ebx, [mouse.active_sys_window.last_ticks]
sub eax, ebx
movzx ebx, [mouse_doubleclick_delay]
cmp eax, ebx
jg @f
bts dword [BTN_DOWN], 24
@@:
test [mouse.state.buttons], not mouse.LEFT_BUTTON_FLAG
jnz .exit
 
call mouse._.find_sys_window_under_cursor
call mouse._.check_sys_window_actions
mov [mouse.active_sys_window.action], al
or eax, eax
jz .exit
 
xchg eax, edx
test dl, mouse.WINDOW_MOVE_FLAG
jz @f
 
bt dword [BTN_DOWN], 24
jnc @f
 
mov [mouse.active_sys_window.last_ticks], 0
call sys_window_maximize_handler
jmp .exit
 
@@:
test [edi + WDATA.fl_wstate], WSTATE_MAXIMIZED
jnz .exit
mov [mouse.active_sys_window.pslot], esi
lea eax, [edi + WDATA.box]
mov ebx, mouse.active_sys_window.old_box
mov ecx, sizeof.BOX
call memmove
mov ebx, mouse.active_sys_window.new_box
call memmove
test edx, mouse.WINDOW_MOVE_FLAG
jz @f
 
call .calculate_n_delta
call .calculate_w_delta
jmp .call_window_handler
 
@@:
test dl, mouse.WINDOW_RESIZE_W_FLAG
jz @f
call .calculate_w_delta
 
@@:
test dl, mouse.WINDOW_RESIZE_S_FLAG
jz @f
call .calculate_s_delta
 
@@:
test dl, mouse.WINDOW_RESIZE_E_FLAG
jz .call_window_handler
call .calculate_e_delta
 
.call_window_handler:
.exit:
ret
 
.calculate_n_delta:
mov eax, [mouse.state.pos.y]
sub eax, [mouse.active_sys_window.old_box.top]
mov [mouse.active_sys_window.delta.y], eax
ret
 
.calculate_w_delta:
mov eax, [mouse.state.pos.x]
sub eax, [mouse.active_sys_window.old_box.left]
mov [mouse.active_sys_window.delta.x], eax
ret
 
.calculate_s_delta:
mov eax, [mouse.active_sys_window.old_box.top]
add eax, [mouse.active_sys_window.old_box.height]
sub eax, [mouse.state.pos.y]
mov [mouse.active_sys_window.delta.y], eax
ret
 
.calculate_e_delta:
mov eax, [mouse.active_sys_window.old_box.left]
add eax, [mouse.active_sys_window.old_box.width]
sub eax, [mouse.state.pos.x]
mov [mouse.active_sys_window.delta.x], eax
ret
 
align 4
;-----------------------------------------------------------------
mouse._.left_button_release_handler:
; Called when left mouse button has been released
bts dword [BTN_DOWN], 16
xor esi, esi
xchg esi, [mouse.active_sys_window.pslot]
or esi, esi
jz .exit
 
mov eax, esi
shl eax, 5
add eax, window_data + WDATA.box
mov ebx, mouse.active_sys_window.old_box
mov ecx, sizeof.BOX
call memmove
 
mov eax, mouse.active_sys_window.old_box
mov ebx, mouse.active_sys_window.new_box
call sys_window_end_moving_handler
 
.exit:
and [mouse.active_sys_window.action], 0
mov [fl_moving], 0
ret
 
mouse._.right_button_press_handler:
bts word [BTN_DOWN], 9
test [mouse.state.buttons], not mouse.RIGHT_BUTTON_FLAG
jnz @f
call mouse._.find_sys_window_under_cursor
call mouse._.check_sys_window_actions
test al, mouse.WINDOW_MOVE_FLAG
jz @f
jmp sys_window_rollup_handler
 
mouse._.right_button_release_handler:
bts dword [BTN_DOWN], 17
@@:
ret
 
mouse._.middle_button_press_handler:
bts word [BTN_DOWN], 10
ret
 
mouse._.middle_button_release_handler:
bts dword [BTN_DOWN], 18
ret
 
align 4
;-----------------------------------------------------------------
mouse._.move_handler:
; Called when cursor has been moved
;> eax = old x coord
;> ebx = old y coord
cmp [mouse.active_sys_button.pbid], 0
jnz .exit
 
mov esi, [mouse.active_sys_window.pslot]
or esi, esi
jz .exit
 
mov eax, mouse.active_sys_window.new_box
mov ebx, mouse.active_sys_window.old_box
mov ecx, sizeof.BOX
call memmove
 
mov dl, [mouse.active_sys_window.action]
test dl, mouse.WINDOW_MOVE_FLAG
jz .check_resize_w
 
mov eax, [mouse.state.pos.x]
sub eax, [mouse.active_sys_window.delta.x]
mov [mouse.active_sys_window.new_box.left], eax
mov eax, [mouse.state.pos.y]
sub eax, [mouse.active_sys_window.delta.y]
mov [mouse.active_sys_window.new_box.top], eax
 
mov eax, [mouse.active_sys_window.new_box.left]
or eax, eax
jge @f
xor eax, eax
mov [mouse.active_sys_window.new_box.left], eax
@@:
add eax, [mouse.active_sys_window.new_box.width]
cmp eax, [_display.width]
jl @f
sub eax, [_display.width]
inc eax
sub [mouse.active_sys_window.new_box.left], eax
@@:
mov eax, [mouse.active_sys_window.new_box.top]
or eax, eax
jge @f
xor eax, eax
mov [mouse.active_sys_window.new_box.top], eax
@@:
add eax, [mouse.active_sys_window.new_box.height]
cmp eax, [_display.height]
jl .call_window_handler
sub eax, [_display.height]
inc eax
sub [mouse.active_sys_window.new_box.top], eax
jmp .call_window_handler
 
.check_resize_w:
test dl, mouse.WINDOW_RESIZE_W_FLAG
jz .check_resize_s
 
mov eax, [mouse.state.pos.x]
sub eax, [mouse.active_sys_window.delta.x]
mov [mouse.active_sys_window.new_box.left], eax
sub eax, [mouse.active_sys_window.old_box.left]
sub [mouse.active_sys_window.new_box.width], eax
 
mov eax, [mouse.active_sys_window.new_box.width]
sub eax, 127
jge @f
add [mouse.active_sys_window.new_box.left], eax
mov [mouse.active_sys_window.new_box.width], 127
@@:
mov eax, [mouse.active_sys_window.new_box.left]
or eax, eax
jge .check_resize_s
add [mouse.active_sys_window.new_box.width], eax
xor eax, eax
mov [mouse.active_sys_window.new_box.left], eax
 
.check_resize_s:
test dl, mouse.WINDOW_RESIZE_S_FLAG
jz .check_resize_e
 
mov eax, [mouse.state.pos.y]
add eax, [mouse.active_sys_window.delta.y]
sub eax, [mouse.active_sys_window.old_box.top]
mov [mouse.active_sys_window.new_box.height], eax
 
push eax
mov edi, esi
shl edi, 5
add edi, window_data
call window._.get_rolledup_height
mov ecx, eax
pop eax
mov eax, [mouse.active_sys_window.new_box.height]
cmp eax, ecx
jge @f
mov eax, ecx
mov [mouse.active_sys_window.new_box.height], eax
@@:
add eax, [mouse.active_sys_window.new_box.top]
cmp eax, [_display.height]
jl .check_resize_e
sub eax, [_display.height]
neg eax
add [mouse.active_sys_window.new_box.height], eax
mov ecx, [_display.height]
cmp ecx, eax
jg .check_resize_e
mov [mouse.active_sys_window.new_box.height], ecx
 
.check_resize_e:
test dl, mouse.WINDOW_RESIZE_E_FLAG
jz .call_window_handler
 
mov eax, [mouse.state.pos.x]
add eax, [mouse.active_sys_window.delta.x]
sub eax, [mouse.active_sys_window.old_box.left]
mov [mouse.active_sys_window.new_box.width], eax
 
mov eax, [mouse.active_sys_window.new_box.width]
cmp eax, 127
jge @f
mov eax, 127
mov [mouse.active_sys_window.new_box.width], eax
@@:
add eax, [mouse.active_sys_window.new_box.left]
cmp eax, [_display.width]
jl .call_window_handler
sub eax, [_display.width]
neg eax
add [mouse.active_sys_window.new_box.width], eax
mov ecx, [_display.width]
cmp ecx, eax
jg .call_window_handler
mov [mouse.active_sys_window.new_box.width], ecx
 
.call_window_handler:
mov eax, mouse.active_sys_window.old_box
mov ebx, mouse.active_sys_window.new_box
 
push esi
mov esi, mouse.active_sys_window.old_box
mov edi, mouse.active_sys_window.new_box
mov ecx, sizeof.BOX / 4
repe
cmpsd
pop esi
je .exit
 
test [fl_moving], 1
jnz @f
 
mov [fl_moving], 1
push edi
mov edi, esi
shl edi, 5
add edi, WDATA.box + window_data
call window._.draw_negative_box
pop edi
@@:
 
 
mov [mouse.active_sys_window.last_ticks], 0
call sys_window_moving_handler
 
.exit:
ret
 
align 4
;-----------------------------------------------------------------
mouse._.find_sys_window_under_cursor:
; Find system window object which is currently visible on screen
; and has mouse cursor within its bounds
;< esi = process slot
;< edi = pointer to WDATA struct
mov esi, [mouse.state.pos.y]
mov esi, [d_width_calc_area + esi*4]
 
add esi, [_display.win_map]
add esi, [mouse.state.pos.x]
movzx esi, byte[esi]
mov edi, esi
shl edi, 5
add edi, window_data
ret
 
align 4
;-----------------------------------------------------------------
mouse._.activate_sys_window_under_cursor:
; activate and redraw window under cursor (if necessary)
call mouse._.find_sys_window_under_cursor
movzx esi, word[WIN_STACK + esi * 2]
lea esi, [WIN_POS + esi * 2]
jmp waredraw
 
align 4
;-----------------------------------------------------------------
mouse._.find_sys_button_under_cursor:
; Find system button object which is currently visible on screen
; and has mouse cursor within its bounds
;< eax = pack[8(process slot), 24(button id)] or 0
;< ebx = pack[16(button x coord), 16(button y coord)]
push ecx edx esi edi
 
call mouse._.find_sys_window_under_cursor
mov edx, esi
 
; check if any process button contains cursor
mov eax, [BTN_ADDR]
mov ecx, [eax]
imul esi, ecx, sizeof.SYS_BUTTON
add esi, eax
inc ecx
add esi, sizeof.SYS_BUTTON
 
.next_button:
dec ecx
jz .not_found
 
add esi, -sizeof.SYS_BUTTON
 
; does it belong to our process?
cmp dx, [esi + SYS_BUTTON.pslot]
jne .next_button
 
; does it contain cursor coordinates?
mov eax, [mouse.state.pos.x]
sub eax, [edi + WDATA.box.left]
sub ax, [esi + SYS_BUTTON.left]
jl .next_button
sub ax, [esi + SYS_BUTTON.width]
jge .next_button
mov eax, [mouse.state.pos.y]
sub eax, [edi + WDATA.box.top]
sub ax, [esi + SYS_BUTTON.top]
jl .next_button
sub ax, [esi + SYS_BUTTON.height]
jge .next_button
 
; okay, return it
shl edx, 24
mov eax, dword[esi + SYS_BUTTON.id_hi - 2]
mov ax, [esi + SYS_BUTTON.id_lo]
and eax, 0x0ffffff
or eax, edx
mov ebx, dword[esi + SYS_BUTTON.left - 2]
mov bx, [esi + SYS_BUTTON.top]
jmp .exit
 
.not_found:
xor eax, eax
xor ebx, ebx
 
.exit:
pop edi esi edx ecx
ret
 
align 4
;-----------------------------------------------------------------
mouse._.check_sys_window_actions:
;< eax = action flags or 0
; is window movable?
test byte[edi + WDATA.cl_titlebar + 3], 0x01
jnz .no_action
 
mov eax, [mouse.state.pos.x]
mov ebx, [mouse.state.pos.y]
sub eax, [edi + WDATA.box.left]
sub ebx, [edi + WDATA.box.top]
 
; is there a window titlebar under cursor?
push eax
call window._.get_titlebar_height
cmp ebx, eax
pop eax
jl .move_action
 
; no there isn't, can it be resized then?
mov dl, [edi + WDATA.fl_wstyle]
and dl, 0x0f
; NOTE: dangerous optimization, revise if window types changed
; this currently implies only types 2 and 3 could be resized
test dl, 2
jz .no_action
 
mov ecx, [edi + WDATA.box.width]
add ecx, -window.BORDER_SIZE
mov edx, [edi + WDATA.box.height]
add edx, -window.BORDER_SIZE
 
; is it rolled up?
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
jnz .resize_w_or_e_action
 
cmp eax, window.BORDER_SIZE
jl .resize_w_action
cmp eax, ecx
jg .resize_e_action
cmp ebx, edx
jle .no_action
 
.resize_s_action:
cmp eax, window.BORDER_SIZE + 10
jl .resize_sw_action
add ecx, -10
cmp eax, ecx
jge .resize_se_action
mov eax, mouse.WINDOW_RESIZE_S_FLAG
jmp .exit
 
.resize_w_or_e_action:
cmp eax, window.BORDER_SIZE + 10
jl .resize_w_action.direct
add ecx, -10
cmp eax, ecx
jg .resize_e_action.direct
jmp .no_action
 
.resize_w_action:
add edx, -10
cmp ebx, edx
jge .resize_sw_action
.resize_w_action.direct:
mov eax, mouse.WINDOW_RESIZE_W_FLAG
jmp .exit
 
.resize_e_action:
add edx, -10
cmp ebx, edx
jge .resize_se_action
.resize_e_action.direct:
mov eax, mouse.WINDOW_RESIZE_E_FLAG
jmp .exit
 
.resize_sw_action:
mov eax, mouse.WINDOW_RESIZE_SW_FLAG
jmp .exit
 
.resize_se_action:
mov eax, mouse.WINDOW_RESIZE_SE_FLAG
jmp .exit
 
.move_action:
mov eax, mouse.WINDOW_MOVE_FLAG
jmp .exit
 
.no_action:
xor eax, eax
 
.exit:
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/button.inc
0,0 → 1,346
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
button.MAX_BUTTONS = 4095
 
struct SYS_BUTTON
pslot dw ?
id_lo dw ?
left dw ?
width dw ?
top dw ?
height dw ?
id_hi dw ?
dw ?
ends
 
;---------------------------------------------------------------
syscall_button: ;////////////// system function 8 //////////////
;---------------------------------------------------------------
;? Define/undefine GUI button object
;---------------------------------------------------------------
;; Define button:
;> ebx = pack[16(x), 16(width)]
;> ecx = pack[16(y), 16(height)]
;> edx = pack[8(flags), 24(button identifier)]
;> flags bits:
;> 7 (31) = 0
;> 6 (30) = don't draw button
;> 5 (29) = don't draw button frame when pressed
;> esi = button color
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;; Undefine button:
;> edx = pack[8(flags), 24(button identifier)]
;> flags bits:
;> 7 (31) = 1
;---------------------------------------------------------------
; do we actually need to undefine the button?
test edx, 0x80000000
jnz .remove_button
 
; do we have free button slots available?
mov edi, [BTN_ADDR]
mov eax, [edi]
cmp eax, button.MAX_BUTTONS
jge .exit
 
; does it have positive size? (otherwise it doesn't have sense)
or bx, bx
jle .exit
or cx, cx
jle .exit
 
; make coordinates clientbox-relative
push eax
mov eax, [current_slot]
rol ebx, 16
add bx, word[eax + APPDATA.wnd_clientbox.left]
rol ebx, 16
rol ecx, 16
add cx, word[eax + APPDATA.wnd_clientbox.top]
rol ecx, 16
pop eax
 
; basic checks passed, define the button
inc eax
mov [edi], ax
shl eax, 4
add edi, eax
; NOTE: this code doesn't rely on SYS_BUTTON struct,
; please revise it, if you change something.
mov ax, word [current_slot_idx]
stosw
mov ax, dx
stosw ; button id number: bits 0-15
mov eax, ebx
rol eax, 16
stosd ; x start | x size
mov eax, ecx
rol eax, 16
stosd ; y start | y size
mov eax, edx
shr eax, 16
stosw ; button id number: bits 16-31
 
; do we also need to draw the button?
test edx, 0x40000000
jnz .exit
 
and esi, 0xFFFFFF
xor edi, edi
push ebx ecx esi
dec cx
dec cx
cmp [buttontype], 1
jnz .draw
cmp cx, 65
jnc .draw
 
; calculate gradient data
mov eax, esi
shl eax, 8
mov edx, 3
.calculate:
rol eax, 8
shl al, 1
jnc @f
neg al
jnz @f
mov al, 64
@@:
cmp al, 65
jc @f
mov al, 64
@@:
div cl
shl ax, 8
dec edx
jnz .calculate
mov dl, cl
dec edx
shr edx, 1
shr eax, 8
mov edi, eax
mul edx
add esi, eax
 
.draw: ; calculate window-relative coordinates
movzx ebp, cx
dec ebp
shr ebx, 16
shr ecx, 16
mov eax, [TASK_BASE]
add ebx, [eax - twdw + WDATA.box.left]
add ecx, [eax - twdw + WDATA.box.top]
mov eax, ebx
inc eax
mov edx, ebx
add dx, [esp+8]
dec edx
mov ebx, ecx
mov ecx, esi
shr ecx, 1
and cx, 7F7Fh
push esi
mov esi, edi
xor edi, edi
call hline ; top border
inc ebx
or ecx, 808080h
call hline ; top light line
pop ecx
inc ebx
.next_line:
call hline ; button body
inc ebx
sub ecx, esi
dec ebp
jnz .next_line
shr ecx, 2
and cx, 3F3Fh
mov ebp, ecx
shl ecx, 1
add ecx, ebp
call hline ; bottom dark line
inc ebx
sub ecx, ebp
call hline ; bottom border
pop ecx
shr ecx, 1
inc edx
push edx
mov edx, ebx
sub bx, [esp+4]
dec edx
inc ebx
cmp [buttontype], 0
jnz @f
dec edx
or ecx, 808080h
call vline ; left light line
inc edx
@@:
and ecx, 7F7F7Fh
dec eax
call vline ; left border
pop eax
call vline ; right border
cmp [buttontype], 0
jnz @f
mov ebp, ecx
shr ecx, 1
and cx, 7F7Fh
add ecx, ebp
dec eax
inc ebx
dec edx ; avoid lines overflow
call vline ; right dark line
@@:
pop ecx ebx
.exit:
ret
 
; FIXME: mutex needed
.remove_button:
and edx, 0x00ffffff
mov edi, [BTN_ADDR]
mov ebx, [edi]
inc ebx
imul esi, ebx, sizeof.SYS_BUTTON
add esi, edi
xor ecx, ecx
add ecx, -sizeof.SYS_BUTTON
add esi, sizeof.SYS_BUTTON
 
.next_button:
dec ebx
jz .exit
 
add ecx, sizeof.SYS_BUTTON
add esi, -sizeof.SYS_BUTTON
 
; does it belong to our process?
mov ax, word [current_slot_idx]
cmp ax, [esi + SYS_BUTTON.pslot]
jne .next_button
 
; does the identifier match?
mov eax, dword[esi + SYS_BUTTON.id_hi - 2]
mov ax, [esi + SYS_BUTTON.id_lo]
and eax, 0x00ffffff
cmp edx, eax
jne .next_button
 
; okay, undefine it
push ebx
mov ebx, esi
lea eax, [esi + sizeof.SYS_BUTTON]
call memmove
dec dword[edi]
add ecx, -sizeof.SYS_BUTTON
pop ebx
jmp .next_button
 
;---------------------------------------------------------------
sys_button_activate_handler:
sys_button_deactivate_handler:
;---------------------------------------------------------------
;> eax = pack[8(process slot), 24(button id)]
;> ebx = pack[16(button x coord), 16(button y coord)]
;> cl = mouse button mask this system button was pressed with
;---------------------------------------------------------------
; find system button by specified process slot, id and coordinates
push ecx edx esi edi
mov edx, eax
shr edx, 24
and eax, 0x0ffffff
mov edi, [BTN_ADDR]
mov ecx, [edi]
imul esi, ecx, sizeof.SYS_BUTTON
add esi, edi
inc ecx
add esi, sizeof.SYS_BUTTON
.next_button:
dec ecx
jz .popexit
add esi, -sizeof.SYS_BUTTON
 
; does it belong to our process?
cmp dx, [esi + SYS_BUTTON.pslot]
jne .next_button
 
; does id match?
mov edi, dword[esi + SYS_BUTTON.id_hi - 2]
mov di, [esi + SYS_BUTTON.id_lo]
and edi, 0x0ffffff
cmp eax, edi
jne .next_button
 
; does coordinates match?
mov edi, dword[esi + SYS_BUTTON.left - 2]
mov di, [esi + SYS_BUTTON.top]
cmp ebx, edi
jne .next_button
 
mov eax, esi
pop edi esi edx ecx
mov ebx, dword[eax + SYS_BUTTON.id_hi - 2]
 
; display button border on press?
bt ebx, 29
jc .exit
 
; invert system button border
pushad
mov esi, eax
mov edi, ebx
movzx ecx, [esi + SYS_BUTTON.pslot]
shl ecx, 5
add ecx, window_data
mov eax, dword[esi + SYS_BUTTON.left]
mov ebx, dword[esi + SYS_BUTTON.top]
add eax, [ecx + WDATA.box.left]
add ebx, [ecx + WDATA.box.top]
mov ecx, eax
mov edx, ebx
bt edi, 30
jc @f
inc ax
inc bx
dec cx
dec dx
@@:
rol eax, 16
rol ebx, 16
add ax, cx
add bx, dx
mov esi, 1000000h
call draw_rectangle.forced
popad
.exit:
ret
.popexit:
pop edi esi edx ecx
ret
 
;---------------------------------------------------------------
sys_button_perform_handler:
;---------------------------------------------------------------
;> eax = pack[8(process slot), 24(button id)]
;> ebx = pack[16(button x coord), 16(button y coord)]
;> cl = mouse button mask this system button was pressed with
;---------------------------------------------------------------
shl eax, 8
mov al, cl
movzx ebx, byte[BTN_COUNT]
mov [BTN_BUFF + ebx * 4], eax
inc bl
mov [BTN_COUNT], bl
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/event.inc
0,0 → 1,622
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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$
 
WINDOW_MOVE_AND_RESIZE_FLAGS = \
mouse.WINDOW_RESIZE_N_FLAG + \
mouse.WINDOW_RESIZE_W_FLAG + \
mouse.WINDOW_RESIZE_S_FLAG + \
mouse.WINDOW_RESIZE_E_FLAG + \
mouse.WINDOW_MOVE_FLAG
 
uglobal
align 4
event_start dd ?
event_end dd ?
event_uid dd 0
endg
EV_SPACE = 512
FreeEvents = event_start-EVENT.fd ; "virtual" event, only following field used:
; FreeEvents.fd=event_start and FreeEvents.bk=event_end
;-----------------------------------------------------------------------------
align 4
init_events: ;; used from kernel.asm
stdcall kernel_alloc, EV_SPACE*sizeof.EVENT
or eax, eax
jz .fail
; eax - current event, ebx - previous event below
mov ecx, EV_SPACE ; current - in allocated space
mov ebx, FreeEvents ; previous - list beginning
push ebx ; it will be the end later
;--------------------------------------
align 4
@@:
mov [ebx+EVENT.fd], eax
mov [eax+EVENT.bk], ebx
mov ebx, eax ; previos <- current
add eax, sizeof.EVENT ; new current
loop @b
pop eax ; here it became the end
mov [ebx+EVENT.fd], eax
mov [eax+EVENT.bk], ebx
;--------------------------------------
align 4
.fail:
ret
;-----------------------------------------------------------------------------
EVENT_WATCHED = 0x10000000 ; bit 28
EVENT_SIGNALED = 0x20000000 ; bit 29
MANUAL_RESET = 0x40000000 ; bit 30
MANUAL_DESTROY = 0x80000000 ; bit 31
;-----------------------------------------------------------------------------
align 4
create_event: ;; EXPORT use
;info:
; Move EVENT from the FreeEvents list to the ObjList list of the current slot;
; EVENT.state is set from ecx, EVENT.code indirectly from esi (if esi <> 0)
;param:
; esi - event data
; ecx - flags
;retval:
; eax - event (=0 => fail)
; edx - uid
;scratched: ebx,ecx,esi,edi
mov ebx, [current_slot]
add ebx, APP_OBJ_OFFSET
mov edx, [TASK_BASE]
mov edx, [edx+TASKDATA.pid]
pushfd
cli
;--------------------------------------
align 4
set_event: ;; INTERNAL use !!! don't use for Call
;info:
; We take a new event from FreeEvents, fill its fields from ecx, edx, esi
; and add it to the list, which specified in ebx.
; Return event (to eax), and it's uid (to edx)
;param:
; ebx - start-chain "virtual" event for entry new event Right of him
; ecx - flags (copied to EVENT.state)
; edx - pid (copied to EVENT.pid)
; esi - event data (copied to EVENT.code indirect, =0 => skip)
;retval:
; eax - event (=0 => fail)
; edx - uid
;scratched: ebx,ecx,esi,edi
mov eax, FreeEvents
cmp eax, [eax+EVENT.fd]
jne @f ; not empty ???
pushad
call init_events
popad
jz RemoveEventTo.break ; POPF+RET
;--------------------------------------
align 4
@@:
mov eax, [eax+EVENT.fd]
mov [eax+EVENT.magic], 'EVNT'
mov [eax+EVENT.destroy], destroy_event.internal
mov [eax+EVENT.state], ecx
mov [eax+EVENT.pid], edx
inc [event_uid]
mov edx, [event_uid]
mov [eax+EVENT.id], edx
or esi, esi
jz RemoveEventTo
lea edi, [eax+EVENT.code]
mov ecx, (sizeof.EVENT -EVENT.code)/4
cld
rep movsd
;--------------------------------------
align 4
RemoveEventTo: ;; INTERNAL use !!! don't use for Call
;param:
; eax - pointer to event, WHICH we will insert
; ebx - pointer to event, AFTER which we will insert
;scratched: ebx,ecx
mov ecx, eax ; ecx=eax=Self, ebx=NewLeft
xchg ecx, [ebx+EVENT.fd] ; NewLeft.fd=Self, ecx=NewRight
cmp eax, ecx ; stop, I think...
je .break ; - am I not a fool?
mov [ecx+EVENT.bk], eax ; NewRight.bk=Self
xchg ebx, [eax+EVENT.bk] ; Self.bk=NewLeft, ebx=OldLeft
xchg ecx, [eax+EVENT.fd] ; Self.fd=NewRight, ecx=OldRight
mov [ebx+EVENT.fd], ecx ; OldLeft.fd=OldRight
mov [ecx+EVENT.bk], ebx ; OldRight.bk=OldLeft
;--------------------------------------
align 4
.break:
popfd
ret
;-----------------------------------------------------------------------------
align 4
NotDummyTest: ;; INTERNAL use (not returned for fail !!!)
pop edi
call DummyTest ; not returned for fail !!!
mov ebx, eax
mov eax, [ebx+EVENT.pid]
push edi
;--------------------------------------
align 4
.small: ; somehow ugly...
pop edi
pushfd
cli
call pid_to_slot ; saved all registers (eax - retval)
shl eax, 8
jz RemoveEventTo.break ; POPF+RET
jmp edi ; normal return
;-----------------------------------------------------------------------------
align 4
raise_event: ;; EXPORT use
;info:
; Setting up EVENT.code data
; If is has flag EVENT_SIGNALED activated - nothing else
; Otherwise: activate this flag, except when the EVENT_WATCHED flag is present in edx
; In this case EVENT_SIGNALED will activated only if EVENT_WATCHED presents in the event itself
;param:
; eax - event
; ebx - uid (for Dummy testing)
; edx - flags
; esi - event data (=0 => skip)
;scratched: ebx,ecx,esi,edi
call NotDummyTest ; not returned for fail !!!
or esi, esi
jz @f
lea edi, [ebx+EVENT.code]
mov ecx, (sizeof.EVENT -EVENT.code)/4
cld
rep movsd
;--------------------------------------
align 4
@@:
test byte[ebx+EVENT.state+3], EVENT_SIGNALED shr 24
jnz RemoveEventTo.break ; POPF+RET
bt edx, 28 ;EVENT_WATCHED
jnc @f
test byte[ebx+EVENT.state+3], EVENT_WATCHED shr 24
jz RemoveEventTo.break ; POPF+RET
;--------------------------------------
align 4
@@:
or byte[ebx+EVENT.state+3], EVENT_SIGNALED shr 24
add eax, SLOT_BASE+APP_EV_OFFSET
xchg eax, ebx
jmp RemoveEventTo
;-----------------------------------------------------------------------------
align 4
clear_event: ;; EXPORT use
;info:
;
;param:
; eax - event
; ebx - uid (for Dummy testing)
;scratched: ebx,ecx
call NotDummyTest ; not returned for fail !!!
add eax, SLOT_BASE+APP_OBJ_OFFSET
and byte[ebx+EVENT.state+3], not((EVENT_SIGNALED+EVENT_WATCHED)shr 24)
xchg eax, ebx
jmp RemoveEventTo
;-----------------------------------------------------------------------------
align 4
send_event: ;; EXPORT use
;info:
; Creates a new EVENT (pulls from the FreeEvents list) in the EventList list
; of target slot (eax=pid), with data from esi indirectly, and state=EVENT_SIGNALED
;param:
; eax - slots pid, to sending new event
; esi - pointer to sending data (in code field of new event)
;retval:
; eax - event (=0 => fail)
; edx - uid
;warning:
; may be used as CDECL with such prefix...
; mov esi,[esp+8]
; mov eax,[esp+4]
; but not as STDCALL :(
;scratched: ebx,ecx,esi,edi
mov edx, eax
call NotDummyTest.small ; not returned for fail !!!
lea ebx, [eax+SLOT_BASE+APP_EV_OFFSET]
mov ecx, EVENT_SIGNALED
jmp set_event
;-----------------------------------------------------------------------------
align 4
DummyTest: ;; INTERNAL use (not returned for fail !!!)
;param:
; eax - event
; ebx - uid (for Dummy testing)
cmp [eax+EVENT.magic], 'EVNT'
jne @f
cmp [eax+EVENT.id], ebx
je .ret
;--------------------------------------
align 4
@@:
pop eax
xor eax, eax
;--------------------------------------
align 4
.ret:
ret
;-----------------------------------------------------------------------------
align 4
Wait_events:
or ebx, -1; infinite timeout
;--------------------------------------
align 4
Wait_events_ex:
;info:
; Waiting for an "abstract" event by moving the slot to the 5th position.
; Abstractness lies in the fact, that the fact of an event is determined by the APPDATA.wait_test function,
; which is set by the client and can be actually anything.
; This allows the shed to reliably determine the fact of the event, and not make "idle" switches,
; intended for showdowns like "friend / foe" within the problem.
;param:
; edx - wait_test, client testing function (code address)
; ecx - wait_param, additional parameter, possibly needed for [wait_test]
; ebx - wait_timeout
;retval:
; eax - call result [wait_test] (=0 => timeout)
;scratched: esi
mov esi, [current_slot]
mov [esi+APPDATA.wait_param], ecx
pushad
mov ebx, esi ;now this is a question, what where to put..........
pushfd ; this is a consequence of the general concept: let the test function have
cli ; the right to hope to disable interrupts, as when called from shed
call edx
popfd
mov [esp+28], eax
popad
or eax, eax
jnz @f ;RET
mov [esi+APPDATA.wait_test], edx
mov [esi+APPDATA.wait_timeout], ebx
mov eax, [timer_ticks]
mov [esi+APPDATA.wait_begin], eax
mov eax, [TASK_BASE]
mov [eax+TASKDATA.state], TSTATE_WAITING
call change_task
mov eax, [esi+APPDATA.wait_param]
;--------------------------------------
align 4
@@:
ret
;-----------------------------------------------------------------------------
align 4
wait_event: ;; EXPORT use
;info:
; Waiting for the EVENT_SIGNALED flag in a very specific Event
; (set, presumably, via raise_event)
; When the MANUAL_RESET flag is active, nothing else
; Otherwise: the flags EVENT_SIGNALED and EVENT_WATCHED for the received event are cleared,
; and, if MANUAL_DESTROY is active, it moves to the ObjList list of the current slot,
; and if not active, it is destroyed normally (destroy_event.internal)
;param:
; eax - event
; ebx - uid (for Dummy testing)
;scratched: ecx,edx,esi
call DummyTest
mov ecx, eax ; wait_param
mov edx, get_event_alone ; wait_test
call Wait_events ; timeout ignored
jmp wait_finish
;-----------------------------------------------------------------------------
align 4
wait_event_timeout:
;param:
; eax - event
; ebx - uid (for Dummy testing)
; ecx - timeout in timer ticks
;retval:
; eax - EVENT handle or 0 if timeout
call DummyTest
mov ebx, ecx
mov ecx, eax ; wait_param
mov edx, get_event_alone ; wait_test
call Wait_events_ex
test eax, eax
jnz wait_finish
ret
;-----------------------------------------------------------------------------
align 4
get_event_ex: ;; f68:14
;info:
; Waiting for any event in the EventList of the current slot
; Code event data - copied to application memory (indirectly by edi)
; When the MANUAL_RESET flag is active, nothing else
; Otherwise: the flags EVENT_SIGNALED and EVENT_WATCHED for the received event are cleared,
; and, if MANUAL_DESTROY is active, it moves to the ObjList list of the current slot,
; and if not active, it is destroyed normally (destroy_event.internal)
;param:
; edi - address in the application code to copy data from EVENT.code
;retval:
; eax - EVENT itself (we will call it a handle)
;scratched: ebx,ecx,edx,esi,edi
mov edx, get_event_queue ; wait_test
call Wait_events ; timeout ignored
lea esi, [eax+EVENT.code]
mov ecx, (sizeof.EVENT-EVENT.code)/4
cld
rep movsd
mov byte[edi-(sizeof.EVENT-EVENT.code)+2], cl;clear priority field
;--------------------------------------
align 4
wait_finish:
test byte[eax+EVENT.state+3], MANUAL_RESET shr 24
jnz get_event_queue.ret ; RET
and byte[eax+EVENT.state+3], not((EVENT_SIGNALED+EVENT_WATCHED)shr 24)
test byte[eax+EVENT.state+3], MANUAL_DESTROY shr 24
jz destroy_event.internal
mov ebx, [current_slot]
add ebx, APP_OBJ_OFFSET
pushfd
cli
jmp RemoveEventTo
;-----------------------------------------------------------------------------
align 4
destroy_event: ;; EXPORT use
;info:
; Move EVENT to the FreeEvents list, clear the magic, destroy, pid, id fields
;param:
; eax - event
; ebx - uid (for Dummy testing)
;retval:
; eax - address of EVENT object (=0 => fail)
;scratched: ebx,ecx
call DummyTest ; not returned for fail !!!
;--------------------------------------
align 4
.internal:
xor ecx, ecx ; clear common header
pushfd
cli
mov [eax+EVENT.magic], ecx
mov [eax+EVENT.destroy], ecx
mov [eax+EVENT.pid], ecx
mov [eax+EVENT.id], ecx
mov ebx, FreeEvents
jmp RemoveEventTo
;-----------------------------------------------------------------------------
align 4
get_event_queue:
;info:
; client testing function for get_event_ex
;warning:
; -don't use [TASK_BASE],[current_slot],[current_slot_idx] - it is not for your slot
; -may be assumed, that interrupt are disabled
; -it is not restriction for scratched registers
;param:
; ebx - APPDATA address of testing slot
;retval:
; eax - address of EVENT object (=0 => fail)
add ebx, APP_EV_OFFSET
mov eax, [ebx+APPOBJ.bk] ; we choose from the end, according to the FIFO principle
cmp eax, ebx ; empty ???
je get_event_alone.ret0
;--------------------------------------
align 4
.ret:
ret
;-----------------------------------------------------------------------------
align 4
get_event_alone:
;info:
; client testing function for wait_event
;warning:
; -don't use [TASK_BASE],[current_slot],[current_slot_idx] - it is not for your slot
; -may be assumed, that interrupt are disabled
; -it is not restriction for scratched registers
;param:
; ebx - APPDATA address of testing slot
;retval:
; eax - address of EVENT object (=0 => fail)
mov eax, [ebx+APPDATA.wait_param]
test byte[eax+EVENT.state+3], EVENT_SIGNALED shr 24
jnz .ret
or byte[eax+EVENT.state+3], EVENT_WATCHED shr 24
;--------------------------------------
align 4
.ret0:
xor eax, eax; NO event!!!
;--------------------------------------
align 4
.ret:
ret
;-----------------------------------------------------------------------------
align 4
sys_sendwindowmsg: ;; f72
dec ebx
jnz .ret ;subfunction==1 ?
pushfd
cli
sub ecx, 2
je .sendkey
dec ecx
jnz .retf
;--------------------------------------
align 4
.sendbtn:
cmp byte[BTN_COUNT], 1
jae .result ;overflow
inc byte[BTN_COUNT]
shl edx, 8
mov [BTN_BUFF], edx
jmp .result
;--------------------------------------
align 4
.sendkey:
movzx eax, byte[KEY_COUNT]
cmp al, 120
jae .result ;overflow
inc byte[KEY_COUNT]
mov [KEY_BUFF+eax], dl
; store empty scancode
add eax, 120+2
mov [KEY_BUFF+eax], byte 0
sub eax, 120+2
;--------------------------------------
align 4
.result:
setae byte[esp+32+4] ;we consider that initially was: dword[esp+32+4]==72
;--------------------------------------
align 4
.retf:
popfd
;--------------------------------------
align 4
.ret:
ret
;-----------------------------------------------------------------------------
align 4
sys_getevent: ;; f11
mov ebx, [current_slot] ;now this is a question, what where to put......
pushfd ; this is a consequence of the general concept: let the test function have
cli ; the right to hope to disable interrupts, as when called from shed
call get_event_for_app
popfd
mov [esp+32], eax
ret
;-----------------------------------------------------------------------------
align 4
sys_waitforevent: ;; f10
or ebx, -1; infinite timeout
;--------------------------------------
align 4
sys_wait_event_timeout: ;; f23
call unprotect_from_terminate
mov edx, get_event_for_app; wait_test
call Wait_events_ex ; ebx - timeout
mov [esp+32], eax
call protect_from_terminate
ret
;-----------------------------------------------------------------------------
align 4
get_event_for_app: ;; used from f10,f11,f23
;info:
; client testing function for applications (f10,f23)
;warning:
; -don't use [TASK_BASE],[current_slot],[current_slot_idx] - it is not for your slot
; -may be assumed, that interrupt are disabled
; -it is not restriction for scratched registers
;param:
; ebx - APPDATA address of testing slot
;retval:
; eax - event number (=0 => no events)
movzx edi, bh ; bh is assumed as [current_slot_idx]
shl edi, 5
add edi, TASK_TABLE ; edi is assumed as [TASK_BASE]
mov ecx, [edi+TASKDATA.event_mask]
and ecx, 0x7FFFFFFF
;--------------------------------------
align 4
.loop: ; until we run out all the bits of the mask
bsr eax, ecx ; find a non-zero bit of the mask (31 -> 0)
jz .no_events ; ran out all the bits of the mask but found nothing ???
btr ecx, eax ; clear the current checking bit of the mask
; go to the handler of this (eax) bit
cmp eax, 10
jae .loop ; eax=[10..31], ignored (event 11...32)
 
cmp eax, 3
je .loop ; eax=3, ignored (event 4)
 
cmp eax, 4
je .FlagAutoReset ; eax=4, retvals=eax+1 (event 5)
 
cmp eax, 5
je .mouse_check ; eax=5, retvals=eax+1 (event 6)
 
ja .FlagAutoReset ; eax=[6..9], retvals=eax+1 (event 7...10)
 
cmp eax, 1
jae .BtKy ; eax=[1,2], retvals=eax+1 (event 2,3)
;--------------------------------------
align 4
.WndRedraw: ; eax=0, retval WndRedraw=1
cmp [edi-twdw+WDATA.fl_redraw], al;al==0
jne .result
jmp .loop
;--------------------------------------
align 4
.no_events:
xor eax, eax
ret
;--------------------------------------
align 4
.mouse_check: ; Mouse 5+1=6
push eax
mov eax, [TASK_BASE]
mov eax, [eax + TASKDATA.event_mask]
test eax, 0x80000000 ; bit 31: active/inactive filter f.40
jz @f
pop eax
jmp .FlagAutoReset
;--------------------------------------
align 4
@@:
; If the window is captured and moved by the user, then no mouse events!!!
mov al, [mouse.active_sys_window.action]
and al, WINDOW_MOVE_AND_RESIZE_FLAGS
test al, al
pop eax
jnz .loop
;--------------------------------------
align 4
.FlagAutoReset: ; retvals: BgrRedraw=5, IPC=7, Stack=8, Debug=9
btr [ebx+APPDATA.occurred_events], eax
jnc .loop
;--------------------------------------
align 4
.result: ; retval = eax+1
inc eax
ret
;--------------------------------------
align 4
.BtKy:
movzx edx, bh
movzx edx, word[WIN_STACK+edx*2]
je .Keys ; eax=1, retval Keys=2
;--------------------------------------
align 4
.Buttons: ; eax=2, retval Buttons=3
cmp byte[BTN_COUNT], 0
je .loop ; empty ???
cmp edx, [thread_count]
jne .loop ; not Top ???
mov edx, [BTN_BUFF]
shr edx, 8
cmp edx, 0xFFFF ;-ID for Minimize-Button of Form
jne .result
mov [window_minimize], 1
call wakeup_osloop
dec byte[BTN_COUNT]
jmp .loop
;--------------------------------------
align 4
.Keys: ; eax==1
cmp edx, [thread_count]
jne @f ; not Top ???
cmp [KEY_COUNT], al; al==1
jae .result ; not empty ???
;--------------------------------------
align 4
@@:
mov edx, hotkey_buffer
;--------------------------------------
align 4
@@:
cmp [edx], bh ; bh - slot for testing
je .result
add edx, 8
cmp edx, hotkey_buffer+120*8
jb @b
jmp .loop
;end.
;-----------------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/skincode.inc
0,0 → 1,453
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
include "skindata.inc"
 
;skin_data = 0x00778000
;-----------------------------------------------------------------
align 4
read_skin_file:
stdcall load_file, ebx
test eax, eax
jz .notfound
 
cmp dword [eax], 'SKIN'
jnz .noskin
 
xchg eax, [skin_data]
test eax, eax
jz @f
 
stdcall kernel_free, eax
@@:
call parse_skin_data
xor eax, eax
ret
;--------------------------------------
align 4
.notfound:
xor eax, eax
inc eax
ret
;--------------------------------------
align 4
.noskin:
stdcall kernel_free, eax
mov eax, 2
ret
;------------------------------------------------------------------------------
struct SKIN_HEADER
ident dd ?
version dd ?
params dd ?
buttons dd ?
bitmaps dd ?
ends
 
struct SKIN_PARAMS
skin_height dd ?
margin.right dw ?
margin.left dw ?
margin.bottom dw ?
margin.top dw ?
colors.inner dd ?
colors.outer dd ?
colors.frame dd ?
colors_1.inner dd ?
colors_1.outer dd ?
colors_1.frame dd ?
dtp.size dd ?
dtp.data rb 40
ends
 
struct SKIN_BUTTONS
type dd ?
; position
left dw ?
top dw ?
; size
width dw ?
height dw ?
ends
 
struct SKIN_BITMAPS
kind dw ?
type dw ?
data dd ?
ends
;------------------------------------------------------------------------------
align 4
load_default_skin:
mov [_skinh], 22
mov ebx, _skin_file_default
call read_skin_file
ret
;------------------------------------------------------------------------------
align 4
parse_skin_data:
mov ebp, [skin_data]
cmp [ebp+SKIN_HEADER.ident], 'SKIN'
jne .exit
 
mov edi, skin_udata
mov ecx, (skin_udata.end-skin_udata)/4
xor eax, eax
cld
rep stosd
mov ebx, [ebp+SKIN_HEADER.params]
add ebx, [skin_data]
mov eax, [ebx+SKIN_PARAMS.skin_height]
mov [_skinh], eax
mov eax, [ebx+SKIN_PARAMS.colors.inner]
mov [skin_active.colors.inner], eax
mov eax, [ebx+SKIN_PARAMS.colors.outer]
mov [skin_active.colors.outer], eax
mov eax, [ebx+SKIN_PARAMS.colors.frame]
mov [skin_active.colors.frame], eax
mov eax, [ebx+SKIN_PARAMS.colors_1.inner]
mov [skin_inactive.colors.inner], eax
mov eax, [ebx+SKIN_PARAMS.colors_1.outer]
mov [skin_inactive.colors.outer], eax
mov eax, [ebx+SKIN_PARAMS.colors_1.frame]
mov [skin_inactive.colors.frame], eax
lea esi, [ebx+SKIN_PARAMS.dtp.data]
mov edi, common_colours
mov ecx, [ebx+SKIN_PARAMS.dtp.size]
and ecx, 255
rep movsb
mov eax, dword[ebx+SKIN_PARAMS.margin.right]
mov dword[_skinmargins+0], eax
mov eax, dword[ebx+SKIN_PARAMS.margin.bottom]
mov dword[_skinmargins+4], eax
mov ebx, [ebp+SKIN_HEADER.bitmaps]
add ebx, [skin_data]
.lp1:
cmp dword[ebx], 0
je .end_bitmaps
movzx eax, [ebx+SKIN_BITMAPS.kind]
movzx ecx, [ebx+SKIN_BITMAPS.type]
dec eax
jnz .not_left
xor eax, eax
mov edx, skin_active.left.data
or ecx, ecx
jnz .next_bitmap
mov edx, skin_inactive.left.data
jmp .next_bitmap
;--------------------------------------
align 4
.not_left:
dec eax
jnz .not_oper
mov esi, [ebx+SKIN_BITMAPS.data]
add esi, [skin_data]
mov eax, [esi+0]
neg eax
mov edx, skin_active.oper.data
or ecx, ecx
jnz .next_bitmap
mov edx, skin_inactive.oper.data
jmp .next_bitmap
;--------------------------------------
align 4
.not_oper:
dec eax
jnz .not_base
mov eax, [skin_active.left.width]
mov edx, skin_active.base.data
or ecx, ecx
jnz .next_bitmap
mov eax, [skin_inactive.left.width]
mov edx, skin_inactive.base.data
jmp .next_bitmap
;--------------------------------------
align 4
.not_base:
add ebx, 8
jmp .lp1
;--------------------------------------
align 4
.next_bitmap:
mov ecx, [ebx+SKIN_BITMAPS.data]
add ecx, [skin_data]
mov [edx+4], eax
mov eax, [ecx+0]
mov [edx+8], eax
add ecx, 8
mov [edx+0], ecx
add ebx, 8
jmp .lp1
;--------------------------------------
align 4
.end_bitmaps:
mov ebx, [ebp+SKIN_HEADER.buttons]
add ebx, [skin_data]
.lp2:
cmp dword[ebx], 0
je .end_buttons
mov eax, [ebx+SKIN_BUTTONS.type]
dec eax
jnz .not_close
mov edx, skin_btn_close
jmp .next_button
;--------------------------------------
align 4
.not_close:
dec eax
jnz .not_minimize
mov edx, skin_btn_minimize
jmp .next_button
;--------------------------------------
align 4
.not_minimize:
add ebx, 12
jmp .lp2
;--------------------------------------
align 4
.next_button:
movsx eax, [ebx+SKIN_BUTTONS.left]
mov [edx+SKIN_BUTTON.left], eax
movsx eax, [ebx+SKIN_BUTTONS.top]
mov [edx+SKIN_BUTTON.top], eax
movsx eax, [ebx+SKIN_BUTTONS.width]
mov [edx+SKIN_BUTTON.width], eax
movsx eax, [ebx+SKIN_BUTTONS.height]
mov [edx+SKIN_BUTTON.height], eax
add ebx, 12
jmp .lp2
;--------------------------------------
align 4
.end_buttons:
.exit:
ret
;------------------------------------------------------------------------------
align 4
drawwindow_IV_caption:
mov ebp, skin_active
or al, al
jnz @f
mov ebp, skin_inactive
@@:
mov esi, [esp+4]
mov eax, [esi+WDATA.box.width] ; window width
mov edx, [ebp+SKIN_DATA.left.left]
shl edx, 16
mov ecx, [ebp+SKIN_DATA.left.width]
shl ecx, 16
add ecx, [_skinh]
mov ebx, [ebp+SKIN_DATA.left.data]
or ebx, ebx
jz @f
call sys_putimage.forced
@@:
mov esi, [esp+4]
mov eax, [esi+WDATA.box.width]
sub eax, [ebp+SKIN_DATA.left.width]
sub eax, [ebp+SKIN_DATA.oper.width]
cmp eax, [ebp+SKIN_DATA.base.left]
jng .non_base
xor edx, edx
mov ecx, [ebp+SKIN_DATA.base.width]
jecxz .non_base
div ecx
inc eax
mov ebx, [ebp+SKIN_DATA.base.data]
mov ecx, [ebp+SKIN_DATA.base.width]
shl ecx, 16
add ecx, [_skinh]
mov edx, [ebp+SKIN_DATA.base.left]
sub edx, [ebp+SKIN_DATA.base.width]
shl edx, 16
.baseskinloop:
shr edx, 16
add edx, [ebp+SKIN_DATA.base.width]
shl edx, 16
 
push eax ebx ecx edx
or ebx, ebx
jz @f
call sys_putimage.forced
@@:
pop edx ecx ebx eax
 
dec eax
jnz .baseskinloop
.non_base:
mov esi, [esp+4]
mov edx, [esi+WDATA.box.width]
sub edx, [ebp+SKIN_DATA.oper.width]
inc edx
shl edx, 16
mov ebx, [ebp+SKIN_DATA.oper.data]
mov ecx, [ebp+SKIN_DATA.oper.width]
shl ecx, 16
add ecx, [_skinh]
or ebx, ebx
jz @f
call sys_putimage.forced
@@:
ret
;------------------------------------------------------------------------------
align 4
drawwindow_IV:
;param1 - aw_yes
pusha
push edx
mov edi, edx
mov ebp, skin_active
cmp byte [esp+32+4+4], 0
jne @f
mov ebp, skin_inactive
@@:
mov eax, [edi+WDATA.box.left]
shl eax, 16
mov ax, word [edi+WDATA.box.left]
add ax, word [edi+WDATA.box.width]
mov ebx, [edi+WDATA.box.top]
shl ebx, 16
mov bx, word [edi+WDATA.box.top]
add bx, word [edi+WDATA.box.height]
mov esi, [ebp+SKIN_DATA.colors.outer]
or esi, 1 shl 25 ; 0x02000000 used for draw_rectangle without top line
ror ebx, 16
add ebx, [_skinh]
sub bx, 1
rol ebx, 16
call draw_rectangle
mov ecx, 3
_dw3l:
add eax, 1*65536-1
add ebx, 0*65536-1
test ax, ax
js no_skin_add_button
test bx, bx
js no_skin_add_button
mov esi, [ebp+SKIN_DATA.colors.frame];[edi+24]
or esi, 1 shl 25; 0x02000000 used for draw_rectangle without top line
call draw_rectangle
dec ecx
jnz _dw3l
mov esi, [ebp+SKIN_DATA.colors.inner]
or esi, 1 shl 25; 0x02000000 used for draw_rectangle without top line
add eax, 1*65536-1
add ebx, 0*65536-1
test ax, ax
js no_skin_add_button
test bx, bx
js no_skin_add_button
test [edi + WDATA.fl_wstate], WSTATE_ROLLEDUP
jnz @f
call draw_rectangle
@@:
mov eax, [skin_data]
cmp [eax], dword 'SKIN'
je @f
xor eax, eax
xor ebx, ebx
mov esi, [esp]
mov ecx, [esi+WDATA.box.width]
inc ecx
mov edx, [_skinh]
mov edi, [common_colours+4]; standard grab color
call vesa20_drawbar
jmp draw_clientbar
;--------------------------------------
align 4
@@:
mov al, [esp+32+4+4]
call drawwindow_IV_caption
draw_clientbar:
mov esi, [esp]
mov edx, [esi+WDATA.box.top] ; WORK AREA
add edx, 21+5
mov ebx, [esi+WDATA.box.top]
add ebx, [esi+WDATA.box.height]
cmp edx, ebx
jg _noinside2
mov eax, 5
mov ebx, [_skinh]
mov ecx, [esi+WDATA.box.width]
mov edx, [esi+WDATA.box.height]
sub ecx, 4
sub edx, 4
mov edi, [esi+WDATA.cl_workarea]
test edi, 0x40000000
jnz _noinside2
call vesa20_drawbar
_noinside2:
mov eax, [skin_data]
cmp [eax], dword 'SKIN'
jne no_skin_add_button
;* close button
mov edi, [BTN_ADDR]
movzx eax, word [edi]
cmp eax, 1000
jge no_skin_add_button
inc eax
mov [edi], ax
shl eax, 4
add eax, edi
 
mov bx, word [current_slot_idx]
mov [eax], bx
mov word [eax+2], 1 ; button id
xor ebx, ebx
cmp [skin_btn_close.left], 0
jge @f
mov ebx, [esp]
mov ebx, [ebx+WDATA.box.width]
inc ebx
@@:
add ebx, [skin_btn_close.left]
mov word [eax+4], bx ; x start
mov ebx, [skin_btn_close.width]
dec ebx
mov word [eax+6], bx ; x size
mov ebx, [skin_btn_close.top]
mov word [eax+8], bx ; y start
mov ebx, [skin_btn_close.height]
dec ebx
mov word [eax+10], bx ; y size
bts word [eax+12], 14
;* minimize button
mov edi, [BTN_ADDR]
movzx eax, word [edi]
cmp eax, 1000
jge no_skin_add_button
inc eax
mov [edi], ax
shl eax, 4
add eax, edi
 
mov bx, word [current_slot_idx]
mov [eax], bx
mov word [eax+2], -1 ; button id
xor ebx, ebx
cmp [skin_btn_minimize.left], 0
jge @f
mov ebx, [esp]
mov ebx, [ebx+WDATA.box.width]
inc ebx
@@:
add ebx, [skin_btn_minimize.left]
mov word [eax+4], bx ; x start
mov ebx, [skin_btn_minimize.width]
dec ebx
mov word [eax+6], bx ; x size
mov ebx, [skin_btn_minimize.top]
mov word [eax+8], bx ; y start
mov ebx, [skin_btn_minimize.height]
dec ebx
mov word [eax+10], bx ; y size
bts word [eax+12], 14
no_skin_add_button:
pop edi
popa
ret 4
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/charUni.mt
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/font.inc
0,0 → 1,878
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
dtext:
; edx -> string
; esi = number of characters
; ebx = output coordinates XXXXYYYY h
; ecx = char color and flags flRRGGBB h
; fl = ZBFFRSSS b
; Z=1: edx -> zero terminated string, esi = ?
; B=1: fill background with color eax
; R=1: edi -> user area for redirect
; FF=3: UTF-8 8x16, FF=2: UTF-16LE 8x16
; FF=1: cp866 8x16, FF=0: cp866 6x9
; SSS = (font multiplier)-1
; edi=1: force output
; flag CF=1 means that we deal with asciiz but need to draw no more than esi symbols
clc
._:
push ecx edx
setc dl
and eax, 0xFFFFFF
and ecx, 1 shl 31
shl edx, 29
or eax, ecx
or eax, edx
pop edx ecx
bt ecx, 30
jc @f
or eax, 1 shl 30
@@:
pushd 0 0 0 eax
movsx eax, bx
sar ebx, 16
push eax ebx edi
bt ecx, 27
jc .redirect
mov ebp, [_display.width]
xor edi, edi
jmp @f
 
.ret:
add esp, 28
ret
 
.redirect:
mov ebp, [edi]
add edi, 8
@@:
shl ebp, 2
imul eax, ebp
shl ebx, 2
add eax, ebx
js .ret
add edi, eax
mov eax, ecx
mov ebx, ecx
test ecx, ecx
jns @f
mov esi, 256
@@:
shr ecx, 24
and cl, 7
inc ecx
push ebp ecx esi
mov esi, edx
or eax, 0xFF000000
bt ebx, 27
jc .bufferReady
mov eax, 9
test ebx, 0x30000000
jz @f
add eax, 7
@@:
imul eax, ecx
mov [esp+32], eax
imul ebp, eax
stdcall kernel_alloc, ebp
mov ecx, ebp
shr ecx, 2
mov [esp+36], eax
sub edi, eax
mov edx, eax
mov eax, [esp+24]
test eax, 1 shl 30
jz @f
or eax, -1
mov [esp+28], edi
jmp .1
@@:
and eax, 0x00ffffff
.1:
mov edi, edx
rep stosd
mov edi, edx
mov eax, ebx
and eax, 0xFFFFFF
.bufferReady:
mov ebp, eax
mov eax, [esp+8]
shr eax, 2
sub eax, [esp+16]
shr eax, 3
xor edx, edx
div dword[esp+4]
mov ecx, [esp]
cmp eax, ecx
jnc @f
mov [esp], eax
@@:
xor edx, edx
bt ebx, 29
jc @f
bt ebx, 28
jc .draw866toUni
shl eax, 3
mov bx, 6
div bx
xor edx, edx
inc eax
mov [esp], ecx
cmp eax, ecx
jnc .draw866
mov [esp], eax
jmp .draw866
 
@@:
bt ebx, 28
jc .drawUTF8
 
; ebp = font color
; esi -> string
; edi -> buffer
 
; Stack map:
; char counter +0
fontMultiplier = 4
widthX = 8
; edi +12
; X +16
; Y +20
; internal flags & background +24
deltaToScreen = 28
; temp buffer height +32
; temp buffer pointer +36
 
.drawUTF16:
dec dword [esp]
js .done
movzx ebx, word [esi]
test dword [esp + 24], 1 shl 31
jnz @f
test dword [esp + 24], 1 shl 29
jz .u16Still
@@:
test ebx, ebx
jz .done
.u16Still:
inc esi
inc esi
cmp bx, 1419
jc @f
xor ebx, ebx
@@:
pushd esi edi 16
shl ebx, 4
add ebx, fontUni
mov esi, [esp+12+fontMultiplier]
call drawChar
imul esi, 8*4
pop edi
pop edi
add edi, esi
pop esi
jmp .drawUTF16
 
.drawUTF8:
dec dword [esp]
js .done
xor eax, eax
call utf8to16
test dword [esp + 24], 1 shl 31
jnz @f
test dword [esp + 24], 1 shl 29
jz .u8Still
@@:
test eax, eax
jz .done
.u8Still:
cmp eax, 1419
jc @f
xor eax, eax
@@:
shl eax, 4
lea ebx, [eax+fontUni]
pushd esi edi 16
mov esi, [esp+12+fontMultiplier]
call drawChar
imul esi, 8*4
pop edi
pop edi
add edi, esi
pop esi
jmp .drawUTF8
 
.draw866:
dec dword [esp]
js .done
movzx ebx, byte [esi]
test dword [esp + 24], 1 shl 31
jnz @f
test dword [esp + 24], 1 shl 29
jz .866Still
@@:
test ebx, ebx
jz .done
.866Still:
inc esi
pushd esi edi 9
lea ebx, [ebx*8+ebx+font1]
mov esi, [esp+12+fontMultiplier]
call drawChar
imul esi, 6*4
pop edi
pop edi
add edi, esi
pop esi
jmp .draw866
 
.draw866toUni:
dec dword [esp]
js .done
movzx eax, byte [esi]
test dword [esp + 24], 1 shl 31
jnz @f
test dword [esp + 24], 1 shl 29
jz .8662uStill
@@:
test eax, eax
jz .done
.8662uStill:
call ansi2uni_char
shl eax, 4
lea ebx, [eax+fontUni]
inc esi
pushd esi edi 16
mov esi, [esp+12+fontMultiplier]
call drawChar
imul esi, 8*4
pop edi
pop edi
add edi, esi
pop esi
jmp .draw866toUni
 
.done:
mov ecx, edi
pop eax eax eax esi edx ebx ebp ebp ebp
mov edi, [esp]
test edi, edi
jnz @f
pop eax
ret
 
@@: ; redraw from buffer to screen
push eax
sub ecx, edi
shr ecx, 2
add edx, ecx
inc ecx
push ecx
push edi
.drawPicture:
mov eax, -1
repz scasd
jecxz @f
mov eax, edx
sub eax, ecx
push ecx
mov ecx, [edi-4]
xchg esi, edi
call __sys_putpixel
xchg esi, edi
pop ecx
jmp .drawPicture
 
@@:
pop edi
mov ecx, [esp]
add edi, [esp+4]
inc ebx
push edi
dec ebp
jnz .drawPicture
add esp, 12
call kernel_free
ret
 
; scaling/smoothing algorithm
drawChar:
; ebp = font color
; esi = font multiplier
; edi -> buffer
; ebx -> char data
mov dl, [ebx]
.raw:
bsf eax, edx
jz .nextRaw
imul eax, esi
shl eax, 2
push edi
add edi, eax
mov ecx, esi
dec esi
jnz .square
mov [edi], ebp
inc esi
cmp [fontSmoothing], 0
jz .nextPixel
.checkLeftSM: ; smoothing
bsf eax, edx
dec eax
js .checkRightSM
bt [ebx], eax
jc .checkRightSM
dec eax
js .checkLeftDownSM
bt [ebx], eax
jc .checkRightSM
.checkLeftDownSM:
inc eax
bt [ebx+1], eax
jnc .checkLeftUpSM
inc eax
bt [ebx+1], eax
jnc @f
bt [ebx-1], eax
jc .checkRightSM
dec eax
dec eax
js @f
bt [ebx+1], eax
jnc @f
inc eax
.checkLeftUpSM:
bt [ebx-1], eax
jnc .checkRightSM
inc eax
bt [ebx-1], eax
jnc @f
bt [ebx+1], eax
jc .checkRightSM
dec eax
dec eax
js @f
bt [ebx-1], eax
jc .checkRightSM
@@:
mov ecx, [esp+20+deltaToScreen]
mov eax, [edi-4]
test ecx, ecx
jz @f
pusha
lea ebx, [edi+ecx-4]
shr ebx, 2
call syscall_getpixel
popa
@@:
push ebx edx
mov ebx, ebp
xor ecx, ecx
cmp [fontSmoothing], 1
jnz .subpixelLeft
call antiAliasing
jmp @f
 
.subpixelLeft:
mov cl, bl
lea edx, [ecx*8+ecx]
lea edx, [ecx*2+edx]
mov cl, al
lea ecx, [ecx*4+ecx]
add edx, ecx
shr edx, 4
mov al, dl
 
xor ecx, ecx
mov cl, ah
lea edx, [ecx*8+ecx]
lea edx, [ecx*2+edx]
mov cl, bh
lea ecx, [ecx*4+ecx]
add edx, ecx
shr edx, 4
mov ah, dl
 
rol eax, 16
rol ebx, 16
xor ecx, ecx
mov cl, al
mov edx, ecx
shl ecx, 3
sub ecx, edx
mov dl, bl
add ecx, edx
shr ecx, 3
mov al, cl
rol eax, 16
@@:
mov [edi-4], eax
pop edx ebx
.checkRightSM:
bsf eax, edx
inc eax
bt [ebx], eax
jc .nextPixel
inc eax
bt [ebx], eax
jc .nextPixel
dec eax
.checkRightDownSM:
bt [ebx+1], eax
jnc .checkRightUpSM
dec eax
bt [ebx+1], eax
jnc @f
bt [ebx-1], eax
jc .nextPixel
inc eax
inc eax
bt [ebx+1], eax
jnc @f
dec eax
.checkRightUpSM:
bt [ebx-1], eax
jnc .nextPixel
dec eax
bt [ebx-1], eax
jnc @f
bt [ebx+1], eax
jc .nextPixel
inc eax
inc eax
bt [ebx-1], eax
jc .nextPixel
@@:
mov ecx, [esp+20+deltaToScreen]
mov eax, [edi+4]
test ecx, ecx
jz @f
pusha
lea ebx, [edi+ecx+4]
shr ebx, 2
call syscall_getpixel
popa
@@:
push ebx edx
mov ebx, ebp
xor ecx, ecx
cmp [fontSmoothing], 1
jnz .subpixelRight
call antiAliasing
jmp @f
 
.subpixelRight:
mov cl, al
mov edx, ecx
shl ecx, 3
sub ecx, edx
mov dl, bl
add ecx, edx
shr ecx, 3
mov al, cl
 
xor ecx, ecx
mov cl, ah
lea edx, [ecx*8+ecx]
lea edx, [ecx*2+edx]
mov cl, bh
lea ecx, [ecx*4+ecx]
add edx, ecx
shr edx, 4
mov ah, dl
 
rol ebx, 16
rol eax, 16
xor ecx, ecx
mov cl, bl
lea edx, [ecx*8+ecx]
lea edx, [ecx*2+edx]
mov cl, al
lea ecx, [ecx*4+ecx]
add edx, ecx
shr edx, 4
mov al, dl
rol eax, 16
@@:
mov [edi+4], eax
pop edx ebx
jmp .nextPixel
 
.square: ; scaling
mov eax, esi
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
add edi, [esp+20+widthX]
dec ecx
jnz .square
inc esi
mov edi, [esp]
.checkLeft:
bsf eax, edx
dec eax
js .checkRight
bt [ebx], eax
jc .checkRight
.checkLeftDown:
bt [ebx+1], eax
jnc .checkLeftUp
mov ecx, eax
inc eax
bt [ebx+1], eax
jc @f
bt [ebx-1], eax
jnc .downRightLow
bt [ebx-2], eax
jc .downRightLow
dec eax
bt [ebx-1], eax
jc .downRightLow
dec eax
js .downRightHigh
bt [ebx-2], eax
jc .downRightLow
jmp .downRightHigh
 
@@:
bt [ebx-1], eax
jc .checkLeftUp
dec eax
dec eax
js .downRightLow
bt [ebx+1], eax
jc .checkLeftUp
.downRightLow:
imul ecx, esi
shl ecx, 2
add edi, ecx
dec esi
mov eax, [esp+20+widthX]
imul eax, esi
add edi, eax
add edi, 4
mov ecx, esi
dec ecx
.drawDownRight:
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
sub edi, [esp+20+widthX]
add edi, 4
dec ecx
jns .drawDownRight
inc esi
mov edi, [esp]
jmp .checkLeftUp
 
.downRightHigh:
imul ecx, esi
shl ecx, 2
add edi, ecx
dec esi
mov eax, [esp+20+widthX]
imul eax, esi
add edi, eax
add edi, 4
mov ecx, esi
dec ecx
.drawDownRightHigh:
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
sub edi, [esp+20+widthX]
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
sub edi, [esp+20+widthX]
add edi, 4
dec ecx
jns .drawDownRightHigh
inc esi
mov edi, [esp]
.checkLeftUp:
bsf eax, edx
dec eax
bt [ebx-1], eax
jnc .checkRight
mov ecx, eax
inc eax
bt [ebx-1], eax
jc @f
bt [ebx+1], eax
jnc .upRightLow
bt [ebx+2], eax
jc .upRightLow
dec eax
bt [ebx+1], eax
jc .upRightLow
dec eax
js .upRightHigh
bt [ebx+2], eax
jc .upRightLow
jmp .upRightHigh
 
@@:
bt [ebx+1], eax
jc .checkRight
dec eax
dec eax
js .upRightLow
bt [ebx-1], eax
jc .checkRight
.upRightLow:
imul ecx, esi
shl ecx, 2
add edi, ecx
add edi, 4
mov ecx, esi
dec ecx
dec ecx
.drawUpRight:
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
add edi, [esp+20+widthX]
add edi, 4
dec ecx
jns .drawUpRight
mov edi, [esp]
jmp .checkRight
 
.upRightHigh:
imul ecx, esi
shl ecx, 2
add edi, ecx
add edi, 4
mov ecx, esi
dec ecx
dec ecx
.drawUpRightHigh:
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
add edi, [esp+20+widthX]
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
add edi, [esp+20+widthX]
add edi, 4
dec ecx
jns .drawUpRightHigh
mov edi, [esp]
.checkRight:
bsf eax, edx
inc eax
bt [ebx], eax
jc .nextPixel
.checkRightDown:
bt [ebx+1], eax
jnc .checkRightUp
mov ecx, eax
dec eax
bt [ebx+1], eax
jc @f
bt [ebx-1], eax
jnc .downLeftLow
bt [ebx-2], eax
jc .downLeftLow
inc eax
bt [ebx-1], eax
jc .downLeftLow
inc eax
bt [ebx-2], eax
jc .downLeftLow
jmp .downLeftHigh
 
@@:
bt [ebx-1], eax
jc .checkRightUp
inc eax
inc eax
bt [ebx+1], eax
jc .checkRightUp
.downLeftLow:
imul ecx, esi
shl ecx, 2
add edi, ecx
dec esi
mov eax, [esp+20+widthX]
imul eax, esi
add edi, eax
mov ecx, esi
dec ecx
.drawDownLeft:
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
sub edi, [esp+20+widthX]
dec ecx
jns .drawDownLeft
inc esi
mov edi, [esp]
jmp .checkRightUp
 
.downLeftHigh:
imul ecx, esi
shl ecx, 2
add edi, ecx
dec esi
mov eax, [esp+20+widthX]
imul eax, esi
add edi, eax
mov ecx, esi
dec ecx
.drawDownLeftHigh:
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
sub edi, [esp+20+widthX]
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
sub edi, [esp+20+widthX]
dec ecx
jns .drawDownLeftHigh
inc esi
mov edi, [esp]
.checkRightUp:
bsf eax, edx
inc eax
bt [ebx-1], eax
jnc .nextPixel
mov ecx, eax
dec eax
bt [ebx-1], eax
jc @f
bt [ebx+1], eax
jnc .upLeftLow
bt [ebx+2], eax
jc .upLeftLow
inc eax
bt [ebx+1], eax
jc .upLeftLow
inc eax
bt [ebx+2], eax
jc .upLeftLow
jmp .upLeftHigh
 
@@:
bt [ebx+1], eax
jc .nextPixel
inc eax
inc eax
bt [ebx-1], eax
jc .nextPixel
.upLeftLow:
imul ecx, esi
shl ecx, 2
add edi, ecx
mov ecx, esi
dec ecx
dec ecx
.drawUpLeft:
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
add edi, [esp+20+widthX]
dec ecx
jns .drawUpLeft
jmp .nextPixel
 
.upLeftHigh:
imul ecx, esi
shl ecx, 2
add edi, ecx
mov ecx, esi
dec ecx
dec ecx
.drawUpLeftHigh:
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
add edi, [esp+20+widthX]
mov eax, ecx
@@:
mov [edi+eax*4], ebp
dec eax
jns @b
add edi, [esp+20+widthX]
dec ecx
jns .drawUpLeftHigh
.nextPixel:
bsf eax, edx
btr edx, eax
pop edi
jmp .raw
 
.nextRaw:
inc ebx
mov eax, [esp+16+widthX]
imul eax, esi
add edi, eax
dec dword [esp+4]
jnz drawChar
ret
 
antiAliasing:
mov bp, 3
@@:
mov cl, al
mov dl, bl
lea ecx, [ecx*2+ecx]
add ecx, edx
shr ecx, 2
mov al, cl
ror eax, 8
ror ebx, 8
dec bp
jnz @b
ror eax, 8
ror ebx, 8
mov ebp, ebx
ret
 
iglobal
fontSmoothing db 2 ; = 0, 1 or 2
fontSize db 0 ; user mode setting
font1:
if lang eq sp
file 'gui/char_sp.mt'
else if lang eq et
file 'gui/char_et.mt'
else
file 'gui/char.mt'
end if
fontUni:
file 'gui/charUni.mt'
endg
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/char.mt
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/skindata.inc
0,0 → 1,64
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
;
; WINDOW SKIN DATA.
;
 
iglobal
_skin_file_default db '/sys/DEFAULT.SKN',0
endg
 
struct SKIN_DATA
colors.inner dd ?
colors.outer dd ?
colors.frame dd ?
left.data dd ?
left.left dd ?
left.width dd ?
oper.data dd ?
oper.left dd ?
oper.width dd ?
base.data dd ?
base.left dd ?
base.width dd ?
ends
 
struct SKIN_BUTTON
left dd ?
top dd ?
width dd ?
height dd ?
ends
 
uglobal
 
align 4
 
skin_udata:
_skinh dd ?
 
_skinmargins: ; rw 4
.right dw ?
.left dw ?
.bottom dw ?
.top dw ?
 
skin_btn_close SKIN_BUTTON
skin_btn_minimize SKIN_BUTTON
 
skin_active SKIN_DATA
skin_inactive SKIN_DATA
 
align 4
 
skin_udata.end:
 
endg
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/mousepointer.inc
0,0 → 1,250
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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$
 
 
iglobal
 
align 4
mousepointer:
db 0x00,0x00,0x00,0x74,0x74,0x74,0x6e,0x6e,0x6e,0x6f
db 0x6f,0x6f,0x71,0x71,0x71,0x75,0x75,0x75,0x79,0x79
db 0x79,0x7c,0x7c,0x7c,0x7e,0x7e,0x7e,0x80,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x00,0x00,0x00,0x63,0x63,0x63,0x63,0x63,0x63
db 0x66,0x66,0x66,0x6c,0x6c,0x6c,0x72,0x72,0x72,0x78
db 0x78,0x78,0x7c,0x7c,0x7c,0x7e,0x7e,0x7e,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0
db 0xc0,0xc0,0x00,0x00,0x00,0x54,0x54,0x54,0x57,0x57
db 0x57,0x5f,0x5f,0x5f,0x68,0x68,0x68,0x71,0x71,0x71
db 0x77,0x77,0x77,0x7c,0x7c,0x7c,0x7e,0x7e,0x7e,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0xc0,0xc0,0xc0
db 0xc0,0xc0,0xc0,0x00,0x00,0x00,0x47,0x47,0x47,0x50
db 0x50,0x50,0x5b,0x5b,0x5b,0x67,0x67,0x67,0x70,0x70
db 0x70,0x77,0x77,0x77,0x7c,0x7c,0x7c,0x7e,0x7e,0x7e
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0xff,0xff,0xff,0xc0,0xc0
db 0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x3f,0x3f,0x3f
db 0x4b,0x4b,0x4b,0x59,0x59,0x59,0x66,0x66,0x66,0x70
db 0x70,0x70,0x77,0x77,0x77,0x7c,0x7c,0x7c,0x7e,0x7e
db 0x7e,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x80,0x80,0xff,0xff,0xff,0xc0,0xc0,0xc0,0xc0
db 0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x3a,0x3a
db 0x3a,0x49,0x49,0x49,0x59,0x59,0x59,0x66,0x66,0x66
db 0x70,0x70,0x70,0x77,0x77,0x77,0x7c,0x7c,0x7c,0x7e
db 0x7e,0x7e,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0xc0,0xc0
db 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x39
db 0x39,0x39,0x49,0x49,0x49,0x59,0x59,0x59,0x66,0x66
db 0x66,0x71,0x71,0x71,0x78,0x78,0x78,0x7c,0x7c,0x7c
db 0x7e,0x7e,0x7e,0x80,0x80,0x80,0x80,0x80,0x80,0xff
db 0xff,0xff,0xff,0xff,0xff,0xc0,0xc0,0xc0,0xc0,0xc0
db 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00,0x00
db 0x39,0x39,0x39,0x4a,0x4a,0x4a,0x5a,0x5a,0x5a,0x68
db 0x68,0x68,0x72,0x72,0x72,0x79,0x79,0x79,0x7d,0x7d
db 0x7d,0x7f,0x7f,0x7f,0x80,0x80,0x80,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xc0,0xc0,0xc0,0xc0
db 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00,0x00
db 0x00,0x3c,0x3c,0x3c,0x4e,0x4e,0x4e,0x5e,0x5e,0x5e
db 0x6b,0x6b,0x6b,0x75,0x75,0x75,0x7a,0x7a,0x7a,0x7e
db 0x7e,0x7e,0x80,0x80,0x80,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0
db 0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0xc0,0x00
db 0x00,0x00,0x43,0x43,0x43,0x55,0x55,0x55,0x64,0x64
db 0x64,0x70,0x70,0x70,0x78,0x78,0x78,0x7d,0x7d,0x7d
db 0x80,0x80,0x80,0xff,0xff,0xff,0xff,0xff,0xff,0xc0
db 0xc0,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x4e,0x4e,0x4e,0x5f,0x5f,0x5f,0x6d
db 0x6d,0x6d,0x76,0x76,0x76,0x7c,0x7c,0x7c,0x80,0x80
db 0x80,0xff,0xff,0xff,0xc0,0xc0,0xc0,0x00,0x00,0x00
db 0xff,0xff,0xff,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x14
db 0x14,0x14,0x1b,0x1b,0x1b,0x29,0x29,0x29,0x3a,0x3a
db 0x3a,0x4c,0x4c,0x4c,0x5d,0x5d,0x5d,0x6c,0x6c,0x6c
db 0x75,0x75,0x75,0x7b,0x7b,0x7b,0x80,0x80,0x80,0xc0
db 0xc0,0xc0,0x00,0x00,0x00,0x2f,0x2f,0x2f,0x80,0x80
db 0x80,0xff,0xff,0xff,0xc0,0xc0,0xc0,0x00,0x00,0x00
db 0x21,0x21,0x21,0x2e,0x2e,0x2e,0x40,0x40,0x40,0x52
db 0x52,0x52,0x62,0x62,0x62,0x6f,0x6f,0x6f,0x77,0x77
db 0x77,0x7c,0x7c,0x7c,0x80,0x80,0x80,0x00,0x00,0x00
db 0x47,0x47,0x47,0x3b,0x3b,0x3b,0x80,0x80,0x80,0xff
db 0xff,0xff,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x25,0x25
db 0x25,0x30,0x30,0x30,0x42,0x42,0x42,0x54,0x54,0x54
db 0x64,0x64,0x64,0x70,0x70,0x70,0x78,0x78,0x78,0x7d
db 0x7d,0x7d,0x00,0x00,0x00,0x62,0x62,0x62,0x52,0x52
db 0x52,0x4a,0x4a,0x4a,0x43,0x43,0x43,0x80,0x80,0x80
db 0xff,0xff,0xff,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x33
db 0x33,0x33,0x42,0x42,0x42,0x54,0x54,0x54,0x64,0x64
db 0x64,0x71,0x71,0x71,0x79,0x79,0x79,0x7d,0x7d,0x7d
db 0x72,0x72,0x72,0x6b,0x6b,0x6b,0x5f,0x5f,0x5f,0x5a
db 0x5a,0x5a,0x54,0x54,0x54,0x80,0x80,0x80,0xff,0xff
db 0xff,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x35,0x35,0x35
db 0x41,0x41,0x41,0x53,0x53,0x53,0x63,0x63,0x63,0x70
db 0x70,0x70,0x78,0x78,0x78,0x7d,0x7d,0x7d,0x77,0x77
db 0x77,0x73,0x73,0x73,0x6c,0x6c,0x6c,0x68,0x68,0x68
db 0x62,0x62,0x62,0x5a,0x5a,0x5a,0x80,0x80,0x80,0xff
db 0xff,0xff,0xc0,0xc0,0xc0,0x00,0x00,0x00,0x41,0x41
db 0x41,0x52,0x52,0x52,0x62,0x62,0x62,0x6f,0x6f,0x6f
db 0x78,0x78,0x78,0x7d,0x7d,0x7d,0x7b,0x7b,0x7b,0x79
db 0x79,0x79,0x74,0x74,0x74,0x72,0x72,0x72,0x6e,0x6e
db 0x6e,0x66,0x66,0x66,0x80,0x80,0x80,0xc0,0xc0,0xc0
db 0xc0,0xc0,0xc0,0x00,0x00,0x00,0x44,0x44,0x44,0x52
db 0x52,0x52,0x62,0x62,0x62,0x6e,0x6e,0x6e,0x77,0x77
db 0x77,0x7c,0x7c,0x7c,0x7e,0x7e,0x7e,0x7c,0x7c,0x7c
db 0x7a,0x7a,0x7a,0x79,0x79,0x79,0x75,0x75,0x75,0x6f
db 0x6f,0x6f,0x65,0x65,0x65,0x00,0x00,0x00,0x00,0x00
db 0x00,0x48,0x48,0x48,0x4b,0x4b,0x4b,0x56,0x56,0x56
db 0x65,0x65,0x65,0x70,0x70,0x70,0x78,0x78,0x78,0x7d
db 0x7d,0x7d,0x80,0x80,0x80,0x7f,0x7f,0x7f,0x7e,0x7e
db 0x7e,0x7d,0x7d,0x7d,0x7a,0x7a,0x7a,0x76,0x76,0x76
db 0x6f,0x6f,0x6f,0x65,0x65,0x65,0x5c,0x5c,0x5c,0x56
db 0x56,0x56,0x58,0x58,0x58,0x60,0x60,0x60,0x6b,0x6b
db 0x6b,0x73,0x73,0x73,0x7a,0x7a,0x7a,0x7d,0x7d,0x7d
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x7f
db 0x7f,0x7f,0x7d,0x7d,0x7d,0x7a,0x7a,0x7a,0x76,0x76
db 0x76,0x70,0x70,0x70,0x6a,0x6a,0x6a,0x66,0x66,0x66
db 0x66,0x66,0x66,0x6c,0x6c,0x6c,0x72,0x72,0x72,0x78
db 0x78,0x78,0x7c,0x7c,0x7c,0x7e,0x7e,0x7e,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x7f,0x7f,0x7f,0x7d,0x7d,0x7d,0x7b,0x7b,0x7b,0x77
db 0x77,0x77,0x73,0x73,0x73,0x71,0x71,0x71,0x71,0x71
db 0x71,0x74,0x74,0x74,0x78,0x78,0x78,0x7b,0x7b,0x7b
db 0x7d,0x7d,0x7d,0x7f,0x7f,0x7f,0x80,0x80,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x7f,0x7f,0x7f,0x7d,0x7d,0x7d,0x7c,0x7c,0x7c
db 0x7a,0x7a,0x7a,0x78,0x78,0x78,0x78,0x78,0x78,0x7a
db 0x7a,0x7a,0x7c,0x7c,0x7c,0x7e,0x7e,0x7e,0x7f,0x7f
db 0x7f,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80
db 0x80,0x80,0x7f,0x7f,0x7f,0x7e,0x7e,0x7e,0x7e,0x7e
db 0x7e,0x7d,0x7d,0x7d,0x7d,0x7d,0x7d,0x7e,0x7e,0x7e
db 0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x80,0x80,0x80,0x80
db 0x80,0x80
 
mousepointer1:
db 0xff,0xff,0xff,0x06,0x06,0x06,0x0a,0x0a
db 0x0a,0x08,0x08,0x08,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0xff,0xff,0xff,0xff,0xff,0xff,0x19,0x19,0x19,0x16
db 0x16,0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x2e,0x2e,0x2e
db 0x23,0x23,0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x3f
db 0x3f,0x29,0x29,0x29,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x47
db 0x47,0x47,0x2c,0x2c,0x2c,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0x48,0x48,0x48,0x2c,0x2c,0x2c,0x16,0x16,0x16,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0x48,0x48,0x48,0x2c,0x2c,0x2c,0x16,0x16,0x16
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0x48,0x48,0x48,0x2c,0x2c,0x2c,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0x48,0x48,0x48,0x2c,0x2c,0x2c,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0x47,0x47,0x47,0x29,0x29,0x29
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0x40,0x40,0x40,0x23,0x23
db 0x23,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xaa,0xaa,0xaa,0x9f,0x9f,0x9f,0x8c,0x8c,0x8c
db 0x70,0x70,0x70,0x4f,0x4f,0x4f,0x30,0x30,0x30,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x8f,0x8f,0x8f
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0xff,0x9c,0x9c,0x9c,0x87,0x87,0x87,0x6c,0x6c
db 0x6c,0x4f,0x4f,0x4f,0x32,0x32,0x32,0x19,0x19,0x19
db 0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff
db 0xff,0xff,0x69,0x69,0x69,0x84,0x84,0x84,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0x92,0x92,0x92,0x79,0x79,0x79,0x59,0x59,0x59,0x3c
db 0x3c,0x3c,0x24,0x24,0x24,0x11,0x11,0x11,0x00,0x00
db 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0x37,0x37,0x37
db 0x5d,0x5d,0x5d,0x70,0x70,0x70,0x76,0x76,0x76,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0xff,0x75,0x75,0x75,0x51,0x51,0x51,0x31,0x31,0x31
db 0x19,0x19,0x19,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x16,0x16,0x16,0x2d,0x2d,0x2d,0x49,0x49
db 0x49,0x53,0x53,0x53,0x54,0x54,0x54,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x78
db 0x78,0x78,0x54,0x54,0x54,0x30,0x30,0x30,0x16,0x16
db 0x16,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x0f,0x0f,0x0f,0x1f,0x1f,0x1f,0x30,0x30,0x30,0x33
db 0x33,0x33,0x33,0x33,0x33,0x3b,0x3b,0x3b,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
db 0x62,0x62,0x62,0x3b,0x3b,0x3b,0x1c,0x1c,0x1c,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x08
db 0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x24,0x24,0x24,0xff,0xff,0xff,0xff
db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x6e,0x6e
db 0x6e,0x48,0x48,0x48,0x25,0x25,0x25,0x0e,0x0e,0x0e
db 0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x04,0x04,0x00
db 0x00,0x00,0x0a,0x0a,0x0a,0x09,0x09,0x09,0x00,0x00
db 0x00,0x00,0x00,0x00,0x29,0x29,0x29,0xff,0xff,0xff
db 0xff,0xff,0xff,0x7c,0x7c,0x7c,0x71,0x71,0x71,0x50
db 0x50,0x50,0x2b,0x2b,0x2b,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x02,0x02,0x02,0x04,0x04,0x04,0x00
db 0x00,0x00,0x00,0x00,0x00,0x36,0x36,0x36,0x56,0x56
db 0x56,0x69,0x69,0x69,0x64,0x64,0x64,0x4a,0x4a,0x4a
db 0x28,0x28,0x28,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x05,0x05,0x05
db 0x00,0x00,0x00,0x21,0x21,0x21,0x39,0x39,0x39,0x49
db 0x49,0x49,0x48,0x48,0x48,0x35,0x35,0x35,0x1d,0x1d
db 0x1d,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x00,0x00
db 0x00,0x00,0x00,0x00,0x1d,0x1d,0x1d,0x27,0x27,0x27
db 0x27,0x27,0x27,0x1d,0x1d,0x1d,0x0f,0x0f,0x0f,0x06
db 0x06,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
db 0x00,0x00,0x00,0x00
 
endg
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/char_et.mt
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui/char_sp.mt
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/gui
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/kernel.asm
0,0 → 1,5784
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved.
;; PROGRAMMING:
;; Ivan Poddubny
;; Marat Zakiyanov (Mario79)
;; VaStaNi
;; Trans
;; Mihail Semenyako (mike.dld)
;; Sergey Kuzmin (Wildwest)
;; Andrey Halyavin (halyavin)
;; Mihail Lisovin (Mihasik)
;; Andrey Ignatiev (andrew_programmer)
;; NoName
;; Evgeny Grechnikov (Diamond)
;; Iliya Mihailov (Ghost)
;; Sergey Semyonov (Serge)
;; Johnny_B
;; SPraid (simba)
;; Hidnplayr
;; Alexey Teplov (<Lrz>)
;; Rus
;; Nable
;; shurf
;; Alver
;; Maxis
;; Galkov
;; CleverMouse
;; tsdima
;; turbanoff
;; Asper
;; art_zh
;; dunkaist
;; Coldy
;; rgimad
;; Boppan
;; Doczom
;; and others
;;
;; Data in this file was originally part of MenuetOS project which is
;; distributed under the terms of GNU GPL. It is modified and redistributed as
;; part of KolibriOS project under the terms of GNU GPL.
;;
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa
;; PROGRAMMING:
;;
;; Ville Mikael Turjanmaa, villemt@itu.jyu.fi
;; - main os coding/design
;; Jan-Michael Brummer, BUZZ2@gmx.de
;; Felix Kaiser, info@felix-kaiser.de
;; Paolo Minazzi, paolo.minazzi@inwind.it
;; quickcode@mail.ru
;; Alexey, kgaz@crosswinds.net
;; Juan M. Caravaca, bitrider@wanadoo.es
;; kristol@nic.fi
;; Mike Hibbett, mikeh@oceanfree.net
;; Lasse Kuusijarvi, kuusijar@lut.fi
;; Jarek Pelczar, jarekp3@wp.pl
;;
;; KolibriOS is distributed in the hope that it will be useful, but WITHOUT ANY
;; WARRANTY. No author or distributor accepts responsibility to anyone for the
;; consequences of using it or for whether it serves any particular purpose or
;; works at all, unless he says so in writing. Refer to the GNU General Public
;; License (the "GPL") for full details.
;
;; Everyone is granted permission to copy, modify and redistribute KolibriOS,
;; but only under the conditions described in the GPL. A copy of this license
;; is supposed to have been given to you along with KolibriOS so you can know
;; your rights and responsibilities. It should be in a file named COPYING.
;; Among other things, the copyright notice and this notice must be preserved
;; on all copies.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
format binary as "mnt"
 
include 'macros.inc'
include 'struct.inc'
 
$Revision$
 
 
USE_COM_IRQ = 1 ; make irq 3 and irq 4 available for PCI devices
VESA_1_2_VIDEO = 0 ; enable vesa 1.2 bank switch functions
 
; Enabling the next line will enable serial output console
;debug_com_base = 0x3f8 ; 0x3f8 is com1, 0x2f8 is com2, 0x3e8 is com3, 0x2e8 is com4, no irq's are used
 
include "proc32.inc"
include "kglobals.inc"
include "lang.inc"
include "encoding.inc"
 
include "const.inc"
 
iglobal
; The following variable, if equal to 1, duplicates debug output to the screen.
debug_direct_print db 0
; Start the first app (LAUNCHER) after kernel is loaded? (1=yes, 2 or 0=no)
launcher_start db 1
endg
 
max_processes = 255
tss_step = 128 + 8192 ; tss & i/o - 65535 ports, * 256=557056*4
 
os_stack = os_data_l - gdts ; GDTs
os_code = os_code_l - gdts
graph_data = 3 + graph_data_l - gdts
tss0 = tss0_l - gdts
app_code = 3 + app_code_l - gdts
app_data = 3 + app_data_l - gdts
app_tls = 3 + tls_data_l - gdts
pci_code_sel = pci_code_32-gdts
pci_data_sel = pci_data_32-gdts
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Included files:
;;
;; Kernel16.inc
;; - Booteng.inc English text for bootup
;; - Bootcode.inc Hardware setup
;; - Pci16.inc PCI functions
;;
;; Kernel32.inc
;; - Sys32.inc Process management
;; - Shutdown.inc Shutdown and restart
;; - Fat32.inc Read / write hd
;; - Vesa12.inc Vesa 1.2 driver
;; - Vesa20.inc Vesa 2.0 driver
;; - Vga.inc VGA driver
;; - Stack.inc Network interface
;; - Mouse.inc Mouse pointer
;; - Scincode.inc Window skinning
;; - Pci32.inc PCI functions
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
; In bios boot mode the kernel code below is appended to bootbios.bin file.
; That is a loading and initialization code that also draws the blue screen
; menu with svn revision number near top right corner of the screen. This fasm
; preprocessor code searches for '****' signature inside bootbios.bin and
; places revision number there.
if ~ defined UEFI
bootbios:
if ~ defined extended_primary_loader
file 'bootbios.bin'
else
file 'bootbios.bin.ext_loader'
end if
if __REV__ > 0
cur_pos = 0
cnt = 0
repeat $ - bootbios
load a byte from %
if a = '*'
cnt = cnt + 1
else
cnt = 0
end if
if cnt = 4
cur_pos = % - 1
break
end if
end repeat
store byte ' ' at cur_pos + 1
rev_var = __REV__
while rev_var > 0
store byte rev_var mod 10 + '0' at cur_pos
cur_pos = cur_pos - 1
rev_var = rev_var / 10
end while
store byte ' ' at cur_pos
store dword ' SVN' at cur_pos - 4
end if
end if
 
use32
org $+0x10000
 
align 4
B32:
mov ax, os_stack ; Selector for os
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov esp, TMP_STACK_TOP ; Set stack
 
; CLEAR 0x280000 - HEAP_BASE
 
xor eax, eax
mov edi, CLEAN_ZONE
mov ecx, (HEAP_BASE-OS_BASE-CLEAN_ZONE) / 4
cld
rep stosd
 
; CLEAR KERNEL UNDEFINED GLOBALS
mov edi, endofcode-OS_BASE
mov ecx, 0x90000
sub ecx, edi
shr ecx, 2
rep stosd
 
; SAVE & CLEAR 0-0xffff
 
mov edi, 0x1000
mov ecx, 0x8000 / 4
rep stosd
mov edi, 0xa000
mov ecx, 0x6000 / 4
rep stosd
 
call test_cpu
bts [cpu_caps-OS_BASE], CAPS_TSC ;force use rdtsc
 
call acpi_locate
call init_BIOS32
; MEMORY MODEL
call mem_test
call init_mem
call init_page_map
 
; ENABLE PAGING
 
mov eax, sys_proc-OS_BASE+PROC.pdt_0
mov cr3, eax
 
mov eax, cr0
or eax, CR0_PG+CR0_WP
mov cr0, eax
 
lgdt [gdts]
jmp pword os_code:high_code
 
align 4
bios32_entry dd ?
tmp_page_tabs dd ?
use16
ap_init16:
cli
lgdt [cs:gdts_ap-ap_init16]
mov eax, [cs:cr3_ap-ap_init16]
mov cr3, eax
mov eax, [cs:cr4_ap-ap_init16]
mov cr4, eax
mov eax, CR0_PE+CR0_PG+CR0_WP
mov cr0, eax
jmp pword os_code:ap_init_high
align 16
gdts_ap:
dw gdte-gdts-1
dd gdts
dw 0
cr3_ap dd ?
cr4_ap dd ?
ap_init16_size = $ - ap_init16
use32
 
__DEBUG__ fix 1
__DEBUG_LEVEL__ fix 1
include 'init.inc'
 
org OS_BASE+$
 
include 'fdo.inc'
 
align 4
high_code:
mov ax, os_stack
mov bx, app_data
mov cx, app_tls
mov ss, ax
add esp, OS_BASE
 
mov ds, bx
mov es, bx
mov fs, cx
mov gs, bx
 
xor eax, eax
mov ebx, 0xFFFFF000+PG_SHARED+PG_NOCACHE+PG_UWR
bt [cpu_caps], CAPS_PAT
setc al
shl eax, 7
or ebx, eax
 
mov eax, PG_GLOBAL
bt [cpu_caps], CAPS_PGE
jnc @F
 
or [sys_proc+PROC.pdt_0+(OS_BASE shr 20)], eax
or ebx, eax
 
mov eax, cr4
or eax, CR4_PGE
mov cr4, eax
@@:
mov [pte_valid_mask], ebx
 
xor eax, eax
mov dword [sys_proc+PROC.pdt_0], eax
mov dword [sys_proc+PROC.pdt_0+4], eax
 
mov eax, cr3
mov cr3, eax ; flush TLB
 
mov ecx, pg_data.mutex
call mutex_init
 
mov ecx, disk_list_mutex
call mutex_init
 
mov ecx, keyboard_list_mutex
call mutex_init
 
mov ecx, unpack_mutex
call mutex_init
 
mov ecx, application_table_mutex
call mutex_init
 
mov ecx, ide_mutex
call mutex_init
mov ecx, ide_channel1_mutex
call mutex_init
mov ecx, ide_channel2_mutex
call mutex_init
mov ecx, ide_channel3_mutex
call mutex_init
mov ecx, ide_channel4_mutex
call mutex_init
mov ecx, ide_channel5_mutex
call mutex_init
mov ecx, ide_channel6_mutex
call mutex_init
;-----------------------------------------------------------------------------
; SAVE REAL MODE VARIABLES
;-----------------------------------------------------------------------------
; --------------- APM ---------------------
 
; init selectors
mov ebx, [BOOT.apm_entry] ; offset of APM entry point
movzx eax, word [BOOT.apm_code_32] ; real-mode segment base address of
; protected-mode 32-bit code segment
movzx ecx, word [BOOT.apm_code_16] ; real-mode segment base address of
; protected-mode 16-bit code segment
movzx edx, word [BOOT.apm_data_16] ; real-mode segment base address of
; protected-mode 16-bit data segment
 
shl eax, 4
mov [dword apm_code_32 + 2], ax
shr eax, 16
mov [dword apm_code_32 + 4], al
 
shl ecx, 4
mov [dword apm_code_16 + 2], cx
shr ecx, 16
mov [dword apm_code_16 + 4], cl
 
shl edx, 4
mov [dword apm_data_16 + 2], dx
shr edx, 16
mov [dword apm_data_16 + 4], dl
 
mov dword[apm_entry], ebx
mov word [apm_entry + 4], apm_code_32 - gdts
 
mov eax, dword[BOOT.apm_version] ; version & flags
mov [apm_vf], eax
; -----------------------------------------
mov al, [BOOT.dma] ; DMA access
mov [allow_dma_access], al
 
mov al, [BOOT.debug_print] ; If nonzero, duplicates debug output to the screen
mov [debug_direct_print], al
 
mov al, [BOOT.launcher_start] ; Start the first app (LAUNCHER) after kernel is loaded?
mov [launcher_start], al
 
mov eax, [BOOT.devicesdat_size]
mov [acpi_dev_size], eax
mov eax, [BOOT.devicesdat_data]
mov [acpi_dev_data], eax
 
mov esi, BOOT.bios_hd
movzx ecx, byte [esi-1]
mov [NumBiosDisks], ecx
mov edi, BiosDisksData
shl ecx, 2
rep movsd
 
; -------- Fast System Call init ----------
; Intel SYSENTER/SYSEXIT (AMD CPU support it too)
bt [cpu_caps], CAPS_SEP
jnc .SEnP ; SysEnter not Present
xor edx, edx
mov ecx, MSR_SYSENTER_CS
mov eax, os_code
wrmsr
mov ecx, MSR_SYSENTER_ESP
; mov eax, sysenter_stack ; Check it
xor eax, eax
wrmsr
mov ecx, MSR_SYSENTER_EIP
mov eax, sysenter_entry
wrmsr
.SEnP:
; AMD SYSCALL/SYSRET
cmp byte[cpu_vendor], 'A'
jne .noSYSCALL
mov eax, 0x80000001
cpuid
test edx, 0x800 ; bit_11 - SYSCALL/SYSRET support
jz .noSYSCALL
mov ecx, MSR_AMD_EFER
rdmsr
or eax, 1 ; bit_0 - System Call Extension (SCE)
wrmsr
 
; !!!! It`s dirty hack, fix it !!!
; Bits of EDX :
; Bit 31–16 During the SYSRET instruction, this field is copied into the CS register
; and the contents of this field, plus 8, are copied into the SS register.
; Bit 15–0 During the SYSCALL instruction, this field is copied into the CS register
; and the contents of this field, plus 8, are copied into the SS register.
 
; mov edx, (os_code + 16) * 65536 + os_code
mov edx, 0x1B0008
 
mov eax, syscall_entry
mov ecx, MSR_AMD_STAR
wrmsr
.noSYSCALL:
; -----------------------------------------
stdcall alloc_page
stdcall map_page, tss-0xF80, eax, PG_SWR
stdcall alloc_page
stdcall map_page, tss+0x80, eax, PG_SWR
stdcall alloc_page
stdcall map_page, tss+0x1080, eax, PG_SWR
 
; LOAD IDT
 
call build_interrupt_table ;lidt is executed
;lidt [idtreg]
 
call init_kernel_heap
call init_fpu
mov eax, [xsave_area_size]
lea eax, [eax*2 + RING0_STACK_SIZE*2]
stdcall kernel_alloc, eax
mov [os_stack_seg], eax
 
lea esp, [eax+RING0_STACK_SIZE]
 
mov [tss._ss0], os_stack
mov [tss._esp0], esp
mov [tss._esp], esp
mov [tss._cs], os_code
mov [tss._ss], os_stack
mov [tss._ds], app_data
mov [tss._es], app_data
mov [tss._fs], app_data
mov [tss._gs], app_data
mov [tss._io], 128
;Add IO access table - bit array of permitted ports
mov edi, tss._io_map_0
xor eax, eax
not eax
mov ecx, 8192/4
rep stosd ; access to 4096*8=65536 ports
 
mov ax, tss0
ltr ax
 
mov eax, sys_proc
list_init eax
add eax, PROC.thr_list
list_init eax
 
call init_video
call init_mtrr
mov [LFBAddress], LFB_BASE
mov ecx, bios_fb
call set_framebuffer
call init_malloc
 
stdcall alloc_kernel_space, 0x50000 ; FIXME check size
mov [default_io_map], eax
 
add eax, 0x2000
mov [ipc_tmp], eax
mov ebx, 0x1000
 
add eax, 0x40000
mov [proc_mem_map], eax
 
add eax, 0x8000
mov [proc_mem_pdir], eax
 
add eax, ebx
mov [proc_mem_tab], eax
 
add eax, ebx
mov [tmp_task_ptab], eax
 
add eax, ebx
mov [ipc_pdir], eax
 
add eax, ebx
mov [ipc_ptab], eax
 
stdcall kernel_alloc, (unpack.LZMA_BASE_SIZE+(unpack.LZMA_LIT_SIZE shl \
(unpack.lc+unpack.lp)))*4
 
mov [unpack.p], eax
 
call init_events
mov eax, srv.fd-SRV.fd
mov [srv.fd], eax
mov [srv.bk], eax
 
;Set base of graphic segment to linear address of LFB
mov eax, [LFBAddress] ; set for gs
mov [graph_data_l+2], ax
shr eax, 16
mov [graph_data_l+4], al
mov [graph_data_l+7], ah
 
stdcall kernel_alloc, [_display.win_map_size]
mov [_display.win_map], eax
 
xor eax, eax
inc eax
 
; set background
 
mov [BgrDrawMode], eax
mov [BgrDataWidth], eax
mov [BgrDataHeight], eax
mov [mem_BACKGROUND], 4
mov [img_background], static_background_data
 
; set clipboard
 
xor eax, eax
mov [clipboard_slots], eax
mov [clipboard_write_lock], eax
stdcall kernel_alloc, 4096
test eax, eax
jnz @f
 
dec eax
@@:
mov [clipboard_main_list], eax
 
call check_acpi
 
mov eax, [hpet_base]
test eax, eax
jz @F
stdcall map_io_mem, [hpet_base], 1024, PG_GLOBAL+PAT_UC+PG_SWR
mov [hpet_base], eax
mov eax, [eax+HPET_ID]
DEBUGF 1, "K : HPET caps %x\n", eax
call init_hpet
@@:
; SET UP OS TASK
 
mov esi, boot_setostask
call boot_log
 
mov edi, sys_proc+PROC.heap_lock
mov ecx, (PROC.ht_free-PROC.heap_lock)/4
 
xor eax, eax
cld
rep stosd
 
mov [edi], dword (PROC.pdt_0 - PROC.htab)/4 - 3
mov [edi+4], dword 3 ;reserve handles for stdin stdout and stderr
mov ecx, (PROC.pdt_0 - PROC.htab)/4
add edi, 8
inc eax
@@:
stosd
inc eax
cmp eax, ecx
jbe @B
 
mov [sys_proc+PROC.pdt_0_phys], sys_proc-OS_BASE+PROC.pdt_0
 
mov eax, -1
mov edi, thr_slot_map+4
mov [edi-4], dword 0xFFFFFFF8
stosd
stosd
stosd
stosd
stosd
stosd
stosd
 
mov [current_process], sys_proc
 
mov edx, SLOT_BASE+sizeof.APPDATA*1
mov ebx, [os_stack_seg]
add ebx, RING0_STACK_SIZE
add ebx, [xsave_area_size]
call setup_os_slot
mov dword [edx], 'IDLE'
sub [edx+APPDATA.saved_esp], 4
mov eax, [edx+APPDATA.saved_esp]
mov dword [eax], idle_thread
mov ecx, IDLE_PRIORITY
call scheduler_add_thread
 
mov edx, SLOT_BASE+sizeof.APPDATA*2
mov ebx, [os_stack_seg]
call setup_os_slot
mov dword [edx], 'OS'
xor ecx, ecx
call scheduler_add_thread
 
mov dword [current_slot_idx], 2
mov [thread_count], 2
mov dword [current_slot], SLOT_BASE + sizeof.APPDATA*2
mov dword [TASK_BASE], TASK_TABLE + sizeof.TASKDATA*2
 
; Move other CPUs to deep sleep, if it is useful
uglobal
use_mwait_for_idle db 0
endg
cmp [cpu_vendor+8], 'ntel'
jnz .no_wake_cpus
bt [cpu_caps+4], CAPS_MONITOR-32
jnc .no_wake_cpus
dbgstr 'using mwait for idle loop'
inc [use_mwait_for_idle]
mov ebx, [cpu_count]
cmp ebx, 1
jbe .no_wake_cpus
call create_trampoline_pgmap
mov [cr3_ap+OS_BASE], eax
mov eax, cr4
mov [cr4_ap+OS_BASE], eax
mov esi, OS_BASE + ap_init16
mov edi, OS_BASE + 8000h
mov ecx, (ap_init16_size + 3) / 4
rep movsd
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
@@:
lea edi, [eax+APIC_ICRL]
mov esi, smpt+4
dec ebx
.wake_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
; send STARTUP IPI
mov dword [edi], 600h + (8000h shr 12)
call delay_ms
@@:
test dword [edi], 1000h
jnz @b
pop esi
dec ebx
jnz .wake_cpus_loop
mov eax, [cpu_count]
dec eax
@@:
cmp [ap_initialized], eax
jnz @b
mov eax, [cr3_ap+OS_BASE]
call free_page
.no_wake_cpus:
 
; REDIRECT ALL IRQ'S TO INT'S 0x20-0x2f
mov esi, boot_initirq
call boot_log
call init_irqs
 
mov esi, boot_picinit
call boot_log
call PIC_init
 
mov esi, boot_v86machine
call boot_log
; Initialize system V86 machine
call init_sys_v86
 
mov esi, boot_inittimer
call boot_log
; Initialize system timer (IRQ0)
call PIT_init
 
; Register ramdisk file system
if ~ defined extended_primary_loader
cmp [BOOT.rd_load_from], RD_LOAD_FROM_HD ; will be loaded later
je @f
end if
cmp [BOOT.rd_load_from], RD_LOAD_FROM_NONE
je @f
call register_ramdisk
;--------------------------------------
@@:
mov esi, boot_initapic
call boot_log
; Try to Initialize APIC
call APIC_init
 
mov esi, boot_enableirq
call boot_log
; Enable timer IRQ (IRQ0) and co-processor IRQ (IRQ13)
; they are used: when partitions are scanned, hd_read relies on timer
call unmask_timer
; Prevent duplicate timer IRQs in APIC mode
cmp [irq_mode], IRQ_APIC
jz @f
stdcall enable_irq, 2 ; @#$%! PIC
@@:
stdcall enable_irq, 13 ; co-processor
 
; Setup serial output console (if enabled)
if defined debug_com_base
 
; reserve port so nobody else will use it
xor ebx, ebx
mov ecx, debug_com_base
mov edx, debug_com_base+7
call r_f_port_area
 
; enable Divisor latch
mov dx, debug_com_base+3
mov al, 1 shl 7
out dx, al
 
; Set speed to 115200 baud (max speed)
mov dx, debug_com_base
mov al, 0x01
out dx, al
 
mov dx, debug_com_base+1
mov al, 0x00
out dx, al
 
; No parity, 8bits words, one stop bit, dlab bit back to 0
mov dx, debug_com_base+3
mov al, 3
out dx, al
 
; disable interrupts
mov dx, debug_com_base+1
mov al, 0
out dx, al
 
; clear + enable fifo (64 bits)
mov dx, debug_com_base+2
mov al, 0x7 + 1 shl 5
out dx, al
 
end if
 
 
;-----------------------------------------------------------------------------
; show SVN version of kernel on the message board
;-----------------------------------------------------------------------------
mov eax, [version_inf.rev]
DEBUGF 1, "K : kernel SVN r%d\n", eax
;-----------------------------------------------------------------------------
; show CPU count on the message board
;-----------------------------------------------------------------------------
mov eax, [cpu_count]
test eax, eax
jnz @F
mov al, 1 ; at least one CPU
@@:
DEBUGF 1, "K : %d CPU detected\n", eax
;-----------------------------------------------------------------------------
; detect Floppy drives
;-----------------------------------------------------------------------------
mov esi, boot_detectfloppy
call boot_log
include 'detect/dev_fd.inc'
;-----------------------------------------------------------------------------
; create pci-devices list
;-----------------------------------------------------------------------------
mov [pci_access_enabled], 1
call pci_enum
;-----------------------------------------------------------------------------
; initialisation IDE ATA code
;-----------------------------------------------------------------------------
include 'detect/init_ata.inc'
;-----------------------------------------------------------------------------
if 0
mov ax, [BOOT.sys_disk]
cmp ax, 'r1'; if using not ram disk, then load librares and parameters {SPraid.simba}
je no_lib_load
 
mov esi, boot_loadlibs
call boot_log
; LOADING LIBRARES
stdcall dll.Load, @IMPORT ; loading librares for kernel (.obj files)
call load_file_parse_table ; prepare file parse table
call set_kernel_conf ; configure devices and gui
no_lib_load:
end if
 
; Display APIC status
mov esi, boot_APIC_found
cmp [irq_mode], IRQ_APIC
je @f
mov esi, boot_APIC_nfound
@@:
call boot_log
 
; PRINT AMOUNT OF MEMORY
mov esi, boot_memdetect
call boot_log
 
movzx ecx, word [boot_y]
if lang eq ru
or ecx, (10+30*6) shl 16
else if lang eq sp
or ecx, (10+33*6) shl 16
else
or ecx, (10+29*6) shl 16
end if
sub ecx, 10
mov edx, 0xFFFFFF
mov ebx, [MEM_AMOUNT]
shr ebx, 20
xor edi, edi
mov eax, 0x00040000
inc edi
call display_number_force
 
; BUILD SCHEDULER
 
; call build_scheduler; sys32.inc
 
; mov esi, boot_devices
; call boot_log
 
include "detect/vortex86.inc" ; Vortex86 SoC detection code
 
stdcall load_pe_driver, szVidintel, 0
 
call usb_init
 
; SET PRELIMINARY WINDOW STACK AND POSITIONS
 
mov esi, boot_windefs
call boot_log
call set_window_defaults
 
; SET BACKGROUND DEFAULTS
 
mov esi, boot_bgr
call boot_log
call init_background
call calculatebackground
 
; RESERVE SYSTEM IRQ'S JA PORT'S
 
mov esi, boot_resirqports
call boot_log
call reserve_irqs_ports
 
call init_display
mov eax, [def_cursor]
mov [SLOT_BASE+APPDATA.cursor+sizeof.APPDATA], eax
mov [SLOT_BASE+APPDATA.cursor+sizeof.APPDATA*2], eax
 
; PRINT CPU FREQUENCY
 
mov esi, boot_cpufreq
call boot_log
 
cli
mov ebx, [hpet_base]
test ebx, ebx
jz @F
mov ebx, [ebx+HPET_COUNTER]
 
rdtsc
mov ecx, 1000
sub eax, [hpet_tsc_start]
sbb edx, [hpet_tsc_start+4]
shld edx, eax, 10
shl eax, 10
mov esi, eax
mov eax, edx
mul ecx
xchg eax, esi
mul ecx
adc edx, esi
div ebx
mul ecx
div [hpet_period]
mul ecx
DEBUGF 1, "K : cpu frequency %u Hz\n", eax
jmp .next
@@:
rdtsc
mov ecx, eax
mov esi, 250 ; wait 1/4 a second
call delay_ms
rdtsc
 
sub eax, ecx
xor edx, edx
shld edx, eax, 2
shl eax, 2
.next:
mov dword [cpu_freq], eax
mov dword [cpu_freq+4], edx
mov ebx, 1000000
div ebx
mov ebx, eax
 
movzx ecx, word [boot_y]
if lang eq ru
add ecx, (10+19*6) shl 16 - 10
else if lang eq sp
add ecx, (10+25*6) shl 16 - 10
else
add ecx, (10+17*6) shl 16 - 10
end if
 
mov edx, 0xFFFFFF
xor edi, edi
mov eax, 0x00040000
inc edi
call display_number_force
 
; SET VARIABLES
 
call set_variables
 
; STACK AND FDC
 
call stack_init
call fdc_init
 
; PALETTE FOR 320x200 and 640x480 16 col
 
cmp [SCR_MODE], word 0x12
jne no_pal_vga
mov esi, boot_pal_vga
call boot_log
call paletteVGA
no_pal_vga:
 
cmp [SCR_MODE], word 0x13
jne no_pal_ega
mov esi, boot_pal_ega
call boot_log
call palette320x200
no_pal_ega:
 
; LOAD DEFAULT SKIN
 
call load_default_skin
 
; Protect I/O permission map
 
mov esi, [default_io_map]
stdcall map_page, esi, [SLOT_BASE+sizeof.APPDATA+APPDATA.io_map], PG_READ
add esi, 0x1000
stdcall map_page, esi, [SLOT_BASE+sizeof.APPDATA+APPDATA.io_map+4], PG_READ
 
stdcall map_page, tss._io_map_0, \
[SLOT_BASE+sizeof.APPDATA+APPDATA.io_map], PG_READ
stdcall map_page, tss._io_map_1, \
[SLOT_BASE+sizeof.APPDATA+APPDATA.io_map+4], PG_READ
 
; SET KEYBOARD PARAMETERS
mov al, 0xf6 ; reset keyboard, scan enabled
call kb_write_wait_ack
test ah, ah
jnz .no_keyboard
 
iglobal
align 4
ps2_keyboard_functions:
dd .end - $
dd 0 ; no close
dd ps2_set_lights
.end:
endg
stdcall register_keyboard, ps2_keyboard_functions, 0
; mov al, 0xED ; Keyboard LEDs - only for testing!
; call kb_write_wait_ack
; mov al, 111b
; call kb_write_wait_ack
 
mov al, 0xF3 ; set repeat rate & delay
call kb_write_wait_ack
mov al, 0; 30 250 ;00100010b ; 24 500 ;00100100b ; 20 500
call kb_write_wait_ack
;// mike.dld [
call set_lights
;// mike.dld ]
stdcall attach_int_handler, 1, irq1, 0
DEBUGF 1, "K : IRQ1 return code %x\n", eax
.no_keyboard:
 
; Load PS/2 mouse driver
 
stdcall load_pe_driver, szPS2MDriver, 0
 
mov esi, boot_setmouse
call boot_log
call setmouse
 
; LOAD FIRST APPLICATION
cmp byte [launcher_start], 1 ; Check if starting LAUNCHER is selected on blue screen (1 = yes)
jnz first_app_found
 
cli
mov ebp, firstapp
call fs_execute_from_sysdir
test eax, eax
jns first_app_found
 
mov esi, boot_failed
call boot_log
 
mov eax, 0xDEADBEEF ; otherwise halt
hlt
 
first_app_found:
 
; START MULTITASKING
preboot_blogesc = 0 ; start immediately after bootlog
 
; A 'All set - press ESC to start' messages if need
if preboot_blogesc
mov esi, boot_tasking
call boot_log
.bll1:
in al, 0x60 ; wait for ESC key press
cmp al, 129
jne .bll1
end if
 
mov [timer_ticks_enable], 1 ; for cd driver
 
sti
 
call mtrr_validate
 
jmp osloop
 
 
; Fly :)
 
uglobal
align 4
ap_initialized dd 0
endg
 
ap_init_high:
mov ax, os_stack
mov bx, app_data
mov cx, app_tls
mov ss, ax
mov ds, bx
mov es, bx
mov fs, cx
mov gs, bx
xor esp, esp
mov eax, sys_proc-OS_BASE+PROC.pdt_0
mov cr3, eax
lock inc [ap_initialized]
jmp idle_loop
 
 
include 'unpacker.inc'
 
align 4
boot_log:
pushad
 
mov ebx, 10*65536
mov bx, word [boot_y]
add [boot_y], dword 10
mov ecx, 0x80ffffff; ASCIIZ string with white color
xor edi, edi
mov edx, esi
inc edi
call dtext
 
mov [novesachecksum], 1000
call checkVga_N13
 
popad
 
ret
 
;-----------------------------------------------------------------------------
; Register ramdisk file system
register_ramdisk:
mov esi, boot_initramdisk
call boot_log
call ramdisk_init
ret
 
; in: edx -> APPDATA for OS/IDLE slot
; in: ebx = stack base
proc setup_os_slot
xor eax, eax
mov ecx, sizeof.APPDATA/4
mov edi, edx
rep stosd
 
mov eax, tss+0x80
call get_pg_addr
inc eax
mov [edx+APPDATA.io_map], eax
mov eax, tss+0x1080
call get_pg_addr
inc eax
mov [edx+APPDATA.io_map+4], eax
 
mov dword [edx+APPDATA.pl0_stack], ebx
lea edi, [ebx+RING0_STACK_SIZE]
mov dword [edx+APPDATA.fpu_state], edi
mov dword [edx+APPDATA.saved_esp0], edi
mov dword [edx+APPDATA.saved_esp], edi
mov dword [edx+APPDATA.terminate_protection], 1 ; make unkillable
 
mov esi, fpu_data
mov ecx, [xsave_area_size]
add ecx, 3
shr ecx, 2
rep movsd
 
lea eax, [edx+APP_EV_OFFSET]
mov dword [edx+APPDATA.fd_ev], eax
mov dword [edx+APPDATA.bk_ev], eax
 
lea eax, [edx+APP_OBJ_OFFSET]
mov dword [edx+APPDATA.fd_obj], eax
mov dword [edx+APPDATA.bk_obj], eax
 
mov dword [edx+APPDATA.cur_dir], sysdir_path-2
 
mov [edx + APPDATA.process], sys_proc
 
lea ebx, [edx+APPDATA.list]
lea ecx, [sys_proc+PROC.thr_list]
list_add_tail ebx, ecx
 
mov eax, edx
shr eax, 3
add eax, TASK_TABLE - (SLOT_BASE shr 3)
mov [eax+TASKDATA.wnd_number], dh
mov byte [eax+TASKDATA.pid], dh
 
ret
endp
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; MAIN OS LOOP START ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
align 32
osloop:
mov edx, osloop_has_work?
xor ecx, ecx
call Wait_events
xor eax, eax
xchg eax, [osloop_nonperiodic_work]
test eax, eax
jz .no_periodic
 
call __sys_draw_pointer
call window_check_events
call mouse_check_events
call checkmisc
call checkVga_N13
;--------------------------------------
.no_periodic:
call stack_handler
call check_fdd_motor_status
call check_ATAPI_device_event
call check_lights_state
call check_timers
 
jmp osloop
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; MAIN OS LOOP END ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
proc osloop_has_work?
cmp [osloop_nonperiodic_work], 0
jnz .yes
call stack_handler_has_work?
jnz .yes
call check_fdd_motor_status_has_work?
jnz .yes
call check_ATAPI_device_event_has_work?
jnz .yes
call check_lights_state_has_work?
jnz .yes
call check_timers_has_work?
jnz .yes
.no:
xor eax, eax
ret
.yes:
xor eax, eax
inc eax
ret
endp
 
proc wakeup_osloop
mov [osloop_nonperiodic_work], 1
ret
endp
 
uglobal
align 4
osloop_nonperiodic_work dd ?
endg
 
uglobal
align 64
idle_addr rb 64
endg
 
idle_thread:
sti
 
; The following code can be executed by all CPUs in the system.
; All other parts of the kernel do not expect multi-CPU.
; Also, APs don't even have a stack here.
; Beware. Don't do anything here. Anything at all.
idle_loop:
cmp [use_mwait_for_idle], 0
jnz idle_loop_mwait
 
idle_loop_hlt:
hlt
jmp idle_loop_hlt
 
idle_loop_mwait:
mov eax, idle_addr
xor ecx, ecx
xor edx, edx
monitor
xor ecx, ecx
mov eax, 20h ; or 10h
mwait
jmp idle_loop_mwait
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; INCLUDED SYSTEM FILES ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
include "kernel32.inc"
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; KERNEL FUNCTIONS ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
reserve_irqs_ports:
 
 
; RESERVE PORTS
mov eax, RESERVED_PORTS
mov ecx, 1
 
mov [eax], dword 4
 
mov [eax+16], ecx
mov [eax+16+4], dword 0
mov [eax+16+8], dword 0x2D
 
mov [eax+32], ecx
mov [eax+32+4], dword 0x30
mov [eax+32+8], dword 0x4D
 
mov [eax+48], ecx
mov [eax+48+4], dword 0x50
mov [eax+48+8], dword 0xDF
 
mov [eax+64], ecx
mov [eax+64+4], dword 0xE5
mov [eax+64+8], dword 0xFF
 
ret
 
 
iglobal
process_number dd 0x2
endg
 
set_variables:
 
mov ecx, 0x16 ; flush port 0x60
.fl60:
in al, 0x60
loop .fl60
push eax
 
mov ax, [BOOT.y_res]
shr ax, 1
shl eax, 16
mov ax, [BOOT.x_res]
shr ax, 1
mov [MOUSE_X], eax
call wakeup_osloop
 
xor eax, eax
mov [BTN_ADDR], dword BUTTON_INFO ; address of button list
 
mov byte [KEY_COUNT], al ; keyboard buffer
mov byte [BTN_COUNT], al ; button buffer
; mov [MOUSE_X],dword 100*65536+100 ; mouse x/y
 
pop eax
ret
 
align 4
;input eax=43,bl-byte of output, ecx - number of port
sys_outport:
 
mov edi, ecx ; separate flag for read / write
and ecx, 65535
 
mov eax, [RESERVED_PORTS]
test eax, eax
jnz .sopl8
inc eax
mov [esp+32], eax
ret
 
.sopl8:
mov edx, [TASK_BASE]
mov edx, [edx+0x4]
;and ecx,65535
;cld - set on interrupt 0x40
.sopl1:
 
mov esi, eax
shl esi, 4
add esi, RESERVED_PORTS
cmp edx, [esi+0]
jne .sopl2
cmp ecx, [esi+4]
jb .sopl2
cmp ecx, [esi+8]
jg .sopl2
.sopl3:
 
test edi, 0x80000000; read ?
jnz .sopl4
 
mov eax, ebx
mov dx, cx ; write
out dx, al
and [esp+32], dword 0
ret
 
.sopl2:
 
dec eax
jnz .sopl1
inc eax
mov [esp+32], eax
ret
 
 
.sopl4:
 
mov dx, cx ; read
in al, dx
and eax, 0xff
and [esp+32], dword 0
mov [esp+20], eax
ret
 
display_number:
; add check pointers
test bl, bl
jz @f
stdcall is_region_userspace, ecx, 1
jz @f
ret
@@:
test esi, 0x08000000
jz @f
stdcall is_region_userspace, edi, 1
jz @f
ret
@@:
;It is not optimization
mov eax, ebx
mov ebx, ecx
mov ecx, edx
mov edx, esi
mov esi, edi
; eax = print type, al=0 -> ebx is number
; al=1 -> ebx is pointer
; ah=0 -> display decimal
; ah=1 -> display hexadecimal
; ah=2 -> display binary
; eax bits 16-21 = number of digits to display (0-32)
; eax bits 22-31 = reserved
;
; ebx = number or pointer
; ecx = x shl 16 + y
; edx = color
xor edi, edi
display_number_force:
push eax
and eax, 0x3fffffff
cmp eax, 0xffff ; length > 0 ?
pop eax
jge cont_displ
ret
cont_displ:
push eax
and eax, 0x3fffffff
cmp eax, 61*0x10000 ; length <= 60 ?
pop eax
jb cont_displ2
ret
cont_displ2:
 
pushad
 
cmp al, 1 ; ecx is a pointer ?
jne displnl1
mov ebp, ebx
add ebp, 4
mov ebp, [ebp+std_application_base_address]
mov ebx, [ebx+std_application_base_address]
displnl1:
sub esp, 64
 
test ah, ah ; DECIMAL
jnz no_display_desnum
shr eax, 16
and eax, 0xC03f
; and eax,0x3f
push eax
and eax, 0x3f
mov edi, esp
add edi, 4+64-1
mov ecx, eax
mov eax, ebx
mov ebx, 10
d_desnum:
xor edx, edx
call division_64_bits
div ebx
add dl, 48
mov [edi], dl
dec edi
loop d_desnum
pop eax
call normalize_number
call draw_num_text
add esp, 64
popad
ret
no_display_desnum:
 
cmp ah, 0x01 ; HEXADECIMAL
jne no_display_hexnum
shr eax, 16
and eax, 0xC03f
; and eax,0x3f
push eax
and eax, 0x3f
mov edi, esp
add edi, 4+64-1
mov ecx, eax
mov eax, ebx
mov ebx, 16
d_hexnum:
xor edx, edx
call division_64_bits
div ebx
hexletters = __fdo_hexdigits
add edx, hexletters
mov dl, [edx]
mov [edi], dl
dec edi
loop d_hexnum
pop eax
call normalize_number
call draw_num_text
add esp, 64
popad
ret
no_display_hexnum:
 
cmp ah, 0x02 ; BINARY
jne no_display_binnum
shr eax, 16
and eax, 0xC03f
; and eax,0x3f
push eax
and eax, 0x3f
mov edi, esp
add edi, 4+64-1
mov ecx, eax
mov eax, ebx
mov ebx, 2
d_binnum:
xor edx, edx
call division_64_bits
div ebx
add dl, 48
mov [edi], dl
dec edi
loop d_binnum
pop eax
call normalize_number
call draw_num_text
add esp, 64
popad
ret
no_display_binnum:
 
add esp, 64
popad
ret
 
normalize_number:
test ah, 0x80
jz .continue
mov ecx, 48
and eax, 0x3f
@@:
inc edi
cmp [edi], cl
jne .continue
dec eax
cmp eax, 1
ja @r
mov al, 1
.continue:
and eax, 0x3f
ret
 
division_64_bits:
test [esp+1+4], byte 0x40
jz .continue
push eax
mov eax, ebp
div ebx
mov ebp, eax
pop eax
.continue:
ret
 
draw_num_text:
mov esi, eax
mov edx, 64+4
sub edx, eax
add edx, esp
mov ebx, [esp+64+32-8+4]
; add window start x & y
mov ecx, [TASK_BASE]
 
mov edi, [current_slot_idx]
shl edi, 8
 
mov eax, [ecx-twdw+WDATA.box.left]
add eax, [edi+SLOT_BASE+APPDATA.wnd_clientbox.left]
shl eax, 16
add eax, [ecx-twdw+WDATA.box.top]
add eax, [edi+SLOT_BASE+APPDATA.wnd_clientbox.top]
add ebx, eax
mov ecx, [esp+64+32-12+4]
mov eax, [esp+64+8] ; background color (if given)
mov edi, [esp+64+4]
and ecx, 5FFFFFFFh
bt ecx, 27
jnc @f
mov edi, eax
@@:
jmp dtext
;-----------------------------------------------------------------------------
iglobal
midi_base dw 0
endg
;-----------------------------------------------------------------------------
align 4
sys_setup:
; 1 = roland mpu midi base , base io address
; 2 = keyboard 1, base kaybap 2, shift keymap, 9 country 1eng 2fi 3ger 4rus
; 3 = not used
; 4 = not used
; 5 = system language, 1eng 2fi 3ger 4rus
; 6 = not used
; 7 = not used
; 8 = not used
; 9 = not used
; 10 = not used
; 11 = enable lba read
; 12 = enable pci access
;-----------------------------------------------------------------------------
and [esp+32], dword 0
; F.21.1 - set MPU MIDI base port
dec ebx
jnz @f
 
cmp ecx, 0x100
jb @f
 
mov esi, 65535
cmp esi, ecx
jb @f
 
mov [midi_base], cx
mov word [mididp], cx
inc cx
mov word [midisp], cx
ret
;--------------------------------------
@@:
; F.21.2 - set keyboard layout
dec ebx
jnz @f
 
mov edi, [TASK_BASE]
mov eax, [edi+TASKDATA.mem_start]
add eax, edx
; 1 = normal layout
dec ecx
jnz .shift
 
mov ebx, keymap
mov ecx, 128
call memmove
ret
;--------------------------------------
.shift:
; 2 = layout at pressed Shift
dec ecx
jnz .alt
 
mov ebx, keymap_shift
mov ecx, 128
call memmove
ret
;--------------------------------------
.alt:
; 3 = layout at pressed Alt
dec ecx
jnz .country
 
mov ebx, keymap_alt
mov ecx, 128
call memmove
ret
;--------------------------------------
.country:
; country identifier
sub ecx, 6
jnz .error
 
mov word [keyboard], dx
ret
;--------------------------------------
@@:
; F.21.5 - set system language
sub ebx, 3
jnz @f
 
mov [syslang], ecx
ret
;--------------------------------------
@@:
; F.21.11 - enable/disable low-level access to HD
and ecx, 1
sub ebx, 6
jnz @f
 
mov [lba_read_enabled], ecx
ret
;--------------------------------------
@@:
; F.21.12 - enable/disable low-level access to PCI
dec ebx
jnz .error
 
mov [pci_access_enabled], ecx
ret
;--------------------------------------
.error:
or [esp+32], dword -1
ret
;-----------------------------------------------------------------------------
align 4
sys_getsetup:
; 1 = roland mpu midi base , base io address
; 2 = keyboard 1, base kaybap 2, shift keymap, 9 country 1eng 2fi 3ger 4rus
; 3 = not used
; 4 = not used
; 5 = system language, 1eng 2fi 3ger 4rus
; 6 = not used
; 7 = not used
; 8 = not used
; 9 = get hs timer tic
; 10 = not used
; 11 = get the state "lba read"
; 12 = get the state "pci access"
;-----------------------------------------------------------------------------
; F.26.1 - get MPU MIDI base port
dec ebx
jnz @f
 
movzx eax, [midi_base]
mov [esp+32], eax
ret
;--------------------------------------
@@:
; F.26.2 - get keyboard layout
dec ebx
jnz @f
 
mov edi, [TASK_BASE]
mov ebx, [edi+TASKDATA.mem_start]
add ebx, edx
; 1 = normal layout
dec ecx
jnz .shift
 
; if given memory address belongs to kernel then error
stdcall is_region_userspace, ebx, 128
jnz .addr_error
 
mov eax, keymap
mov ecx, 128
call memmove
ret
;--------------------------------------
.shift:
; 2 = layout with pressed Shift
dec ecx
jnz .alt
 
stdcall is_region_userspace, ebx, 128
jnz .addr_error
 
mov eax, keymap_shift
mov ecx, 128
call memmove
ret
;--------------------------------------
.alt:
; 3 = layout with pressed Alt
dec ecx
jne .country
 
stdcall is_region_userspace, ebx, 128
jnz .addr_error
 
mov eax, keymap_alt
mov ecx, 128
call memmove
ret
;--------------------------------------
.country:
; 9 = country identifier
sub ecx, 6
jnz .error
 
movzx eax, word [keyboard]
mov [esp+32], eax
ret
 
.addr_error: ; if given memory address is illegal
mov dword [esp+32], -1
ret
;--------------------------------------
@@:
; F.26.5 - get system language
sub ebx, 3
jnz @f
 
mov eax, [syslang]
mov [esp+32], eax
ret
;--------------------------------------
@@:
; F.26.9 - get the value of the time counter
sub ebx, 4
jnz @f
 
mov eax, [timer_ticks]
mov [esp+32], eax
ret
;--------------------------------------
@@:
; F.26.10 - get the time from kernel launch in nanoseconds
sub ebx, 1
jnz @f
 
call get_clock_ns
mov [esp+24], edx
mov [esp+32], eax
ret
;--------------------------------------
@@:
; F.26.11 - Find out whether low-level HD access is enabled
sub ebx, 1
jnz @f
 
mov eax, [lba_read_enabled]
mov [esp+32], eax
ret
;--------------------------------------
@@:
; F.26.12 - Find out whether low-level PCI access is enabled
dec ebx
jnz .error
 
mov eax, [pci_access_enabled]
mov [esp+32], eax
ret
;--------------------------------------
.error:
or [esp+32], dword -1
ret
;-----------------------------------------------------------------------------
get_timer_ticks:
mov eax, [timer_ticks]
ret
;-----------------------------------------------------------------------------
readmousepos:
; eax=0 screen relative
; eax=1 window relative
; eax=2 buttons pressed
; eax=3 buttons pressed ext
; eax=4 load cursor
; eax=5 set cursor
; eax=6 delete cursor
; eax=7 get mouse_z
; eax=8 load cursor unicode
cmp ebx, 8
ja @f
jmp dword[.mousefn+ebx*4]
 
align 4
.mousefn:
dd .msscreen
dd .mswin
dd .msbutton
dd .msbuttonExt
dd .app_load_cursor
dd .app_set_cursor
dd .app_delete_cursor
dd .msz
dd .loadCursorUni
 
.msscreen:
mov eax, [MOUSE_X]
shl eax, 16
mov ax, [MOUSE_Y]
mov [esp+36-4], eax
@@:
ret
 
.mswin:
mov eax, [MOUSE_X]
shl eax, 16
mov ax, [MOUSE_Y]
mov esi, [TASK_BASE]
mov bx, word [esi-twdw+WDATA.box.left]
shl ebx, 16
mov bx, word [esi-twdw+WDATA.box.top]
sub eax, ebx
mov edi, [current_slot_idx]
shl edi, 8
sub ax, word[edi+SLOT_BASE+APPDATA.wnd_clientbox.top]
rol eax, 16
sub ax, word[edi+SLOT_BASE+APPDATA.wnd_clientbox.left]
rol eax, 16
mov [esp+36-4], eax
ret
 
.msbutton:
movzx eax, byte [BTN_DOWN]
mov [esp+36-4], eax
ret
 
.msbuttonExt:
mov eax, [BTN_DOWN]
mov [esp+36-4], eax
ret
 
.app_load_cursor:
cmp ecx, OS_BASE
jae @f
stdcall load_cursor, ecx, edx
mov [esp+36-4], eax
@@:
ret
 
.loadCursorUni:
cmp ecx, OS_BASE
jae @b
push ecx edx
stdcall kernel_alloc, maxPathLength
mov edi, eax
pop eax esi
push edi
call getFullPath
pop ebp
test eax, eax
jz @f
stdcall load_cursor, ebp, LOAD_FROM_FILE
mov [esp+32], eax
@@:
stdcall kernel_free, ebp
ret
 
.app_set_cursor:
stdcall set_cursor, ecx
mov [esp+36-4], eax
ret
 
.app_delete_cursor:
stdcall delete_cursor, ecx
mov [esp+36-4], eax
ret
 
.msz:
mov edi, [thread_count]
movzx edi, word [WIN_POS + edi*2]
cmp edi, [current_slot_idx]
jne @f
mov ax, [MOUSE_SCROLL_H]
shl eax, 16
mov ax, [MOUSE_SCROLL_V]
mov [esp+36-4], eax
and [MOUSE_SCROLL_H], word 0
and [MOUSE_SCROLL_V], word 0
ret
@@:
and [esp+36-4], dword 0
ret
 
is_input:
 
push edx
mov dx, word [midisp]
in al, dx
and al, 0x80
pop edx
ret
 
is_output:
 
push edx
mov dx, word [midisp]
in al, dx
and al, 0x40
pop edx
ret
 
 
get_mpu_in:
 
push edx
mov dx, word [mididp]
in al, dx
pop edx
ret
 
 
put_mpu_out:
 
push edx
mov dx, word [mididp]
out dx, al
pop edx
ret
 
 
 
align 4
 
sys_midi:
cmp [mididp], 0
jnz sm0
mov [esp+36], dword 1
ret
sm0:
and [esp+36], dword 0
dec ebx
jnz smn1
; call setuart
su1:
call is_output
test al, al
jnz su1
mov dx, word [midisp]
mov al, 0xff
out dx, al
su2:
mov dx, word [midisp]
mov al, 0xff
out dx, al
call is_input
test al, al
jnz su2
call get_mpu_in
cmp al, 0xfe
jnz su2
su3:
call is_output
test al, al
jnz su3
mov dx, word [midisp]
mov al, 0x3f
out dx, al
ret
smn1:
dec ebx
jnz smn2
sm10:
call get_mpu_in
call is_output
test al, al
jnz sm10
mov al, bl
call put_mpu_out
smn2:
ret
 
detect_devices:
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;include 'detect/commouse.inc'
;include 'detect/ps2mouse.inc'
;include 'detect/dev_fd.inc'
;include 'detect/dev_hdcd.inc'
;include 'detect/sear_par.inc'
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
ret
 
sys_end:
;--------------------------------------
cmp [_display.select_cursor], 0
je @f
; restore default cursor before killing
pusha
mov ecx, [current_slot]
call restore_default_cursor_before_killing
popa
@@:
;--------------------------------------
; kill all sockets this process owns
pusha
mov edx, [TASK_BASE]
mov edx, [edx+TASKDATA.pid]
call socket_process_end
popa
;--------------------------------------
mov ecx, [current_slot]
mov eax, [ecx+APPDATA.tls_base]
test eax, eax
jz @F
 
stdcall user_free, eax
@@:
 
mov eax, [TASK_BASE]
mov [eax+TASKDATA.state], TSTATE_ZOMBIE
call wakeup_osloop
 
.waitterm: ; wait here for termination
call change_task
jmp .waitterm
;------------------------------------------------------------------------------
align 4
restore_default_cursor_before_killing:
pushfd
cli
mov eax, [def_cursor]
mov [ecx+APPDATA.cursor], eax
 
movzx eax, word [MOUSE_Y]
movzx ebx, word [MOUSE_X]
mov eax, [d_width_calc_area + eax*4]
 
add eax, [_display.win_map]
movzx edx, byte [ebx+eax]
shl edx, 8
mov esi, [edx+SLOT_BASE+APPDATA.cursor]
 
cmp esi, [current_cursor]
je @f
 
push esi
call [_display.select_cursor]
mov [current_cursor], esi
@@:
mov [redrawmouse_unconditional], 1
call wakeup_osloop
popfd
ret
;------------------------------------------------------------------------------
iglobal
align 4
sys_system_table:
dd sysfn_deactivate ; 1 = deactivate window
dd sysfn_terminate ; 2 = terminate thread
dd sysfn_activate ; 3 = activate window
dd sysfn_getidletime ; 4 = get idle time
dd sysfn_getcpuclock ; 5 = get cpu clock
dd sysfn_saveramdisk ; 6 = save ramdisk
dd sysfn_getactive ; 7 = get active window
dd sysfn_sound_flag ; 8 = get/set sound_flag
dd sysfn_shutdown ; 9 = shutdown with parameter
dd sysfn_minimize ; 10 = minimize window
dd sysfn_getdiskinfo ; 11 = get disk subsystem info
dd sysfn_lastkey ; 12 = get last pressed key
dd sysfn_getversion ; 13 = get kernel version
dd sysfn_waitretrace ; 14 = wait retrace
dd sysfn_centermouse ; 15 = center mouse cursor
dd sysfn_getfreemem ; 16 = get free memory size
dd sysfn_getallmem ; 17 = get total memory size
dd sysfn_terminate2 ; 18 = terminate thread using PID
; instead of slot
dd sysfn_mouse_acceleration; 19 = set/get mouse acceleration
dd sysfn_meminfo ; 20 = get extended memory info
dd sysfn_pid_to_slot ; 21 = get slot number for pid
dd sysfn_min_rest_window ; 22 = minimize and restore any window
dd sysfn_min_windows ; 23 = minimize all windows
dd sysfn_set_screen_sizes ; 24 = set screen sizes for Vesa
 
dd sysfn_zmodif ; 25 = get/set window z modifier ;Fantomer
sysfn_num = ($ - sys_system_table)/4
endg
;------------------------------------------------------------------------------
sys_system:
dec ebx
cmp ebx, sysfn_num
jae @f
jmp dword [sys_system_table + ebx*4]
@@:
ret
;------------------------------------------------------------------------------
sysfn_shutdown: ; 18.9 = system shutdown
cmp ecx, SYSTEM_SHUTDOWN
jl exit_for_anyone
cmp ecx, SYSTEM_RESTART
jg exit_for_anyone
mov [BOOT.shutdown_type], cl
 
mov eax, [thread_count]
mov [SYS_SHUTDOWN], al
mov [shutdown_processes], eax
call wakeup_osloop
and dword [esp+32], 0
exit_for_anyone:
ret
uglobal
shutdown_processes:
dd 0x0
endg
;------------------------------------------------------------------------------
; in: eax -- APPDATA ptr
; out: Z/z -- is/not kernel thread
is_kernel_thread:
mov eax, [eax+APPDATA.process]
cmp eax, [SLOT_BASE+2*sizeof.APPDATA+APPDATA.process] ; OS
ret
;------------------------------------------------------------------------------
sysfn_terminate: ; 18.2 = TERMINATE
push ecx
cmp ecx, 2
jb noprocessterminate
mov edx, [thread_count]
cmp ecx, edx
ja noprocessterminate
mov eax, [thread_count]
shl ecx, BSF sizeof.TASKDATA
mov edx, [ecx+TASK_TABLE+TASKDATA.pid]
add ecx, TASK_TABLE+TASKDATA.state
cmp byte [ecx], TSTATE_FREE
jz noprocessterminate
push eax
lea eax, [(ecx-(TASK_TABLE and 1FFFFFFFh)-TASKDATA.state)*8+SLOT_BASE]
call is_kernel_thread
pop eax
jz noprocessterminate
push ecx edx
lea edx, [(ecx-(TASK_TABLE and 1FFFFFFFh)-TASKDATA.state)*8+SLOT_BASE]
call request_terminate
pop edx ecx
test eax, eax
jz noprocessterminate
;--------------------------------------
; terminate all network sockets it used
pusha
mov eax, edx
call socket_process_end
popa
;--------------------------------------
cmp [_display.select_cursor], 0
je .restore_end
; restore default cursor before killing
pusha
mov ecx, [esp+32]
shl ecx, 8
add ecx, SLOT_BASE
mov eax, [def_cursor]
cmp [ecx+APPDATA.cursor], eax
je @f
call restore_default_cursor_before_killing
@@:
popa
.restore_end:
;--------------------------------------
;call MEM_Heap_Lock ;guarantee that process isn't working with heap
mov [ecx], byte 3; clear possible i40's
call wakeup_osloop
;call MEM_Heap_UnLock
 
cmp edx, [application_table_owner]; clear app table stat
jne noatsc
call unlock_application_table
noatsc:
noprocessterminate:
add esp, 4
ret
;------------------------------------------------------------------------------
sysfn_terminate2:
;lock application_table_status mutex
.table_status:
call lock_application_table
mov eax, ecx
call pid_to_slot
test eax, eax
jz .not_found
mov ecx, eax
cli
call sysfn_terminate
call unlock_application_table
sti
and dword [esp+32], 0
ret
.not_found:
call unlock_application_table
or dword [esp+32], -1
ret
;------------------------------------------------------------------------------
sysfn_deactivate: ; 18.1 = DEACTIVATE WINDOW
cmp ecx, 2
jb .nowindowdeactivate
cmp ecx, [thread_count]
ja .nowindowdeactivate
 
movzx esi, word [WIN_STACK + ecx*2]
cmp esi, 1
je .nowindowdeactivate ; already deactive
 
mov edi, ecx
shl edi, 5
add edi, window_data
movzx esi, word [WIN_STACK + ecx * 2]
lea esi, [WIN_POS + esi * 2]
call window._.window_deactivate
call syscall_display_settings.calculateScreen
call syscall_display_settings.redrawScreen
.nowindowdeactivate:
ret
;------------------------------------------------------------------------------
sysfn_activate: ; 18.3 = ACTIVATE WINDOW
cmp ecx, 2
jb .nowindowactivate
cmp ecx, [thread_count]
ja .nowindowactivate
;-------------------------------------
@@:
; If the window is captured and moved by the user,
; then you can't change the position in window stack!!!
mov al, [mouse.active_sys_window.action]
and al, WINDOW_MOVE_AND_RESIZE_FLAGS
test al, al
jz @f
call change_task
jmp @b
@@:
;-------------------------------------
mov [window_minimize], 2; restore window if minimized
call wakeup_osloop
 
movzx esi, word [WIN_STACK + ecx*2]
cmp esi, [thread_count]
je .nowindowactivate; already active
 
mov edi, ecx
shl edi, 5
add edi, window_data
movzx esi, word [WIN_STACK + ecx * 2]
lea esi, [WIN_POS + esi * 2]
call waredraw
.nowindowactivate:
ret
;------------------------------------------------------------------------------
align 4
sysfn_zmodif:
;18,25,1 - get z_modif
;18,25,2 - set z_modif
;edx = -1(for current task) or TID
;esi(for 2) = new value z_modif
;return:
;1: eax = z_modif
;2: eax=0(fail),1(success) for set z_modif
 
cmp edx, -1
jne @f
mov edx, [current_slot_idx]
@@:
cmp edx, [thread_count]
ja .fail
cmp edx, 1
je .fail
 
mov eax, edx
shl edx, 5
 
cmp [edx + TASK_TABLE + TASKDATA.state], TSTATE_FREE
je .fail
 
cmp ecx, 1
jnz .set_zmod
 
mov al, [edx + window_data + WDATA.z_modif]
jmp .exit
 
.set_zmod:
cmp ecx, 2
jnz .fail
 
mov ebx, esi
mov esi, eax
 
cmp bl, ZPOS_ALWAYS_TOP
jg .fail
 
mov [edx + window_data + WDATA.z_modif], bl
 
mov eax, [edx + window_data + WDATA.box.left]
mov ebx, [edx + window_data + WDATA.box.top]
mov ecx, [edx + window_data + WDATA.box.width]
mov edx, [edx + window_data + WDATA.box.height]
add ecx, eax
add edx, ebx
call window._.set_screen
call window._.set_top_wnd
call window._.redraw_top_wnd
 
shl esi, 5
mov [esi + window_data + WDATA.fl_redraw], 1
 
 
mov eax, 1
jmp .exit
.fail:
xor eax, eax
.exit:
mov [esp+32], eax
ret
 
;------------------------------------------------------------------------------
sysfn_getidletime: ; 18.4 = GET IDLETIME
mov eax, [TASK_TABLE+32+TASKDATA.cpu_usage]
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
sysfn_getcpuclock: ; 18.5 = GET TSC/SEC
mov eax, dword [cpu_freq]
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
get_cpu_freq:
mov eax, dword [cpu_freq]
mov edx, dword [cpu_freq+4]
ret
; SAVE ramdisk to /hd/1/menuet.img
;!!!!!!!!!!!!!!!!!!!!!!!!
include 'blkdev/rdsave.inc'
;!!!!!!!!!!!!!!!!!!!!!!!!
;------------------------------------------------------------------------------
align 4
sysfn_getactive: ; 18.7 = get active window
mov eax, [thread_count]
movzx eax, word [WIN_POS + eax*2]
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
sysfn_sound_flag: ; 18.8 = get/set sound_flag
; cmp ecx,1
dec ecx
jnz nogetsoundflag
movzx eax, byte [sound_flag]; get sound_flag
mov [esp+32], eax
ret
nogetsoundflag:
; cmp ecx,2
dec ecx
jnz nosoundflag
xor byte [sound_flag], 1
nosoundflag:
ret
;------------------------------------------------------------------------------
sysfn_minimize: ; 18.10 = minimize window
mov [window_minimize], 1
call wakeup_osloop
ret
;------------------------------------------------------------------------------
align 4
sysfn_getdiskinfo: ; 18.11 = get disk info table
dec ecx
jnz .exit
.small_table:
stdcall is_region_userspace, edx, DRIVE_DATA_SIZE
jnz .exit
mov edi, edx
mov esi, DRIVE_DATA
mov ecx, DRIVE_DATA_SIZE ;10
cld
rep movsb
.exit:
ret
;------------------------------------------------------------------------------
sysfn_lastkey: ; 18.12 = return 0 (backward compatibility)
and dword [esp+32], 0
ret
;------------------------------------------------------------------------------
sysfn_getversion: ; 18.13 = get kernel ID and version
; if given memory address belongs to kernel then error
stdcall is_region_userspace, ecx, version_end-version_inf
jnz .addr_error
 
mov edi, ecx
mov esi, version_inf
mov ecx, version_end-version_inf
rep movsb
ret
.addr_error: ; if given memory address is illegal
mov dword [esp+32], -1
ret
;------------------------------------------------------------------------------
sysfn_waitretrace: ; 18.14 = sys wait retrace
;wait retrace functions
sys_wait_retrace:
mov edx, 0x3da
WaitRetrace_loop:
in al, dx
test al, 1000b
jz WaitRetrace_loop
and [esp+32], dword 0
ret
;------------------------------------------------------------------------------
align 4
sysfn_centermouse: ; 18.15 = mouse centered
mov eax, [_display.width]
shr eax, 1
mov [MOUSE_X], ax
mov eax, [_display.height]
shr eax, 1
mov [MOUSE_Y], ax
call wakeup_osloop
xor eax, eax
and [esp+32], eax
ret
;------------------------------------------------------------------------------
sysfn_mouse_acceleration: ; 18.19 = set/get mouse features
cmp ecx, 8
jnc @f
jmp dword [.table+ecx*4]
.get_mouse_acceleration:
xor eax, eax
mov ax, [mouse_speed_factor]
mov [esp+32], eax
ret
.set_mouse_acceleration:
mov [mouse_speed_factor], dx
ret
.get_mouse_delay:
xor eax, eax
mov al, [mouse_delay]
mov [esp+32], eax
ret
.set_mouse_delay:
mov [mouse_delay], dl
@@:
ret
.set_pointer_position:
cmp dx, word[_display.height]
jae @b
rol edx, 16
cmp dx, word[_display.width]
jae @b
mov [MOUSE_X], edx
mov [mouse_active], 1
jmp wakeup_osloop
.set_mouse_button:
mov [BTN_DOWN], edx
mov [mouse_active], 1
jmp wakeup_osloop
.get_doubleclick_delay:
xor eax, eax
mov al, [mouse_doubleclick_delay]
mov [esp+32], eax
ret
.set_doubleclick_delay:
mov [mouse_doubleclick_delay], dl
ret
align 4
.table:
dd .get_mouse_acceleration
dd .set_mouse_acceleration
dd .get_mouse_delay
dd .set_mouse_delay
dd .set_pointer_position
dd .set_mouse_button
dd .get_doubleclick_delay
dd .set_doubleclick_delay
;------------------------------------------------------------------------------
sysfn_getfreemem:
mov eax, [pg_data.pages_free]
shl eax, 2
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
sysfn_getallmem:
mov eax, [MEM_AMOUNT]
shr eax, 10
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
sysfn_pid_to_slot:
mov eax, ecx
call pid_to_slot
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
sysfn_min_rest_window:
pushad
mov eax, edx ; ebx - operating
shr ecx, 1
jnc @f
call pid_to_slot
@@:
or eax, eax ; eax - number of slot
jz .error
cmp eax, 255 ; varify maximal slot number
ja .error
movzx eax, word [WIN_STACK + eax*2]
shr ecx, 1
jc .restore
; .minimize:
call minimize_window
jmp .exit
.restore:
call restore_minimized_window
.exit:
popad
xor eax, eax
mov [esp+32], eax
ret
.error:
popad
xor eax, eax
dec eax
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
sysfn_min_windows:
call minimize_all_window
mov [esp+32], eax
call change_task
ret
;------------------------------------------------------------------------------
sysfn_set_screen_sizes:
cmp [SCR_MODE], word 0x13
jbe .exit
 
cmp [_display.select_cursor], select_cursor
jne .exit
 
cmp ecx, [display_width_standard]
ja .exit
 
cmp edx, [display_height_standard]
ja .exit
 
pushfd
cli
mov eax, ecx
mov ecx, [_display.lfb_pitch]
mov [_display.width], eax
dec eax
mov [_display.height], edx
dec edx
; eax - new Screen_Max_X
; edx - new Screen_Max_Y
mov [do_not_touch_winmap], 1
call set_screen
mov [do_not_touch_winmap], 0
popfd
call change_task
.exit:
ret
;------------------------------------------------------------------------------
uglobal
screen_workarea RECT
display_width_standard dd 0
display_height_standard dd 0
do_not_touch_winmap db 0
window_minimize db 0
sound_flag db 0
 
endg
 
UID_NONE=0
UID_MENUETOS=1 ;official
UID_KOLIBRI=2 ;russian
 
iglobal
version_inf:
db 0,7,7,0 ; version 0.7.7.0
db 0
.rev dd __REV__
version_end:
endg
;------------------------------------------------------------------------------
align 4
sys_cachetodiskette:
cmp ebx, 1
jb .no_floppy_save
cmp ebx, 2
ja .no_floppy_save
call save_image
mov [esp + 32], eax
ret
.no_floppy_save:
mov [esp + 32], dword 1
ret
;------------------------------------------------------------------------------
uglobal
; bgrchanged dd 0x0
align 4
bgrlockpid dd 0
bgrlock db 0
endg
;------------------------------------------------------------------------------
align 4
sys_background:
cmp ebx, 1 ; BACKGROUND SIZE
jnz nosb1
test ecx, ecx
jz sbgrr
 
test edx, edx
jz sbgrr
;--------------------------------------
align 4
@@:
;;Maxis use atomic bts for mutexes 4.4.2009
bts dword [bgrlock], 0
jnc @f
call change_task
jmp @b
;--------------------------------------
align 4
@@:
mov [BgrDataWidth], ecx
mov [BgrDataHeight], edx
; mov [bgrchanged],1
 
pushad
; return memory for old background
mov eax, [img_background]
cmp eax, static_background_data
jz @f
stdcall kernel_free, eax
;--------------------------------------
align 4
@@:
; calculate RAW size
xor eax, eax
inc eax
cmp [BgrDataWidth], eax
jae @f
mov [BgrDataWidth], eax
;--------------------------------------
align 4
@@:
cmp [BgrDataHeight], eax
jae @f
mov [BgrDataHeight], eax
;--------------------------------------
align 4
@@:
mov eax, [BgrDataWidth]
imul eax, [BgrDataHeight]
lea eax, [eax*3]
; it is reserved with aligned to the boundary of 4 KB pages,
; otherwise there may be exceptions a page fault for vesa20_drawbackground_tiled
; because the 32 bit read is used for high performance: "mov eax,[esi]"
shr eax, 12
inc eax
shl eax, 12
mov [mem_BACKGROUND], eax
; get memory for new background
stdcall kernel_alloc, eax
test eax, eax
jz .memfailed
mov [img_background], eax
jmp .exit
;--------------------------------------
align 4
.memfailed:
; revert to static monotone data
mov [img_background], static_background_data
xor eax, eax
inc eax
mov [BgrDataWidth], eax
mov [BgrDataHeight], eax
mov [mem_BACKGROUND], 4
;--------------------------------------
align 4
.exit:
popad
mov [bgrlock], 0
;--------------------------------------
align 4
sbgrr:
ret
;------------------------------------------------------------------------------
align 4
nosb1:
cmp ebx, 2 ; SET PIXEL
jnz nosb2
 
mov eax, [img_background]
test ecx, ecx
jz @f
cmp eax, static_background_data
jz .ret
;--------------------------------------
align 4
@@:
mov ebx, [mem_BACKGROUND]
add ebx, 4095
and ebx, -4096
sub ebx, 4
cmp ecx, ebx
ja .ret
 
mov ebx, [eax+ecx]
and ebx, 0xFF000000;255*256*256*256
and edx, 0x00FFFFFF;255*256*256+255*256+255
add edx, ebx
mov [eax+ecx], edx
;--------------------------------------
align 4
.ret:
ret
;------------------------------------------------------------------------------
align 4
nosb2:
cmp ebx, 3 ; DRAW BACKGROUND
jnz nosb3
;--------------------------------------
align 4
draw_background_temp:
mov [background_defined], 1
call force_redraw_background
;--------------------------------------
align 4
nosb31:
ret
;------------------------------------------------------------------------------
align 4
nosb3:
cmp ebx, 4 ; TILED / STRETCHED
jnz nosb4
cmp ecx, [BgrDrawMode]
je nosb41
mov [BgrDrawMode], ecx
;--------------------------------------
align 4
nosb41:
ret
;------------------------------------------------------------------------------
align 4
nosb4:
cmp ebx, 5 ; BLOCK MOVE TO BGR
jnz nosb5
 
; add check pointer
stdcall is_region_userspace, ecx, esi
jnz .fin
 
cmp [img_background], static_background_data
jnz @f
test edx, edx
jnz .fin
cmp esi, 4
ja .fin
;--------------------------------------
align 4
@@:
; bughere
mov eax, ecx
mov ebx, edx
add ebx, [img_background];IMG_BACKGROUND
mov ecx, esi
call memmove
;--------------------------------------
align 4
.fin:
ret
;------------------------------------------------------------------------------
align 4
nosb5:
cmp ebx, 6
jnz nosb6
;--------------------------------------
align 4
;;Maxis use atomic bts for mutex 4.4.2009
@@:
bts dword [bgrlock], 0
jnc @f
call change_task
jmp @b
;--------------------------------------
align 4
@@:
mov eax, [current_slot_idx]
mov [bgrlockpid], eax
cmp [img_background], static_background_data
jz .nomem
stdcall user_alloc, [mem_BACKGROUND]
mov [esp+32], eax
test eax, eax
jz .nomem
mov ebx, eax
shr ebx, 12
or dword [page_tabs+(ebx-1)*4], MEM_BLOCK_DONT_FREE
mov esi, [img_background]
shr esi, 12
mov ecx, [mem_BACKGROUND]
add ecx, 0xFFF
shr ecx, 12
;--------------------------------------
align 4
.z:
mov eax, [page_tabs+ebx*4]
test al, 1
jz @f
call free_page
;--------------------------------------
align 4
@@:
mov eax, [page_tabs+esi*4]
or al, PG_UWR
mov [page_tabs+ebx*4], eax
mov eax, ebx
shl eax, 12
invlpg [eax]
inc ebx
inc esi
loop .z
ret
;--------------------------------------
align 4
.nomem:
and [bgrlockpid], 0
mov [bgrlock], 0
;------------------------------------------------------------------------------
align 4
nosb6:
cmp ebx, 7
jnz nosb7
cmp [bgrlock], 0
jz .err
mov eax, [current_slot_idx]
cmp [bgrlockpid], eax
jnz .err
mov eax, ecx
mov ebx, ecx
shr eax, 12
mov ecx, [page_tabs+(eax-1)*4]
test cl, MEM_BLOCK_USED or MEM_BLOCK_DONT_FREE
jz .err
jnp .err
push eax
shr ecx, 12
dec ecx
;--------------------------------------
align 4
@@:
and dword [page_tabs+eax*4], 0
mov edx, eax
shl edx, 12
push eax
invlpg [edx]
pop eax
inc eax
loop @b
pop eax
and dword [page_tabs+(eax-1)*4], not MEM_BLOCK_DONT_FREE
stdcall user_free, ebx
mov [esp+32], eax
and [bgrlockpid], 0
mov [bgrlock], 0
ret
;--------------------------------------
align 4
.err:
and dword [esp+32], 0
ret
;------------------------------------------------------------------------------
align 4
nosb7:
cmp ebx, 8
jnz nosb8
 
mov ecx, [current_slot]
xor eax, eax
xchg eax, [ecx+APPDATA.draw_bgr_x]
mov [esp + 32], eax ; eax = [left]*65536 + [right]
xor eax, eax
xchg eax, [ecx+APPDATA.draw_bgr_y]
mov [esp + 20], eax ; ebx = [top]*65536 + [bottom]
ret
;------------------------------------------------------------------------------
align 4
nosb8:
cmp ebx, 9
jnz nosb9
; ecx = [left]*65536 + [right]
; edx = [top]*65536 + [bottom]
mov eax, [_display.width]
mov ebx, [_display.height]
; check [right]
cmp cx, ax
jae .exit
; check [left]
ror ecx, 16
cmp cx, ax
jae .exit
; check [bottom]
cmp dx, bx
jae .exit
; check [top]
ror edx, 16
cmp dx, bx
jae .exit
 
movzx eax, cx ; [left]
movzx ebx, dx ; [top]
 
shr ecx, 16 ; [right]
shr edx, 16 ; [bottom]
 
mov [background_defined], 1
 
mov [draw_data+32 + RECT.left], eax
mov [draw_data+32 + RECT.top], ebx
 
mov [draw_data+32 + RECT.right], ecx
mov [draw_data+32 + RECT.bottom], edx
 
inc [REDRAW_BACKGROUND]
call wakeup_osloop
;--------------------------------------
align 4
.exit:
ret
;------------------------------------------------------------------------------
align 4
nosb9:
ret
;------------------------------------------------------------------------------
align 4
uglobal
BG_Rect_X_left_right dd 0x0
BG_Rect_Y_top_bottom dd 0x0
endg
;------------------------------------------------------------------------------
align 4
force_redraw_background:
and [draw_data+32 + RECT.left], 0
and [draw_data+32 + RECT.top], 0
push eax ebx
mov eax, [_display.width]
mov ebx, [_display.height]
dec eax
dec ebx
mov [draw_data+32 + RECT.right], eax
mov [draw_data+32 + RECT.bottom], ebx
pop ebx eax
inc [REDRAW_BACKGROUND]
call wakeup_osloop
ret
;------------------------------------------------------------------------------
align 4
sys_getbackground:
; cmp eax,1 ; SIZE
dec ebx
jnz nogb1
mov eax, [BgrDataWidth]
shl eax, 16
mov ax, word [BgrDataHeight]
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
align 4
nogb1:
; cmp eax,2 ; PIXEL
dec ebx
jnz nogb2
 
mov eax, [img_background]
test ecx, ecx
jz @f
cmp eax, static_background_data
jz .ret
;--------------------------------------
align 4
@@:
mov ebx, [mem_BACKGROUND]
add ebx, 4095
and ebx, -4096
sub ebx, 4
cmp ecx, ebx
ja .ret
 
mov eax, [ecx+eax]
 
and eax, 0xFFFFFF
mov [esp+32], eax
;--------------------------------------
align 4
.ret:
ret
;------------------------------------------------------------------------------
align 4
nogb2:
 
; cmp eax,4 ; TILED / STRETCHED
dec ebx
dec ebx
jnz nogb4
mov eax, [BgrDrawMode]
;--------------------------------------
align 4
nogb4:
mov [esp+32], eax
ret
;------------------------------------------------------------------------------
align 4
sys_getkey:
mov [esp + 32], dword 1
; test main buffer
mov ebx, [current_slot_idx] ; TOP OF WINDOW STACK
movzx ecx, word [WIN_STACK + ebx * 2]
mov edx, [thread_count]
cmp ecx, edx
jne .finish
cmp [KEY_COUNT], byte 0
je .finish
movzx ax, byte [KEY_BUFF + 120 + 2]
shl eax, 8
mov al, byte [KEY_BUFF]
shl eax, 8
push eax
dec byte [KEY_COUNT]
and byte [KEY_COUNT], 127
movzx ecx, byte [KEY_COUNT]
add ecx, 2
mov eax, KEY_BUFF + 1
mov ebx, KEY_BUFF
call memmove
add eax, 120 + 2
add ebx, 120 + 2
call memmove
pop eax
;--------------------------------------
align 4
.ret_eax:
mov [esp + 32], eax
ret
;--------------------------------------
align 4
.finish:
; test hotkeys buffer
mov ecx, hotkey_buffer
;--------------------------------------
align 4
@@:
cmp [ecx], ebx
jz .found
add ecx, 8
cmp ecx, hotkey_buffer + 120 * 8
jb @b
ret
;--------------------------------------
align 4
.found:
mov ax, [ecx + 6]
shl eax, 16
mov ah, [ecx + 4]
mov al, 2
and dword [ecx + 4], 0
and dword [ecx], 0
jmp .ret_eax
;------------------------------------------------------------------------------
align 4
sys_getbutton:
mov ebx, [current_slot_idx] ; TOP OF WINDOW STACK
mov [esp + 32], dword 1
movzx ecx, word [WIN_STACK + ebx * 2]
mov edx, [thread_count] ; less than 256 processes
cmp ecx, edx
jne .exit
movzx eax, byte [BTN_COUNT]
test eax, eax
jz .exit
mov eax, [BTN_BUFF]
and al, 0xFE ; delete left button bit
mov [BTN_COUNT], byte 0
mov [esp + 32], eax
;--------------------------------------
align 4
.exit:
ret
;------------------------------------------------------------------------------
align 4
sys_cpuusage:
 
; RETURN:
;
; +00 dword process cpu usage
; +04 word position in windowing stack
; +06 word windowing stack value at current position (cpu nro)
; +10 12 bytes name
; +22 dword start in mem
; +26 dword used mem
; +30 dword PID , process idenfification number
;
; if given memory address belongs to kernel then error
stdcall is_region_userspace, ebx, 0x4C
jnz .addr_error
 
cmp ecx, -1 ; who am I ?
jne .no_who_am_i
mov ecx, [current_slot_idx]
.no_who_am_i:
cmp ecx, max_processes
ja .nofillbuf
 
; +4: word: position of the window of thread in the window stack
mov ax, [WIN_STACK + ecx * 2]
mov [ebx+4], ax
; +6: word: number of the thread slot, which window has in the window stack
; position ecx (has no relation to the specific thread)
mov ax, [WIN_POS + ecx * 2]
mov [ebx+6], ax
 
shl ecx, 5
 
; +0: dword: memory usage
mov eax, [ecx+TASK_TABLE+TASKDATA.cpu_usage]
mov [ebx], eax
; +10: 11 bytes: name of the process
push ecx
lea eax, [ecx*8+SLOT_BASE+APPDATA.app_name]
add ebx, 10
mov ecx, 11
call memmove
pop ecx
 
; +22: address of the process in memory
; +26: size of used memory - 1
push edi
lea edi, [ebx+12]
xor eax, eax
mov edx, 0x100000*16
cmp ecx, 1 shl 5
je .os_mem
mov edx, [SLOT_BASE+ecx*8+APPDATA.process]
mov edx, [edx+PROC.mem_used]
mov eax, std_application_base_address
.os_mem:
stosd
lea eax, [edx-1]
stosd
 
; +30: PID/TID
mov eax, [ecx+TASK_TABLE+TASKDATA.pid]
stosd
 
; window position and size
push esi
lea esi, [ecx + window_data + WDATA.box]
movsd
movsd
movsd
movsd
 
; Process state (+50)
movzx eax, byte [ecx+TASK_TABLE+TASKDATA.state]
stosd
 
; Window client area box
lea esi, [ecx*8 + SLOT_BASE + APPDATA.wnd_clientbox]
movsd
movsd
movsd
movsd
 
; Window state
mov al, [ecx+window_data+WDATA.fl_wstate]
stosb
 
; Event mask (+71)
mov EAX, dword [ECX+TASK_TABLE+TASKDATA.event_mask]
stosd
 
; Keyboard mode (+75)
mov al, byte [ecx*8 + SLOT_BASE + APPDATA.keyboard_mode]
stosb
 
pop esi
pop edi
 
.nofillbuf:
; return number of processes
 
mov eax, [thread_count]
mov [esp+32], eax
ret
 
.addr_error: ; if given memory address is illegal
mov dword [esp+32], -1
ret
 
align 4
sys_clock:
cli
; Mikhail Lisovin xx Jan 2005
@@:
mov al, 10
out 0x70, al
in al, 0x71
test al, al
jns @f
mov esi, 1
call delay_ms
jmp @b
@@:
; end Lisovin's fix
 
xor al, al ; seconds
out 0x70, al
in al, 0x71
movzx ecx, al
mov al, 02 ; minutes
shl ecx, 16
out 0x70, al
in al, 0x71
movzx edx, al
mov al, 04 ; hours
shl edx, 8
out 0x70, al
in al, 0x71
add ecx, edx
movzx edx, al
add ecx, edx
sti
mov [esp + 32], ecx
ret
 
 
align 4
 
sys_date:
 
cli
@@:
mov al, 10
out 0x70, al
in al, 0x71
test al, al
jns @f
mov esi, 1
call delay_ms
jmp @b
@@:
 
mov ch, 0
mov al, 7 ; date
out 0x70, al
in al, 0x71
mov cl, al
mov al, 8 ; month
shl ecx, 16
out 0x70, al
in al, 0x71
mov ch, al
mov al, 9 ; year
out 0x70, al
in al, 0x71
mov cl, al
sti
mov [esp+32], ecx
ret
 
 
; redraw status
 
sys_redrawstat:
cmp ebx, 1
jne no_widgets_away
; buttons away
mov ecx, [current_slot_idx]
sys_newba2:
mov edi, [BTN_ADDR]
cmp [edi], dword 0 ; empty button list ?
je end_of_buttons_away
movzx ebx, word [edi]
inc ebx
mov eax, edi
sys_newba:
dec ebx
jz end_of_buttons_away
 
add eax, 0x10
cmp cx, [eax]
jnz sys_newba
 
push eax ebx ecx
mov ecx, ebx
inc ecx
shl ecx, 4
mov ebx, eax
add eax, 0x10
call memmove
dec dword [edi]
pop ecx ebx eax
 
jmp sys_newba2
 
end_of_buttons_away:
 
ret
 
no_widgets_away:
 
cmp ebx, 2
jnz srl1
 
mov edx, [TASK_BASE] ; return whole screen draw area for this app
add edx, draw_data - TASK_TABLE
mov [edx + RECT.left], 0
mov [edx + RECT.top], 0
mov eax, [_display.width]
dec eax
mov [edx + RECT.right], eax
mov eax, [_display.height]
dec eax
mov [edx + RECT.bottom], eax
 
srl1:
ret
 
;ok - 100% work
;nt - not tested
;---------------------------------------------------------------------------------------------
;eax
;0 - task switch counter. Ret switch counter in eax. Block. ok.
;1 - change task. Ret nothing. Block. ok.
;2 - performance control
; ebx
; 0 - enable or disable (inversion) PCE flag on CR4 for rdmpc in user mode.
; returned new cr4 in eax. Ret cr4 in eax. Block. ok.
; 1 - is cache enabled. Ret cr0 in eax if enabled else zero in eax. Block. ok.
; 2 - enable cache. Ret 1 in eax. Ret nothing. Block. ok.
; 3 - disable cache. Ret 0 in eax. Ret nothing. Block. ok.
;eax
;3 - rdmsr. Counter in edx. (edx:eax) [esi:edi, edx] => [edx:esi, ecx]. Ret in ebx:eax. Block. ok.
;4 - wrmsr. Counter in edx. (edx:eax) [esi:edi, edx] => [edx:esi, ecx]. Ret in ebx:eax. Block. ok.
;---------------------------------------------------------------------------------------------
iglobal
align 4
sheduler:
dd sys_sheduler.00
dd change_task
dd sys_sheduler.02
dd sys_sheduler.03
dd sys_sheduler.04
endg
sys_sheduler:
;rewritten by <Lrz> 29.12.2009
jmp dword [sheduler+ebx*4]
;.shed_counter:
.00:
mov eax, [context_counter]
mov [esp+32], eax
ret
 
.02:
;.perf_control:
inc ebx ;before ebx=2, ebx=3
cmp ebx, ecx ;if ecx=3, ebx=3
jz cache_disable
 
dec ebx ;ebx=2
cmp ebx, ecx ;
jz cache_enable ;if ecx=2 and ebx=2
 
dec ebx ;ebx=1
cmp ebx, ecx
jz is_cache_enabled ;if ecx=1 and ebx=1
 
dec ebx
test ebx, ecx ;ebx=0 and ecx=0
jz modify_pce ;if ecx=0
 
ret
 
.03:
;.rdmsr_instr:
;now counter in ecx
;(edx:eax) esi:edi => edx:esi
mov eax, esi
mov ecx, edx
rdmsr
mov [esp+32], eax
mov [esp+20], edx ;ret in ebx?
ret
 
.04:
;.wrmsr_instr:
;now counter in ecx
;(edx:eax) esi:edi => edx:esi
; Fast Call MSR can't be destroy
; Но MSR_AMD_EFER можно изменять, т.к. в этом регистре лиш
; включаются/выключаются расширенные возможности
cmp edx, MSR_SYSENTER_CS
je @f
cmp edx, MSR_SYSENTER_ESP
je @f
cmp edx, MSR_SYSENTER_EIP
je @f
cmp edx, MSR_AMD_STAR
je @f
 
mov eax, esi
mov ecx, edx
wrmsr
; mov [esp + 32], eax
; mov [esp + 20], edx ;ret in ebx?
@@:
ret
 
cache_disable:
mov eax, cr0
or eax, 01100000000000000000000000000000b
mov cr0, eax
wbinvd ;set MESI
ret
 
cache_enable:
mov eax, cr0
and eax, 10011111111111111111111111111111b
mov cr0, eax
ret
 
is_cache_enabled:
mov eax, cr0
mov ebx, eax
and eax, 01100000000000000000000000000000b
jz cache_disabled
mov [esp+32], ebx
cache_disabled:
mov dword [esp+32], eax;0
ret
 
modify_pce:
mov eax, cr4
; mov ebx,0
; or bx,100000000b ;pce
; xor eax,ebx ;invert pce
bts eax, 8;pce=cr4[8]
mov cr4, eax
mov [esp+32], eax
ret
;---------------------------------------------------------------------------------------------
 
 
iglobal
cpustring db 'CPU',0
endg
 
uglobal
background_defined db 0 ; diamond, 11.04.2006
endg
;-----------------------------------------------------------------------------
align 4
checkmisc:
cmp [ctrl_alt_del], 1
jne nocpustart
 
mov ebp, cpustring
call fs_execute_from_sysdir
 
mov [ctrl_alt_del], 0
;--------------------------------------
align 4
nocpustart:
cmp [mouse_active], 1
jne mouse_not_active
mov [mouse_active], 0
 
xor edi, edi
mov ebx, TASK_TABLE
 
mov ecx, [thread_count]
movzx eax, word [WIN_POS + ecx*2] ; active window
shl eax, 8
push eax
 
movzx eax, word [MOUSE_X]
movzx edx, word [MOUSE_Y]
;--------------------------------------
align 4
.set_mouse_event:
add edi, sizeof.APPDATA
add ebx, sizeof.TASKDATA
test [ebx+TASKDATA.event_mask], 0x80000000
jz .pos_filter
 
cmp edi, [esp] ; skip if filtration active
jne .skip
;--------------------------------------
align 4
.pos_filter:
test [ebx+TASKDATA.event_mask], 0x40000000
jz .set
 
mov esi, [ebx-twdw+WDATA.box.left]
cmp eax, esi
jb .skip
add esi, [ebx-twdw+WDATA.box.width]
cmp eax, esi
ja .skip
 
mov esi, [ebx-twdw+WDATA.box.top]
cmp edx, esi
jb .skip
add esi, [ebx-twdw+WDATA.box.height]
cmp edx, esi
ja .skip
;--------------------------------------
align 4
.set:
or [edi+SLOT_BASE+APPDATA.occurred_events], EVENT_MOUSE
;--------------------------------------
align 4
.skip:
loop .set_mouse_event
 
pop eax
;--------------------------------------
align 4
mouse_not_active:
cmp [REDRAW_BACKGROUND], 0 ; background update ?
jz nobackgr
 
cmp [background_defined], 0
jz nobackgr
;--------------------------------------
align 4
backgr:
mov eax, [draw_data+32 + RECT.left]
shl eax, 16
add eax, [draw_data+32 + RECT.right]
mov [BG_Rect_X_left_right], eax ; [left]*65536 + [right]
 
mov eax, [draw_data+32 + RECT.top]
shl eax, 16
add eax, [draw_data+32 + RECT.bottom]
mov [BG_Rect_Y_top_bottom], eax ; [top]*65536 + [bottom]
 
call drawbackground
; DEBUGF 1, "K : drawbackground\n"
; DEBUGF 1, "K : backg x %x\n",[BG_Rect_X_left_right]
; DEBUGF 1, "K : backg y %x\n",[BG_Rect_Y_top_bottom]
;--------- set event 5 start ----------
push ecx edi
xor edi, edi
mov ecx, [thread_count]
;--------------------------------------
align 4
set_bgr_event:
add edi, sizeof.APPDATA
mov eax, [BG_Rect_X_left_right]
mov edx, [BG_Rect_Y_top_bottom]
cmp [edi+SLOT_BASE+APPDATA.draw_bgr_x], 0
jz .set
.join:
cmp word [edi+SLOT_BASE+APPDATA.draw_bgr_x], ax
jae @f
mov word [edi+SLOT_BASE+APPDATA.draw_bgr_x], ax
@@:
shr eax, 16
cmp word [edi+SLOT_BASE+APPDATA.draw_bgr_x+2], ax
jbe @f
mov word [edi+SLOT_BASE+APPDATA.draw_bgr_x+2], ax
@@:
cmp word [edi+SLOT_BASE+APPDATA.draw_bgr_y], dx
jae @f
mov word [edi+SLOT_BASE+APPDATA.draw_bgr_y], dx
@@:
shr edx, 16
cmp word [edi+SLOT_BASE+APPDATA.draw_bgr_y+2], dx
jbe @f
mov word [edi+SLOT_BASE+APPDATA.draw_bgr_y+2], dx
@@:
jmp .common
.set:
mov [edi+SLOT_BASE+APPDATA.draw_bgr_x], eax
mov [edi+SLOT_BASE+APPDATA.draw_bgr_y], edx
.common:
or [edi+SLOT_BASE+APPDATA.occurred_events], EVENT_BACKGROUND
loop set_bgr_event
pop edi ecx
;--------- set event 5 stop -----------
dec [REDRAW_BACKGROUND] ; got new update request?
jnz backgr
 
xor eax, eax
mov [draw_data+32 + RECT.left], eax
mov [draw_data+32 + RECT.top], eax
mov [draw_data+32 + RECT.right], eax
mov [draw_data+32 + RECT.bottom], eax
;--------------------------------------
align 4
nobackgr:
; system shutdown request
cmp [SYS_SHUTDOWN], byte 0
je noshutdown
 
mov edx, [shutdown_processes]
 
cmp [SYS_SHUTDOWN], dl
jne noshutdown
 
lea ecx, [edx-1]
mov edx, OS_BASE+0x3040
jecxz no_mark_system_shutdown
;--------------------------------------
align 4
markz:
push ecx edx
cmp [edx+TASKDATA.state], TSTATE_FREE
jz .nokill
lea edx, [(edx-(TASK_TABLE and 1FFFFFFFh))*8+SLOT_BASE]
cmp [edx+APPDATA.process], sys_proc
jz .nokill
call request_terminate
jmp .common
.nokill:
dec byte [SYS_SHUTDOWN]
xor eax, eax
.common:
pop edx ecx
test eax, eax
jz @f
mov [edx+TASKDATA.state], TSTATE_ZOMBIE
@@:
add edx, 0x20
loop markz
call wakeup_osloop
;--------------------------------------
align 4
@@:
no_mark_system_shutdown:
dec byte [SYS_SHUTDOWN]
je system_shutdown
;--------------------------------------
align 4
noshutdown:
mov eax, [thread_count] ; termination
mov ebx, TASK_DATA+TASKDATA.state
mov esi, 1
;--------------------------------------
align 4
newct:
mov cl, [ebx]
cmp cl, byte 3
jz .terminate
 
cmp cl, byte 4
jnz .noterminate
.terminate:
pushad
mov ecx, eax
shl ecx, 8
add ecx, SLOT_BASE
call restore_default_cursor_before_killing
popad
 
pushad
call terminate
popad
cmp byte [SYS_SHUTDOWN], 0
jz .noterminate
dec byte [SYS_SHUTDOWN]
je system_shutdown
 
.noterminate:
add ebx, 0x20
inc esi
dec eax
jnz newct
ret
;-----------------------------------------------------------------------------
align 4
redrawscreen:
; eax , if process window_data base is eax, do not set flag/limits
 
pushad
push eax
 
;;; mov ebx,2
;;; call delay_hs
 
;mov ecx,0 ; redraw flags for apps
xor ecx, ecx
;--------------------------------------
align 4
newdw2:
inc ecx
push ecx
 
mov eax, ecx
shl eax, 5
add eax, window_data
 
cmp eax, [esp+4]
je not_this_task
; check if window in redraw area
mov edi, eax
 
cmp ecx, 1 ; limit for background
jz bgli
 
mov eax, [esp+4] ;if upper in z-position - no redraw
test eax, eax
jz @f
mov al, [eax + WDATA.z_modif]
cmp [edi + WDATA.z_modif], al
jg ricino
@@:
 
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.top]
 
mov ecx, [draw_limits.bottom] ; ecx = area y end ebx = window y start
cmp ecx, ebx
jb ricino
 
mov ecx, [draw_limits.right] ; ecx = area x end eax = window x start
cmp ecx, eax
jb ricino
 
mov eax, [edi + WDATA.box.left]
mov ebx, [edi + WDATA.box.top]
mov ecx, [edi + WDATA.box.width]
mov edx, [edi + WDATA.box.height]
add ecx, eax
add edx, ebx
 
mov eax, [draw_limits.top] ; eax = area y start edx = window y end
cmp edx, eax
jb ricino
 
mov eax, [draw_limits.left] ; eax = area x start ecx = window x end
cmp ecx, eax
jb ricino
;--------------------------------------
align 4
bgli:
cmp dword[esp], 1
jnz .az
 
cmp [REDRAW_BACKGROUND], 0
jz .az
 
mov dl, 0
lea eax, [edi+draw_data-window_data]
mov ebx, [draw_limits.left]
cmp ebx, [eax+RECT.left]
jae @f
 
mov [eax+RECT.left], ebx
mov dl, 1
;--------------------------------------
align 4
@@:
mov ebx, [draw_limits.top]
cmp ebx, [eax+RECT.top]
jae @f
 
mov [eax+RECT.top], ebx
mov dl, 1
;--------------------------------------
align 4
@@:
mov ebx, [draw_limits.right]
cmp ebx, [eax+RECT.right]
jbe @f
 
mov [eax+RECT.right], ebx
mov dl, 1
;--------------------------------------
align 4
@@:
mov ebx, [draw_limits.bottom]
cmp ebx, [eax+RECT.bottom]
jbe @f
 
mov [eax+RECT.bottom], ebx
mov dl, 1
;--------------------------------------
align 4
@@:
add [REDRAW_BACKGROUND], dl
call wakeup_osloop
jmp newdw8
;--------------------------------------
align 4
.az:
mov eax, edi
add eax, draw_data-window_data
 
mov ebx, [draw_limits.left] ; set limits
mov [eax + RECT.left], ebx
mov ebx, [draw_limits.top]
mov [eax + RECT.top], ebx
mov ebx, [draw_limits.right]
mov [eax + RECT.right], ebx
mov ebx, [draw_limits.bottom]
mov [eax + RECT.bottom], ebx
 
sub eax, draw_data-window_data
 
cmp dword [esp], 1
jne nobgrd
inc [REDRAW_BACKGROUND]
call wakeup_osloop
;--------------------------------------
align 4
newdw8:
nobgrd:
;--------------------------------------
push eax edi ebp
mov edi, [esp+12]
cmp edi, 1
je .found
 
mov eax, [draw_limits.left]
mov ebx, [draw_limits.top]
mov ecx, [draw_limits.right]
sub ecx, eax
test ecx, ecx
jz .not_found
 
mov edx, [draw_limits.bottom]
sub edx, ebx
test edx, edx
jz .not_found
 
; eax - x, ebx - y
; ecx - size x, edx - size y
add ebx, edx
;--------------------------------------
align 4
.start_y:
push ecx
;--------------------------------------
align 4
.start_x:
add eax, ecx
mov ebp, [d_width_calc_area + ebx*4]
add ebp, [_display.win_map]
movzx ebp, byte[eax+ebp] ; get value for current point
cmp ebp, edi
jne @f
 
pop ecx
jmp .found
;--------------------------------------
align 4
@@:
sub eax, ecx
 
dec ecx
jnz .start_x
 
pop ecx
dec ebx
dec edx
jnz .start_y
;--------------------------------------
align 4
.not_found:
pop ebp edi eax
jmp ricino
;--------------------------------------
align 4
.found:
pop ebp edi eax
 
mov [eax + WDATA.fl_redraw], byte 1 ; mark as redraw
;--------------------------------------
align 4
ricino:
not_this_task:
pop ecx
 
cmp ecx, [thread_count]
jle newdw2
 
pop eax
popad
ret
;-----------------------------------------------------------------------------
align 4
calculatebackground: ; background
mov edi, [_display.win_map] ; set os to use all pixels
mov eax, 0x01010101
mov ecx, [_display.win_map_size]
shr ecx, 2
rep stosd
mov byte[window_data+32+WDATA.z_modif], ZPOS_DESKTOP
mov [REDRAW_BACKGROUND], 0
ret
;-----------------------------------------------------------------------------
uglobal
imax dd 0x0
endg
;-----------------------------------------------------------------------------
align 4
delay_ms: ; delay in 1/1000 sec
pushad
 
cmp [hpet_base], 0
jz .no_hpet
mov eax, esi
mov edx, 1_000_000 ; ms to ns
mul edx
mov ebx, edx
mov ecx, eax
 
push ecx
call get_clock_ns
pop ecx
mov edi, edx
mov esi, eax
.wait:
push ecx
call get_clock_ns
pop ecx
sub eax, esi
sbb edx, edi
sub eax, ecx
sbb edx, ebx
jc .wait
jmp .done
 
.no_hpet:
mov ecx, esi
; <CPU clock fix by Sergey Kuzmin aka Wildwest>
imul ecx, 33941
shr ecx, 9
; </CPU clock fix>
 
in al, 0x61
and al, 0x10
mov ah, al
cld
 
.cnt1:
in al, 0x61
and al, 0x10
cmp al, ah
jz .cnt1
 
mov ah, al
loop .cnt1
 
.done:
popad
ret
;-----------------------------------------------------------------------------
align 4
set_app_param:
mov edi, [TASK_BASE]
mov eax, ebx
xchg eax, [edi + TASKDATA.event_mask] ; set new event mask
mov [esp+32], eax ; return old mask value
ret
;-----------------------------------------------------------------------------
 
; this is for syscall
proc delay_hs_unprotected
call unprotect_from_terminate
call delay_hs
call protect_from_terminate
ret
endp
 
if 1
align 4
delay_hs: ; delay in 1/100 secs
; ebx = delay time
 
pushad
push ebx
xor esi, esi
mov ecx, MANUAL_DESTROY
call create_event
test eax, eax
jz .done
 
mov ebx, edx
mov ecx, [esp]
push edx
push eax
call wait_event_timeout
pop eax
pop ebx
call destroy_event
.done:
add esp, 4
popad
ret
 
else
 
align 4
delay_hs: ; delay in 1/100 secs
; ebx = delay time
push ecx
push edx
 
mov edx, [timer_ticks]
;--------------------------------------
align 4
newtic:
mov ecx, [timer_ticks]
sub ecx, edx
cmp ecx, ebx
jae zerodelay
 
call change_task
 
jmp newtic
;--------------------------------------
align 4
zerodelay:
pop edx
pop ecx
ret
end if
 
;-----------------------------------------------------------------------------
align 16 ;very often call this subrutine
memmove: ; memory move in bytes
; eax = from
; ebx = to
; ecx = no of bytes
test ecx, ecx
jle .ret
 
push esi edi ecx
 
mov edi, ebx
mov esi, eax
 
test ecx, not 11b
jz @f
 
push ecx
shr ecx, 2
rep movsd
pop ecx
and ecx, 11b
jz .finish
;--------------------------------------
align 4
@@:
rep movsb
;--------------------------------------
align 4
.finish:
pop ecx edi esi
;--------------------------------------
align 4
.ret:
ret
;-----------------------------------------------------------------------------
; <diamond> Sysfunction 34, read_floppy_file, is obsolete. Use 58 or 70 function instead.
;align 4
;
;read_floppy_file:
;
;; as input
;;
;; eax pointer to file
;; ebx file lenght
;; ecx start 512 byte block number
;; edx number of blocks to read
;; esi pointer to return/work area (atleast 20 000 bytes)
;;
;;
;; on return
;;
;; eax = 0 command succesful
;; 1 no fd base and/or partition defined
;; 2 yet unsupported FS
;; 3 unknown FS
;; 4 partition not defined at hd
;; 5 file not found
;; ebx = size of file
;
; mov edi,[TASK_BASE]
; add edi,0x10
; add esi,[edi]
; add eax,[edi]
;
; pushad
; mov edi,esi
; add edi,1024
; mov esi,0x100000+19*512
; sub ecx,1
; shl ecx,9
; add esi,ecx
; shl edx,9
; mov ecx,edx
; cld
; rep movsb
; popad
;
; mov [esp+36],eax
; mov [esp+24],ebx
; ret
 
 
 
align 4
set_io_access_rights:
push edi eax
mov edi, tss._io_map_0
; mov ecx,eax
; and ecx,7 ; offset in byte
; shr eax,3 ; number of byte
; add edi,eax
; mov ebx,1
; shl ebx,cl
test ebp, ebp
; cmp ebp,0 ; enable access - ebp = 0
jnz .siar1
; not ebx
; and [edi],byte bl
btr [edi], eax
pop eax edi
ret
.siar1:
bts [edi], eax
; or [edi],byte bl ; disable access - ebp = 1
pop eax edi
ret
;reserve/free group of ports
; * eax = 46 - number function
; * ebx = 0 - reserve, 1 - free
; * ecx = number start arrea of ports
; * edx = number end arrea of ports (include last number of port)
;Return value:
; * eax = 0 - succesful
; * eax = 1 - error
; * The system has reserve this ports:
; 0..0x2d, 0x30..0x4d, 0x50..0xdf, 0xe5..0xff (include last number of port).
;destroys eax,ebx, ebp
r_f_port_area:
 
test ebx, ebx
jnz free_port_area
; je r_port_area
; jmp free_port_area
 
; r_port_area:
 
; pushad
 
cmp ecx, edx ; beginning > end ?
ja rpal1
cmp edx, 65536
jae rpal1
mov eax, [RESERVED_PORTS]
test eax, eax ; no reserved areas ?
je rpal2
cmp eax, 255 ; max reserved
jae rpal1
rpal3:
mov ebx, eax
shl ebx, 4
add ebx, RESERVED_PORTS
cmp ecx, [ebx+8]
ja rpal4
cmp edx, [ebx+4]
jae rpal1
; jb rpal4
; jmp rpal1
rpal4:
dec eax
jnz rpal3
jmp rpal2
rpal1:
; popad
; mov eax,1
xor eax, eax
inc eax
ret
rpal2:
; popad
; enable port access at port IO map
cli
pushad ; start enable io map
 
cmp edx, 65536;16384
jae no_unmask_io; jge
mov eax, ecx
; push ebp
xor ebp, ebp ; enable - eax = port
new_port_access:
; pushad
call set_io_access_rights
; popad
inc eax
cmp eax, edx
jbe new_port_access
; pop ebp
no_unmask_io:
popad ; end enable io map
sti
 
mov eax, [RESERVED_PORTS]
add eax, 1
mov [RESERVED_PORTS], eax
shl eax, 4
add eax, RESERVED_PORTS
mov ebx, [TASK_BASE]
mov ebx, [ebx+TASKDATA.pid]
mov [eax], ebx
mov [eax+4], ecx
mov [eax+8], edx
 
xor eax, eax
ret
 
free_port_area:
 
; pushad
mov eax, [RESERVED_PORTS]; no reserved areas ?
test eax, eax
jz frpal2
mov ebx, [TASK_BASE]
mov ebx, [ebx+TASKDATA.pid]
frpal3:
mov edi, eax
shl edi, 4
add edi, RESERVED_PORTS
cmp ebx, [edi]
jne frpal4
cmp ecx, [edi+4]
jne frpal4
cmp edx, [edi+8]
jne frpal4
jmp frpal1
frpal4:
dec eax
jnz frpal3
frpal2:
; popad
inc eax
ret
frpal1:
push ecx
mov ecx, 256
sub ecx, eax
shl ecx, 4
mov esi, edi
add esi, 16
cld
rep movsb
 
dec dword [RESERVED_PORTS]
;popad
;disable port access at port IO map
 
; pushad ; start disable io map
pop eax ;start port
cmp edx, 65536;16384
jge no_mask_io
 
; mov eax,ecx
xor ebp, ebp
inc ebp
new_port_access_disable:
; pushad
; mov ebp,1 ; disable - eax = port
call set_io_access_rights
; popad
inc eax
cmp eax, edx
jbe new_port_access_disable
no_mask_io:
; popad ; end disable io map
xor eax, eax
ret
;-----------------------------------------------------------------------------
align 4
drawbackground:
dbrv20:
cmp [BgrDrawMode], dword 1
jne bgrstr
call vesa20_drawbackground_tiled
; call [draw_pointer]
call __sys_draw_pointer
ret
;--------------------------------------
align 4
bgrstr:
call vesa20_drawbackground_stretch
; call [draw_pointer]
call __sys_draw_pointer
ret
;-----------------------------------------------------------------------------
align 4
syscall_putimage: ; PutImage
; add check pointer
push ecx
mov ax, cx
shr ecx, 16
imul eax, ecx
lea eax, [eax*3]
stdcall is_region_userspace, ebx, eax
pop ecx
jnz sys_putimage.exit
 
sys_putimage:
test ecx, 0x80008000
jnz .exit
test ecx, 0x0000FFFF
jz .exit
test ecx, 0xFFFF0000
jnz @f
;--------------------------------------
align 4
.exit:
ret
;--------------------------------------
align 4
@@:
mov edi, [current_slot]
add dx, word[edi+APPDATA.wnd_clientbox.top]
rol edx, 16
add dx, word[edi+APPDATA.wnd_clientbox.left]
rol edx, 16
;--------------------------------------
align 4
.forced:
push ebp esi 0
mov ebp, putimage_get24bpp
mov esi, putimage_init24bpp
;--------------------------------------
align 4
sys_putimage_bpp:
call vesa20_putimage
pop ebp esi ebp
ret
; jmp [draw_pointer]
;-----------------------------------------------------------------------------
align 4
sys_putimage_palette:
; ebx = pointer to image
; ecx = [xsize]*65536 + [ysize]
; edx = [xstart]*65536 + [ystart]
; esi = number of bits per pixel, must be 8, 24 or 32
; edi = pointer to palette
; ebp = row delta
; check pointer
push ecx
mov ax, cx
shr ecx, 16
imul eax, ecx
stdcall is_region_userspace, ebx, eax
pop ecx
jnz sys_putimage.exit
 
mov eax, [current_slot_idx]
shl eax, 8
add dx, word [eax+SLOT_BASE+APPDATA.wnd_clientbox.top]
rol edx, 16
add dx, word [eax+SLOT_BASE+APPDATA.wnd_clientbox.left]
rol edx, 16
;--------------------------------------
align 4
.forced:
cmp esi, 1
jnz @f
push edi
mov eax, [edi+4]
sub eax, [edi]
push eax
push dword [edi]
push 0ffffff80h
mov edi, esp
call put_mono_image
add esp, 12
pop edi
ret
;--------------------------------------
align 4
@@:
cmp esi, 2
jnz @f
push edi
push 0ffffff80h
mov edi, esp
call put_2bit_image
pop eax
pop edi
ret
;--------------------------------------
align 4
@@:
cmp esi, 4
jnz @f
push edi
push 0ffffff80h
mov edi, esp
call put_4bit_image
pop eax
pop edi
ret
;--------------------------------------
align 4
@@:
push ebp esi ebp
cmp esi, 8
jnz @f
mov ebp, putimage_get8bpp
mov esi, putimage_init8bpp
jmp sys_putimage_bpp
;--------------------------------------
align 4
@@:
cmp esi, 9
jnz @f
mov ebp, putimage_get9bpp
mov esi, putimage_init9bpp
jmp sys_putimage_bpp
;--------------------------------------
align 4
@@:
cmp esi, 15
jnz @f
mov ebp, putimage_get15bpp
mov esi, putimage_init15bpp
jmp sys_putimage_bpp
;--------------------------------------
align 4
@@:
cmp esi, 16
jnz @f
mov ebp, putimage_get16bpp
mov esi, putimage_init16bpp
jmp sys_putimage_bpp
;--------------------------------------
align 4
@@:
cmp esi, 24
jnz @f
mov ebp, putimage_get24bpp
mov esi, putimage_init24bpp
jmp sys_putimage_bpp
;--------------------------------------
align 4
@@:
cmp esi, 32
jnz @f
mov ebp, putimage_get32bpp
mov esi, putimage_init32bpp
jmp sys_putimage_bpp
;--------------------------------------
align 4
@@:
pop ebp esi ebp
ret
;-----------------------------------------------------------------------------
align 4
put_mono_image:
push ebp esi ebp
mov ebp, putimage_get1bpp
mov esi, putimage_init1bpp
jmp sys_putimage_bpp
;-----------------------------------------------------------------------------
align 4
put_2bit_image:
push ebp esi ebp
mov ebp, putimage_get2bpp
mov esi, putimage_init2bpp
jmp sys_putimage_bpp
;-----------------------------------------------------------------------------
align 4
put_4bit_image:
push ebp esi ebp
mov ebp, putimage_get4bpp
mov esi, putimage_init4bpp
jmp sys_putimage_bpp
;-----------------------------------------------------------------------------
align 4
putimage_init24bpp:
lea eax, [eax*3]
putimage_init8bpp:
putimage_init9bpp:
ret
;-----------------------------------------------------------------------------
align 16
putimage_get24bpp:
movzx eax, byte [esi+2]
shl eax, 16
mov ax, [esi]
add esi, 3
ret 4
;-----------------------------------------------------------------------------
align 16
putimage_get8bpp:
movzx eax, byte [esi]
push edx
mov edx, [esp+8]
mov eax, [edx+eax*4]
pop edx
inc esi
ret 4
;-----------------------------------------------------------------------------
align 16
putimage_get9bpp:
lodsb
mov ah, al
shl eax, 8
mov al, ah
ret 4
;-----------------------------------------------------------------------------
align 4
putimage_init1bpp:
add eax, ecx
push ecx
add eax, 7
add ecx, 7
shr eax, 3
shr ecx, 3
sub eax, ecx
pop ecx
ret
;-----------------------------------------------------------------------------
align 16
putimage_get1bpp:
push edx
mov edx, [esp+8]
mov al, [edx]
add al, al
jnz @f
lodsb
adc al, al
@@:
mov [edx], al
sbb eax, eax
and eax, [edx+8]
add eax, [edx+4]
pop edx
ret 4
;-----------------------------------------------------------------------------
align 4
putimage_init2bpp:
add eax, ecx
push ecx
add ecx, 3
add eax, 3
shr ecx, 2
shr eax, 2
sub eax, ecx
pop ecx
ret
;-----------------------------------------------------------------------------
align 16
putimage_get2bpp:
push edx
mov edx, [esp+8]
mov al, [edx]
mov ah, al
shr al, 6
shl ah, 2
jnz .nonewbyte
lodsb
mov ah, al
shr al, 6
shl ah, 2
add ah, 1
.nonewbyte:
mov [edx], ah
mov edx, [edx+4]
movzx eax, al
mov eax, [edx+eax*4]
pop edx
ret 4
;-----------------------------------------------------------------------------
align 4
putimage_init4bpp:
add eax, ecx
push ecx
add ecx, 1
add eax, 1
shr ecx, 1
shr eax, 1
sub eax, ecx
pop ecx
ret
;-----------------------------------------------------------------------------
align 16
putimage_get4bpp:
push edx
mov edx, [esp+8]
add byte [edx], 80h
jc @f
movzx eax, byte [edx+1]
mov edx, [edx+4]
and eax, 0x0F
mov eax, [edx+eax*4]
pop edx
ret 4
@@:
movzx eax, byte [esi]
add esi, 1
mov [edx+1], al
shr eax, 4
mov edx, [edx+4]
mov eax, [edx+eax*4]
pop edx
ret 4
;-----------------------------------------------------------------------------
align 4
putimage_init32bpp:
shl eax, 2
ret
;-----------------------------------------------------------------------------
align 16
putimage_get32bpp:
lodsd
ret 4
;-----------------------------------------------------------------------------
align 4
putimage_init15bpp:
putimage_init16bpp:
add eax, eax
ret
;-----------------------------------------------------------------------------
align 16
putimage_get15bpp:
; 0RRRRRGGGGGBBBBB -> 00000000RRRRR000GGGGG000BBBBB000
push ecx edx
movzx eax, word [esi]
add esi, 2
mov ecx, eax
mov edx, eax
and eax, 0x1F
and ecx, 0x1F shl 5
and edx, 0x1F shl 10
shl eax, 3
shl ecx, 6
shl edx, 9
or eax, ecx
or eax, edx
pop edx ecx
ret 4
;-----------------------------------------------------------------------------
align 16
putimage_get16bpp:
; RRRRRGGGGGGBBBBB -> 00000000RRRRR000GGGGGG00BBBBB000
push ecx edx
movzx eax, word [esi]
add esi, 2
mov ecx, eax
mov edx, eax
and eax, 0x1F
and ecx, 0x3F shl 5
and edx, 0x1F shl 11
shl eax, 3
shl ecx, 5
shl edx, 8
or eax, ecx
or eax, edx
pop edx ecx
ret 4
;-----------------------------------------------------------------------------
;align 4
; eax x beginning
; ebx y beginning
; ecx x end
; edx y end
; edi color
;__sys_drawbar:
; mov esi, [current_slot]
; add eax, [esi+APPDATA.wnd_clientbox.left]
; add ecx, [esi+APPDATA.wnd_clientbox.left]
; add ebx, [esi+APPDATA.wnd_clientbox.top]
; add edx, [esi+APPDATA.wnd_clientbox.top]
;--------------------------------------
;align 4
;.forced:
; call vesa20_drawbar
; call [draw_pointer]
; ret
;-----------------------------------------------------------------------------
align 4
kb_write_wait_ack:
 
push ecx edx
 
mov dl, al
mov ecx, 0x1ffff; last 0xffff, new value in view of fast CPU's
.wait_output_ready:
in al, 0x64
test al, 2
jz @f
loop .wait_output_ready
mov ah, 1
jmp .nothing
@@:
mov al, dl
out 0x60, al
mov ecx, 0xfffff; last 0xffff, new value in view of fast CPU's
.wait_ack:
in al, 0x64
test al, 1
jnz @f
loop .wait_ack
mov ah, 1
jmp .nothing
@@:
in al, 0x60
xor ah, ah
 
.nothing:
pop edx ecx
 
ret
;-----------------------------------------------------------------------------
 
setmouse: ; set mousepicture -pointer
; ps2 mouse enable
 
; mov [MOUSE_PICTURE], dword mousepointer
 
cli
 
ret
 
if used _rdtsc
_rdtsc:
bt [cpu_caps], CAPS_TSC
jnc ret_rdtsc
rdtsc
ret
ret_rdtsc:
mov edx, 0xffffffff
mov eax, 0xffffffff
ret
end if
 
sys_msg_board_str:
 
pushad
@@:
cmp [esi], byte 0
je @f
mov ebx, 1
movzx ecx, byte [esi]
call sys_msg_board
inc esi
jmp @b
@@:
popad
ret
 
sys_msg_board_byte:
; in: al = byte to display
; out: nothing
; destroys: nothing
pushad
mov ecx, 2
shl eax, 24
jmp @f
 
sys_msg_board_word:
; in: ax = word to display
; out: nothing
; destroys: nothing
pushad
mov ecx, 4
shl eax, 16
jmp @f
 
sys_msg_board_dword:
; in: eax = dword to display
; out: nothing
; destroys: nothing
pushad
mov ecx, 8
@@:
push ecx
rol eax, 4
push eax
and al, 0xF
cmp al, 10
sbb al, 69h
das
mov cl, al
xor ebx, ebx
inc ebx
call sys_msg_board
pop eax
pop ecx
loop @b
popad
ret
 
msg_board_data_size = 65536 ; Must be power of two
 
uglobal
msg_board_data rb msg_board_data_size
msg_board_count dd ?
endg
 
iglobal
msg_board_pos dd 42*6*65536+10 ; for printing debug output on the screen
endg
 
sys_msg_board:
; ebx=1 -> write, cl = byte to write
; ebx=2 -> read, ecx=0 -> no data, ecx=1 -> data in al
push eax ebx
mov eax, ebx
mov ebx, ecx
mov ecx, [msg_board_count]
cmp eax, 1
jne .read
 
if defined debug_com_base
push dx ax
@@: ; wait for empty transmit register
mov dx, debug_com_base+5
in al, dx
test al, 1 shl 5
jz @r
mov dx, debug_com_base ; Output the byte
mov al, bl
out dx, al
pop ax dx
end if
 
mov [msg_board_data+ecx], bl
cmp byte [debug_direct_print], 1
jnz .end
pusha
lea edx, [msg_board_data+ecx]
mov ecx, 0x40FFFFFF
mov ebx, [msg_board_pos]
mov edi, 1
mov esi, 1
call dtext
popa
add word [msg_board_pos+2], 6
cmp word [msg_board_pos+2], 105*6
jnc @f
cmp bl, 10
jnz .end
@@:
mov word [msg_board_pos+2], 42*6
add word [msg_board_pos], 10
mov eax, [_display.height]
sub eax, 10
cmp ax, word [msg_board_pos]
jnc @f
mov word [msg_board_pos], 10
@@:
pusha
mov eax, [msg_board_pos]
movzx ebx, ax
shr eax, 16
mov edx, 105*6
xor ecx, ecx
mov edi, 1
mov esi, 9
@@:
call hline
inc ebx
dec esi
jnz @b
popa
.end:
inc ecx
and ecx, msg_board_data_size - 1
mov [msg_board_count], ecx
.ret:
pop ebx eax
ret
 
@@:
mov [esp+32], ecx
mov [esp+20], ecx
jmp .ret
 
.read:
cmp eax, 2
jne .ret
test ecx, ecx
jz @b
add esp, 8 ; returning data in ebx and eax, so no need to restore them
mov eax, msg_board_data+1
mov ebx, msg_board_data
movzx edx, byte [ebx]
call memmove
dec [msg_board_count]
mov [esp + 32], edx ;eax
mov [esp + 20], dword 1
ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 66 sys function. ;;
;; in eax=66,ebx in [0..5],ecx,edx ;;
;; out eax ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
iglobal
align 4
f66call:
dd sys_process_def.1 ; 1 = set keyboard mode
dd sys_process_def.2 ; 2 = get keyboard mode
dd sys_process_def.3 ; 3 = get keyboard ctrl, alt, shift
dd sys_process_def.4 ; 4 = set system-wide hotkey
dd sys_process_def.5 ; 5 = delete installed hotkey
dd sys_process_def.6 ; 6 = disable input, work only hotkeys
dd sys_process_def.7 ; 7 = enable input, opposition to f.66.6
endg
;-----------------------------------------------------------------------------
align 4
sys_process_def:
dec ebx
cmp ebx, 7
jae .not_support ;if >=8 then or eax,-1
 
mov edi, [current_slot_idx]
jmp dword [f66call+ebx*4]
 
.not_support:
or eax, -1
ret
;-----------------------------------------------------------------------------
align 4
.1:
shl edi, 8
mov [edi+SLOT_BASE + APPDATA.keyboard_mode], cl
 
ret
;-----------------------------------------------------------------------------
align 4
.2: ; 2 = get keyboard mode
shl edi, 8
movzx eax, byte [SLOT_BASE+edi + APPDATA.keyboard_mode]
mov [esp+32], eax
ret
;-----------------------------------------------------------------------------
align 4
.3: ;3 = get keyboard ctrl, alt, shift
mov eax, [kb_state]
mov [esp+32], eax
ret
;-----------------------------------------------------------------------------
align 4
.4:
mov eax, hotkey_list
@@:
cmp dword [eax+8], 0
jz .found_free
add eax, 16
cmp eax, hotkey_list+16*256
jb @b
mov dword [esp+32], 1
ret
.found_free:
mov [eax+8], edi
mov [eax+4], edx
movzx ecx, cl
lea ecx, [hotkey_scancodes+ecx*4]
mov edx, [ecx]
mov [eax], edx
mov [ecx], eax
mov [eax+12], ecx
test edx, edx
jz @f
mov [edx+12], eax
@@:
and dword [esp+32], 0
ret
;-----------------------------------------------------------------------------
align 4
.5:
movzx ebx, cl
lea ebx, [hotkey_scancodes+ebx*4]
mov eax, [ebx]
.scan:
test eax, eax
jz .notfound
cmp [eax+8], edi
jnz .next
cmp [eax+4], edx
jz .found
.next:
mov eax, [eax]
jmp .scan
.notfound:
mov dword [esp+32], 1
ret
.found:
mov ecx, [eax]
jecxz @f
mov edx, [eax+12]
mov [ecx+12], edx
@@:
mov ecx, [eax+12]
mov edx, [eax]
mov [ecx], edx
xor edx, edx
mov [eax+4], edx
mov [eax+8], edx
mov [eax+12], edx
mov [eax], edx
mov [esp+32], edx
ret
;-----------------------------------------------------------------------------
align 4
.6:
pushfd
cli
mov eax, [PID_lock_input]
test eax, eax
jnz @f
; get current PID
mov eax, [current_slot_idx]
shl eax, 5
mov eax, [eax+TASK_TABLE+TASKDATA.pid]
; set current PID for lock input
mov [PID_lock_input], eax
@@:
popfd
ret
;-----------------------------------------------------------------------------
align 4
.7:
mov eax, [PID_lock_input]
test eax, eax
jz @f
; get current PID
mov ebx, [current_slot_idx]
shl ebx, 5
mov ebx, [ebx+TASK_TABLE+TASKDATA.pid]
; compare current lock input with current PID
cmp ebx, eax
jne @f
 
xor eax, eax
mov [PID_lock_input], eax
@@:
ret
;-----------------------------------------------------------------------------
uglobal
PID_lock_input dd 0x0
endg
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 61 sys function. ;;
;; in eax=61,ebx in [1..3] ;;
;; out eax ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
iglobal
align 4
f61call:
dd sys_gs.1 ; resolution
dd sys_gs.2 ; bits per pixel
dd sys_gs.3 ; bytes per scanline
endg
 
 
align 4
 
sys_gs: ; direct screen access
dec ebx
cmp ebx, 2
ja .not_support
jmp dword [f61call+ebx*4]
.not_support:
or [esp+32], dword -1
ret
 
 
.1: ; resolution
mov eax, [_display.width]
shl eax, 16
mov ax, word [_display.height]
mov [esp+32], eax
ret
.2: ; bits per pixel
mov eax, [_display.bits_per_pixel]
mov [esp+32], eax
ret
.3: ; bytes per scanline
mov eax, [_display.lfb_pitch]
mov [esp+32], eax
ret
 
align 4 ; system functions
 
syscall_setpixel: ; SetPixel
 
mov eax, ebx
mov ebx, ecx
mov ecx, edx
mov edx, [TASK_BASE]
add eax, [edx-twdw+WDATA.box.left]
add ebx, [edx-twdw+WDATA.box.top]
mov edi, [current_slot]
add eax, [edi+APPDATA.wnd_clientbox.left]
add ebx, [edi+APPDATA.wnd_clientbox.top]
xor edi, edi ; no force
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area
; jmp [putpixel]
jmp __sys_putpixel
 
align 4
 
syscall_writetext: ; WriteText
 
stdcall is_region_userspace, edx, esi
jnz .err
 
mov eax, [TASK_BASE]
mov ebp, [eax-twdw+WDATA.box.left]
push esi
mov esi, [current_slot]
add ebp, [esi+APPDATA.wnd_clientbox.left]
shl ebp, 16
add ebp, [eax-twdw+WDATA.box.top]
add bp, word[esi+APPDATA.wnd_clientbox.top]
pop esi
test ecx, 0x08000000 ; redirect the output to the user area
jnz @f
add ebx, ebp
align 4
@@:
mov eax, edi
test ecx, 0x08000000 ; redirect the output to the user area
jnz @f
xor edi, edi
jmp dtext
 
@@: ; check pointer
stdcall is_region_userspace, edi, 0
jnz .err
jmp dtext
.err:
ret
 
align 4
 
syscall_drawrect: ; DrawRect
 
mov edi, edx ; color + gradient
and edi, 0x80FFFFFF
test bx, bx ; x.size
je .drectr
test cx, cx ; y.size
je .drectr
 
mov eax, ebx ; bad idea
mov ebx, ecx
 
movzx ecx, ax ; ecx - x.size
shr eax, 16 ; eax - x.coord
movzx edx, bx ; edx - y.size
shr ebx, 16 ; ebx - y.coord
mov esi, [current_slot]
 
add eax, [esi + APPDATA.wnd_clientbox.left]
add ebx, [esi + APPDATA.wnd_clientbox.top]
add ecx, eax
add edx, ebx
; jmp [drawbar]
jmp vesa20_drawbar
.drectr:
ret
 
align 4
syscall_getscreensize: ; GetScreenSize
mov ax, word [_display.width]
dec ax
shl eax, 16
mov ax, word [_display.height]
dec ax
mov [esp + 32], eax
ret
;-----------------------------------------------------------------------------
align 4
syscall_cdaudio:
; ECX - position of CD/DVD-drive
; from 0=Primary Master to 3=Secondary Slave for first IDE contr.
; from 4=Primary Master to 7=Secondary Slave for second IDE contr.
; from 8=Primary Master to 11=Secondary Slave for third IDE contr.
cmp ecx, 11
ja .exit
 
mov eax, ecx
shr eax, 2
lea eax, [eax*5]
mov al, [eax+DRIVE_DATA+1]
 
push ecx ebx
mov ebx, ecx
and ebx, 11b
shl ebx, 1
mov cl, 6
sub cl, bl
shr al, cl
test al, 2 ; it's not an ATAPI device
pop ebx ecx
 
jz .exit
 
cmp ebx, 4
je .eject
 
cmp ebx, 5
je .load
;--------------------------------------
.exit:
ret
;--------------------------------------
.load:
call .reserve
call LoadMedium
jmp .free
;--------------------------------------
.eject:
call .reserve
call clear_CD_cache
call allow_medium_removal
call EjectMedium
jmp .free
;--------------------------------------
.reserve:
call reserve_cd
 
mov ebx, ecx
inc ebx
mov [cdpos], ebx
 
mov eax, ecx
shr eax, 1
and eax, 1
inc eax
mov [ChannelNumber], al
mov eax, ecx
and eax, 1
mov [DiskNumber], al
call reserve_cd_channel
ret
;--------------------------------------
.free:
call free_cd_channel
and [cd_status], 0
ret
;-----------------------------------------------------------------------------
align 4
syscall_getpixel_WinMap: ; GetPixel WinMap
cmp ebx, [_display.width]
jb @f
cmp ecx, [_display.height]
jb @f
xor eax, eax
jmp .store
;--------------------------------------
align 4
@@:
mov eax, [d_width_calc_area + ecx*4]
add eax, [_display.win_map]
movzx eax, byte[eax+ebx] ; get value for current point
;--------------------------------------
align 4
.store:
mov [esp + 32], eax
ret
;-----------------------------------------------------------------------------
align 4
syscall_getpixel: ; GetPixel
mov ecx, [_display.width]
xor edx, edx
mov eax, ebx
div ecx
mov ebx, edx
xchg eax, ebx
and ecx, 0xFBFFFFFF ;negate 0x04000000 use mouseunder area
call dword [GETPIXEL]; eax - x, ebx - y
mov [esp + 32], ecx
ret
;-----------------------------------------------------------------------------
align 4
syscall_getarea:
;eax = 36
;ebx = pointer to bufer for img BBGGRRBBGGRR...
;ecx = [size x]*65536 + [size y]
;edx = [start x]*65536 + [start y]
pushad
mov edi, ebx
mov eax, edx
shr eax, 16
mov ebx, edx
and ebx, 0xffff
dec eax
dec ebx
; eax - x, ebx - y
mov edx, ecx
 
shr ecx, 16
and edx, 0xffff
mov esi, ecx
; ecx - size x, edx - size y
 
mov ebp, edx
lea ebp, [ebp*3]
imul ebp, esi
stdcall is_region_userspace, edi, ebp
jnz .exit
 
mov ebp, edx
dec ebp
lea ebp, [ebp*3]
 
imul ebp, esi
 
mov esi, ecx
dec esi
lea esi, [esi*3]
 
add ebp, esi
add ebp, edi
 
add ebx, edx
;--------------------------------------
align 4
.start_y:
push ecx edx
;--------------------------------------
align 4
.start_x:
push eax ebx ecx
add eax, ecx
 
and ecx, 0xFBFFFFFF ;negate 0x04000000 use mouseunder area
call dword [GETPIXEL]; eax - x, ebx - y
 
mov [ebp], cx
shr ecx, 16
mov [ebp+2], cl
 
pop ecx ebx eax
sub ebp, 3
dec ecx
jnz .start_x
pop edx ecx
dec ebx
dec edx
jnz .start_y
.exit:
popad
ret
;-----------------------------------------------------------------------------
align 4
syscall_putarea_backgr:
;eax = 25
;ebx = pointer to bufer for img BBGGRRBBGGRR...
;ecx = [size x]*65536 + [size y]
;edx = [start x]*65536 + [start y]
pushad
mov edi, ebx
mov eax, edx
shr eax, 16
mov ebx, edx
and ebx, 0xffff
dec eax
dec ebx
; eax - x, ebx - y
mov edx, ecx
shr ecx, 16
and edx, 0xffff
mov esi, ecx
; ecx - size x, edx - size y
mov ebp, edx
lea ebp, [ebp*4]
imul ebp, esi
stdcall is_region_userspace, edi, ebp
jnz .exit
mov ebp, edx
 
dec ebp
shl ebp, 2
 
imul ebp, esi
 
mov esi, ecx
dec esi
shl esi, 2
 
add ebp, esi
add ebp, edi
 
add ebx, edx
;--------------------------------------
align 4
.start_y:
push ecx edx
;--------------------------------------
align 4
.start_x:
push eax ecx
add eax, ecx
 
mov ecx, [ebp]
rol ecx, 8
test cl, cl ; transparensy = 0
jz .no_put
 
xor cl, cl
ror ecx, 8
 
pushad
mov edx, [d_width_calc_area + ebx*4]
add edx, [_display.win_map]
movzx edx, byte [eax+edx]
cmp dl, byte 1
jne @f
 
call dword [PUTPIXEL]; eax - x, ebx - y
;--------------------------------------
align 4
@@:
popad
;--------------------------------------
align 4
.no_put:
pop ecx eax
 
sub ebp, 4
dec ecx
jnz .start_x
 
pop edx ecx
dec ebx
dec edx
jnz .start_y
 
.exit:
popad
ret
;-----------------------------------------------------------------------------
align 4
syscall_drawline: ; DrawLine
 
mov edi, [TASK_BASE]
movzx eax, word[edi-twdw+WDATA.box.left]
mov ebp, eax
mov esi, [current_slot]
add ebp, [esi+APPDATA.wnd_clientbox.left]
add ax, word[esi+APPDATA.wnd_clientbox.left]
add ebp, ebx
shl eax, 16
movzx ebx, word[edi-twdw+WDATA.box.top]
add eax, ebp
mov ebp, ebx
add ebp, [esi+APPDATA.wnd_clientbox.top]
add bx, word[esi+APPDATA.wnd_clientbox.top]
add ebp, ecx
shl ebx, 16
xor edi, edi
add ebx, ebp
mov ecx, edx
; jmp [draw_line]
jmp __sys_draw_line
 
 
align 4
syscall_reserveportarea: ; ReservePortArea and FreePortArea
 
call r_f_port_area
mov [esp+32], eax
ret
 
align 4
syscall_threads: ; CreateThreads
;
; ecx=thread entry point
; edx=thread stack pointer
;
; on return : eax = pid
 
xor ebx, ebx
call new_sys_threads
 
mov [esp+32], eax
ret
 
align 4
 
paleholder:
ret
;------------------------------------------------------------------------------
align 4
calculate_fast_getting_offset_for_WinMapAddress:
; calculate data area for fast getting offset to _WinMapAddress
xor eax, eax
mov ecx, [_display.height]
mov edi, d_width_calc_area
cld
@@:
stosd
add eax, [_display.width]
dec ecx
jnz @r
ret
;------------------------------------------------------------------------------
align 4
calculate_fast_getting_offset_for_LFB:
; calculate data area for fast getting offset to LFB
xor eax, eax
mov ecx, [_display.height]
mov edi, BPSLine_calc_area
cld
@@:
stosd
add eax, [_display.lfb_pitch]
dec ecx
jnz @r
ret
;------------------------------------------------------------------------------
align 4
set_screen:
; in:
; eax - new Screen_Max_X
; ecx - new BytesPerScanLine
; edx - new Screen_Max_Y
 
pushfd
cli
 
mov [_display.lfb_pitch], ecx
 
mov [screen_workarea.right], eax
mov [screen_workarea.bottom], edx
 
push ebx
push esi
push edi
 
pushad
 
cmp [do_not_touch_winmap], 1
je @f
 
stdcall kernel_free, [_display.win_map]
 
mov eax, [_display.width]
mul [_display.height]
mov [_display.win_map_size], eax
 
stdcall kernel_alloc, eax
mov [_display.win_map], eax
test eax, eax
jz .epic_fail
; store for f.18.24
mov eax, [_display.width]
mov [display_width_standard], eax
 
mov eax, [_display.height]
mov [display_height_standard], eax
@@:
call calculate_fast_getting_offset_for_WinMapAddress
; for Qemu or non standart video cards
; Unfortunately [BytesPerScanLine] does not always
; equal to [_display.width] * [ScreenBPP] / 8
call calculate_fast_getting_offset_for_LFB
popad
 
call repos_windows
xor eax, eax
xor ebx, ebx
mov ecx, [_display.width]
mov edx, [_display.height]
dec ecx
dec edx
call calculatescreen
pop edi
pop esi
pop ebx
 
popfd
ret
 
.epic_fail:
hlt ; Houston, we've had a problem
 
; --------------- APM ---------------------
uglobal
apm_entry dp 0
apm_vf dd 0
endg
 
align 4
sys_apm:
xor eax, eax
cmp word [apm_vf], ax ; Check APM BIOS enable
jne @f
inc eax
or dword [esp + 44], eax ; error
add eax, 7
mov dword [esp + 32], eax ; 32-bit protected-mode interface not supported
ret
 
@@:
; xchg eax, ecx
; xchg ebx, ecx
 
cmp dx, 3
ja @f
and [esp + 44], byte 0xfe ; emulate func 0..3 as func 0
mov eax, [apm_vf]
mov [esp + 32], eax
shr eax, 16
mov [esp + 28], eax
ret
 
@@:
 
mov esi, [master_tab+(OS_BASE shr 20)]
xchg [master_tab], esi
push esi
mov edi, cr3
mov cr3, edi ;flush TLB
 
call pword [apm_entry] ;call APM BIOS
 
xchg eax, [esp]
mov [master_tab], eax
mov eax, cr3
mov cr3, eax
pop eax
 
mov [esp + 4 ], edi
mov [esp + 8], esi
mov [esp + 20], ebx
mov [esp + 24], edx
mov [esp + 28], ecx
mov [esp + 32], eax
setc al
and [esp + 44], byte 0xfe
or [esp + 44], al
ret
; -----------------------------------------
 
align 4
undefined_syscall: ; Undefined system call
mov [esp + 32], dword -1
ret
 
align 4
; @brief Check if given memory region lays in lower 2gb (userspace memory) or not
; @param base Base address of region
; @param len Lenght of region
; @return ZF = 1 if region in userspace memory,
; ZF = 0 otherwise
proc is_region_userspace stdcall, base:dword, len:dword
push eax
mov eax, [base]
 
cmp eax, OS_BASE-1
ja @f ; zf
 
add eax, [len]
jc @f ; zf
cmp eax, OS_BASE
ja @f ; zf
 
cmp eax, eax ; ZF
@@:
pop eax
ret
endp
 
if ~ lang eq sp
diff16 "end of .text segment",0,$
end if
 
include "data32.inc"
 
__REV__ = __REV
 
if ~ lang eq sp
diff16 "end of kernel code",0,$
end if
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/stack.inc
0,0 → 1,984
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; STACK.INC ;;
;; ;;
;; TCP/IP stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; Some parts of code are based on the work of: ;;
;; Mike Hibbett (menuetos network stack) ;;
;; Eugen Brasoveanu (solar os network stack and drivers) ;;
;; mike.dld (kolibrios socket code) ;;
;; ;;
;; TCP part is based on 4.4BSD ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
uglobal
net_10ms dd ?
net_tmr_count dw ?
endg
 
DEBUG_NETWORK_ERROR = 1
DEBUG_NETWORK_VERBOSE = 0
NETWORK_SANITY_CHECKS = 1
 
NET_DEVICES_MAX = 16
NET_BUFFERS = 512
NET_BUFFER_SIZE = 2048
ARP_BLOCK = 1 ; true or false
 
EPHEMERAL_PORT_MIN = 49152
EPHEMERAL_PORT_MAX = 61000
MIN_EPHEMERAL_PORT_N = 0x00C0 ; same in Network byte order (FIXME)
MAX_EPHEMERAL_PORT_N = 0x48EE ; same in Network byte order (FIXME)
 
; Ethernet protocol numbers
ETHER_PROTO_ARP = 0x0608
ETHER_PROTO_IPv4 = 0x0008
ETHER_PROTO_IPv6 = 0xDD86
ETHER_PROTO_PPP_DISCOVERY = 0x6388
ETHER_PROTO_PPP_SESSION = 0x6488
 
; Internet protocol numbers
IP_PROTO_IP = 0
IP_PROTO_ICMP = 1
IP_PROTO_TCP = 6
IP_PROTO_UDP = 17
IP_PROTO_RAW = 255
 
; IP options
IP_TOS = 1
IP_TTL = 2
IP_HDRINCL = 3
 
; PPP protocol numbers
PPP_PROTO_IPv4 = 0x2100
PPP_PROTO_IPV6 = 0x5780
PPP_PROTO_ETHERNET = 666 ; FIXME
 
;Protocol family
AF_UNSPEC = 0
AF_LOCAL = 1
AF_INET4 = 2
AF_INET6 = 10
AF_PPP = 777 ; FIXME
 
; Socket types
SOCK_STREAM = 1
SOCK_DGRAM = 2
SOCK_RAW = 3
 
; Socket level
SOL_SOCKET = 0xffff
 
; Socket options
SO_ACCEPTCON = 1 shl 0
SO_BROADCAST = 1 shl 1
SO_DEBUG = 1 shl 2
SO_DONTROUTE = 1 shl 3
SO_KEEPALIVE = 1 shl 4
SO_OOBINLINE = 1 shl 5
SO_REUSEADDR = 1 shl 6
SO_REUSEPORT = 1 shl 7
SO_USELOOPBACK = 1 shl 8
SO_BINDTODEVICE = 1 shl 9
SO_LINGER = 1 shl 10
 
SO_NONBLOCK = 1 shl 31
 
; Socket flags for user calls
MSG_PEEK = 0x02
MSG_DONTWAIT = 0x40
 
; Socket States
SS_NOFDREF = 0x0001 ; no file table ref any more
SS_ISCONNECTED = 0x0002 ; socket connected to a peer
SS_ISCONNECTING = 0x0004 ; in process of connecting to peer
SS_ISDISCONNECTING = 0x0008 ; in process of disconnecting
SS_CANTSENDMORE = 0x0010 ; can't send more data to peer
SS_CANTRCVMORE = 0x0020 ; can't receive more data from peer
SS_RCVATMARK = 0x0040 ; at mark on input
SS_ISABORTING = 0x0080 ; aborting fd references - close()
SS_RESTARTSYS = 0x0100 ; restart blocked system calls
SS_ISDISCONNECTED = 0x0800 ; socket disconnected from peer
 
SS_ASYNC = 0x1000 ; async i/o notify
SS_ISCONFIRMING = 0x2000 ; deciding to accept connection req
SS_MORETOCOME = 0x4000
 
SS_BLOCKED = 0x8000
 
 
SOCKET_BUFFER_SIZE = 4096*8 ; must be 4096*(power of 2) where 'power of 2' is at least 8
MAX_backlog = 20 ; maximum backlog for stream sockets
 
; Error Codes
ENOBUFS = 1
EINPROGRESS = 2
EOPNOTSUPP = 4
EWOULDBLOCK = 6
ENOTCONN = 9
EALREADY = 10
EINVAL = 11
EMSGSIZE = 12
ENOMEM = 18
EADDRINUSE = 20
EADDRNOTAVAIL = 21
ECONNRESET = 52
ECONNABORTED = 53
EISCONN = 56
ETIMEDOUT = 60
ECONNREFUSED = 61
 
; Api protocol numbers
API_ETH = 0
API_IPv4 = 1
API_ICMP = 2
API_UDP = 3
API_TCP = 4
API_ARP = 5
API_PPPOE = 6
API_IPv6 = 7
 
; Network device types
NET_DEVICE_LOOPBACK = 0
NET_DEVICE_ETH = 1
NET_DEVICE_SLIP = 2
 
; Network link types (link protocols)
NET_LINK_LOOPBACK = 0
NET_LINK_MAC = 1 ; Media access control (ethernet, isdn, ...)
NET_LINK_PPP = 2 ; Point to Point Protocol (PPPoE, ...)
NET_LINK_IEEE802.11 = 3 ; IEEE 802.11 (WiFi)
 
; Hardware acceleration bits
NET_HWACC_TCP_IPv4_IN = 1 shl 0
NET_HWACC_TCP_IPv4_OUT = 1 shl 1
 
; Network frame types
NET_BUFF_LOOPBACK = 0
NET_BUFF_ETH = 1
 
struct NET_DEVICE
 
device_type dd ? ; Type field
mtu dd ? ; Maximal Transmission Unit
name dd ? ; Ptr to 0 terminated string
 
unload dd ? ; Ptrs to driver functions
reset dd ? ;
transmit dd ? ;
 
link_state dd ? ; link state (0 = no link)
hwacc dd ? ; bitmask stating enabled HW accelerations (offload engines)
 
bytes_tx dq ? ; Statistics, updated by the driver
bytes_rx dq ? ;
 
packets_tx dd ? ;
packets_tx_err dd ? ; CRC errors, too long or too short frames
packets_tx_drop dd ? ;
packets_tx_ovr dd ? ; FIFO overrun
 
packets_rx dd ? ;
packets_rx_err dd ? ; CRC errors, too long or too short frames
packets_rx_drop dd ? ;
packets_rx_ovr dd ? ; FIFO overrun
 
ends
 
struct NET_BUFF
 
NextPtr dd ? ; pointer to next frame in list
PrevPtr dd ? ; pointer to previous frame in list
device dd ? ; ptr to NET_DEVICE structure
type dd ? ; encapsulation type: e.g. Ethernet
length dd ? ; size of encapsulated data
offset dd ? ; offset to actual data (24 bytes for default frame)
data rb 0
 
ends
 
 
; Exactly as it says..
macro pseudo_random reg {
add reg, [esp]
rol reg, 5
xor reg, [timer_ticks]
; add reg, [CPU_FREQ]
imul reg, 214013
xor reg, 0xdeadbeef
rol reg, 9
}
 
; Network to Hardware byte order (dword)
macro ntohd reg {
 
rol word reg, 8
rol dword reg, 16
rol word reg , 8
 
}
 
; Network to Hardware byte order (word)
macro ntohw reg {
 
rol word reg, 8
 
}
 
 
include "queue.inc"
 
include "loopback.inc"
include "ethernet.inc"
 
include "PPPoE.inc"
 
include "ARP.inc"
include "IPv4.inc"
include "IPv6.inc"
 
include "icmp.inc"
include "udp.inc"
include "tcp.inc"
 
include "socket.inc"
 
 
 
uglobal
align 4
 
net_device_count dd ?
net_device_list rd NET_DEVICES_MAX
 
net_buffs_free rd NET_BUFFERS ; list of pointers to actual net buffs
.current dd ? ; pointer to current element in net_buffs_free list
 
if defined NETWORK_SANITY_CHECKS
net_buffs_low dd ? ; actual net buff mem region start
net_buffs_high dd ? ; actual net buff mem region stop
end if
 
endg
 
 
;-----------------------------------------------------------------;
; ;
; stack_init: Initialize all network variables ;
; ;
; IN: / ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
stack_init:
 
; allocate network buffers
stdcall kernel_alloc, NET_BUFFER_SIZE*NET_BUFFERS
test eax, eax
jz .fail
 
if defined NETWORK_SANITY_CHECKS
mov [net_buffs_low], eax
end if
 
mov edi, net_buffs_free
mov ecx, NET_BUFFERS
cld
.loop:
stosd
add eax, NET_BUFFER_SIZE
dec ecx
jnz .loop
 
if defined NETWORK_SANITY_CHECKS
sub eax, NET_BUFFER_SIZE
mov [net_buffs_high], eax
end if
 
mov eax, net_buffs_free
stosd
 
; Init the network drivers list
xor eax, eax
mov edi, net_device_count
mov ecx, (NET_DEVICES_MAX + 1)
rep stosd
 
eth_init
 
pppoe_init
 
ipv4_init
; ipv6_init
icmp_init
 
arp_init
udp_init
tcp_init
 
socket_init
 
loop_init
 
mov [net_tmr_count], 0
ret
 
.fail:
DEBUGF DEBUG_NETWORK_ERROR, "Stack init failed!\n"
ret
 
 
 
; Wakeup every tick.
proc stack_handler_has_work?
 
mov eax, [timer_ticks]
cmp eax, [net_10ms]
 
ret
endp
 
 
;-----------------------------------------------------------------;
; ;
; stack_handler: Network handlers called from os_loop. ;
; ;
; IN: / ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
stack_handler:
 
; Test for 10ms tick
mov eax, [timer_ticks]
cmp eax, [net_10ms]
je .exit
mov [net_10ms], eax
 
cmp [net_device_count], 0
je .exit
 
test [net_10ms], 0x0f ; 160ms
jnz .exit
 
tcp_timer_160ms
 
test [net_10ms], 0x3f ; 640ms
jnz .exit
 
arp_decrease_entry_ttls
ipv4_decrease_fragment_ttls
 
xor edx, edx
mov eax, [TCP_timer1_event]
mov ebx, [eax + EVENT.id]
xor esi, esi
call raise_event
 
.exit:
ret
 
 
align 4
proc net_buff_alloc stdcall, buffersize
 
cmp [buffersize], NET_BUFFER_SIZE
ja .too_large
 
spin_lock_irqsave
 
mov eax, [net_buffs_free.current]
cmp eax, net_buffs_free+NET_BUFFERS*4
jae .out_of_mem
mov eax, [eax]
add [net_buffs_free.current], 4
 
spin_unlock_irqrestore
 
if defined NETWORK_SANITY_CHECKS
cmp eax, [net_buffs_low]
cmp eax, [net_buffs_low]
jb .assert_mbuff
cmp eax, [net_buffs_high]
ja .assert_mbuff
test eax, 0x7ff
jnz .assert_mbuff
end if
 
DEBUGF DEBUG_NETWORK_VERBOSE, "net_buff_alloc: 0x%x\n", eax
ret
 
.out_of_mem:
spin_unlock_irqrestore
 
xor eax, eax
DEBUGF DEBUG_NETWORK_ERROR, "net_buff_alloc: out of mem!\n"
ret
 
.too_large:
xor eax, eax
DEBUGF DEBUG_NETWORK_ERROR, "net_buff_alloc: too large!\n"
ret
 
if defined NETWORK_SANITY_CHECKS
.assert_mbuff:
DEBUGF DEBUG_NETWORK_ERROR, "net_buff_alloc: invalid buffer 0x%x\n", eax
DEBUGF DEBUG_NETWORK_ERROR, "net_buff_alloc: caller=0x%x\n", [esp+4]
xor eax, eax
ret
end if
 
endp
 
 
align 4
proc net_buff_free stdcall, buffer
 
DEBUGF DEBUG_NETWORK_VERBOSE, "net_buff_free: 0x%x\n", [buffer]
 
if defined NETWORK_SANITY_CHECKS
mov eax, [buffer]
cmp eax, [net_buffs_low]
jb .assert_mbuff
cmp eax, [net_buffs_high]
ja .assert_mbuff
test eax, 0x7ff
jnz .assert_mbuff
end if
 
spin_lock_irqsave
 
sub [net_buffs_free.current], 4 ; move pointer backwards
mov eax, [net_buffs_free.current] ; place free'd buffer pointer on the list
push [buffer]
pop dword[eax]
 
spin_unlock_irqrestore
 
ret
 
if defined NETWORK_SANITY_CHECKS
.assert_mbuff:
DEBUGF DEBUG_NETWORK_ERROR, "net_buff_free: invalid buffer 0x%x\n", eax
DEBUGF DEBUG_NETWORK_ERROR, "net_buff_free: caller=0x%x\n", [esp+4]
xor eax, eax
ret
end if
 
endp
 
 
align 4
net_link_changed:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "net_link_changed device=0x%x status=0x%x\n", ebx, [ebx + NET_DEVICE.link_state]
 
align 4
net_send_event:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "net_send_event\n"
 
; Send event to all applications
push edi ecx
mov edi, SLOT_BASE
mov ecx, [thread_count]
.loop:
add edi, sizeof.APPDATA
or [edi + APPDATA.occurred_events], EVENT_NETWORK2
loop .loop
pop ecx edi
 
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; net_add_device: Called by network driver to register interface. ;
; ;
; IN: ebx = ptr to device structure ;
; ;
; OUT: eax = device num on success ;
; eax = -1 on error ;
; ;
;-----------------------------------------------------------------;
align 4
net_add_device:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "net_add_device: %x\n", ebx ;;; TODO: use mutex to lock net device list
 
cmp [net_device_count], NET_DEVICES_MAX
jae .error
 
;----------------------------------
; Check if device is already listed
mov eax, ebx
mov ecx, NET_DEVICES_MAX ; We need to check whole list because a device may be removed without re-organizing list
mov edi, net_device_list
 
repne scasd ; See if device is already in the list
jz .error
 
;----------------------------
; Find empty slot in the list
xor eax, eax
mov ecx, NET_DEVICES_MAX
mov edi, net_device_list
 
repne scasd
jnz .error
 
sub edi, 4
 
;-----------------------------
; Add device to the found slot
mov [edi], ebx ; add device to list
 
mov eax, edi ; Calculate device number in eax
sub eax, net_device_list
shr eax, 2
 
inc [net_device_count] ; Indicate that one more network device is up and running
 
call net_send_event
 
DEBUGF DEBUG_NETWORK_VERBOSE, "Device number: %u\n", eax
ret
 
.error:
or eax, -1
DEBUGF DEBUG_NETWORK_ERROR, "Adding network device failed\n"
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; net_remove_device: Called by network driver to unregister dev. ;
; ;
; IN: ebx = ptr to device ;
; ;
; OUT: eax: -1 on error ;
; ;
;-----------------------------------------------------------------;
align 4
net_remove_device:
 
cmp [net_device_count], 0
je .error
 
;----------------------------
; Find the driver in the list
 
mov eax, ebx
mov ecx, NET_DEVICES_MAX
mov edi, net_device_list
 
repne scasd
jnz .error
 
;------------------------
; Remove it from the list
 
xor eax, eax
mov dword [edi-4], eax
dec [net_device_count]
 
call net_send_event
 
xor eax, eax
ret
 
.error:
or eax, -1
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; net_ptr_to_num ;
; ;
; IN: ebx = ptr to device struct ;
; ;
; OUT: edi = device number ;
; edi = -1 on error ;
; ;
;-----------------------------------------------------------------;
align 4
net_ptr_to_num:
 
call net_ptr_to_num4
ror edi, 2 ; If -1, stay -1
; valid device numbers have last two bits 0, so do just shr
 
ret
 
align 4
net_ptr_to_num4: ; Todo, place number in device structure so we only need to verify?
 
test ebx, ebx
jz .fail
 
push ecx
mov ecx, NET_DEVICES_MAX
mov edi, net_device_list
.loop:
cmp ebx, [edi]
je .found
add edi, 4
dec ecx
jnz .loop
 
pop ecx
.fail:
or edi, -1
ret
 
.found:
sub edi, net_device_list
pop ecx
ret
 
;-----------------------------------------------------------------;
; ;
; checksum_1: Calculate semi-checksum for network packets. ;
; ;
; IN: edx = start offset for semi-checksum ;
; esi = pointer to data ;
; ecx = data size ;
; ;
; OUT: edx = semi-checksum ;
; ;
;-----------------------------------------------------------------;
align 4
checksum_1:
 
shr ecx, 1
pushf
jz .no_2
 
shr ecx, 1
pushf
jz .no_4
 
shr ecx, 1
pushf
jz .no_8
 
.loop:
add dl, [esi+1]
adc dh, [esi+0]
 
adc dl, [esi+3]
adc dh, [esi+2]
 
adc dl, [esi+5]
adc dh, [esi+4]
 
adc dl, [esi+7]
adc dh, [esi+6]
 
adc edx, 0
add esi, 8
 
dec ecx
jnz .loop
 
adc edx, 0
 
.no_8:
popf
jnc .no_4
 
add dl, [esi+1]
adc dh, [esi+0]
 
adc dl, [esi+3]
adc dh, [esi+2]
 
adc edx, 0
add esi, 4
 
.no_4:
popf
jnc .no_2
 
add dl, [esi+1]
adc dh, [esi+0]
 
adc edx, 0
inc esi
inc esi
 
.no_2:
popf
jnc .end
 
add dh, [esi+0]
adc edx, 0
.end:
ret
 
;-----------------------------------------------------------------;
; ;
; checksum_2: Calculate the final ip/tcp/udp checksum. ;
; ;
; IN: edx = semi-checksum ;
; ;
; OUT: dx = checksum (in INET byte order) ;
; ;
;-----------------------------------------------------------------;
align 4
checksum_2:
 
mov ecx, edx
shr ecx, 16
and edx, 0xffff
add edx, ecx
 
mov ecx, edx
shr ecx, 16
add dx, cx
test dx, dx ; it seems that ZF is not set when CF is set :(
not dx
jnz .not_zero
dec dx
.not_zero:
xchg dl, dh
 
DEBUGF DEBUG_NETWORK_VERBOSE, "Checksum: %x\n", dx
 
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; System function 74: Low level access to network devices. ;
; ;
;-----------------------------------------------------------------;
align 4
sys_network:
 
cmp bl, 255
jne @f
 
mov eax, [net_device_count]
mov [esp+32], eax
ret
 
@@:
cmp bh, NET_DEVICES_MAX ; Check if device number exists
jae .doesnt_exist
 
mov esi, ebx
and esi, 0x0000ff00
shr esi, 6
 
cmp dword[esi + net_device_list], 0 ; check if device is running
je .doesnt_exist
 
mov eax, [esi + net_device_list]
 
and ebx, 0x000000ff
cmp ebx, .number
ja .doesnt_exist
jmp dword [.table + 4*ebx]
 
.table:
dd .get_type ; 0
dd .get_dev_name ; 1
dd .reset ; 2
dd .stop ; 3
dd .get_ptr ; 4
dd .get_drv_name ; 5
 
dd .packets_tx ; 6
dd .packets_rx ; 7
dd .bytes_tx ; 8
dd .bytes_rx ; 9
dd .state ; 10
dd .packets_tx_err ; 11
dd .packets_tx_drop ; 12
dd .packets_tx_ovr ; 13
dd .packets_rx_err ; 14
dd .packets_rx_drop ; 15
dd .packets_rx_ovr ; 16
 
.number = ($ - .table) / 4 - 1
 
.get_type:
mov eax, [eax + NET_DEVICE.device_type]
mov [esp+32], eax
ret
 
.get_dev_name:
mov ebx, eax
stdcall is_region_userspace, ecx, 64
jnz .bad_buffer
mov esi, [ebx + NET_DEVICE.name]
mov edi, ecx
 
mov ecx, 64/4 ; max length
rep movsd
 
xor eax, eax
mov [esp+32], eax
ret
 
.reset:
call [eax + NET_DEVICE.reset]
mov [esp+32], eax
ret
 
.stop:
call [eax + NET_DEVICE.unload]
mov [esp+32], eax
ret
 
 
.get_ptr:
mov [esp+32], eax
ret
 
 
.get_drv_name:
xor eax, eax
mov [esp+32], eax
ret
 
.packets_tx:
mov eax, [eax + NET_DEVICE.packets_tx]
mov [esp+32], eax
ret
 
.packets_rx:
mov eax, [eax + NET_DEVICE.packets_rx]
mov [esp+32], eax
ret
 
.bytes_tx:
mov ebx, dword[eax + NET_DEVICE.bytes_tx + 4]
mov [esp+20], ebx
mov eax, dword[eax + NET_DEVICE.bytes_tx]
mov [esp+32], eax
ret
 
.bytes_rx:
mov ebx, dword[eax + NET_DEVICE.bytes_rx + 4]
mov [esp+20], ebx
mov eax, dword[eax + NET_DEVICE.bytes_rx]
mov [esp+32], eax
ret
 
.packets_tx_err:
mov eax, [eax + NET_DEVICE.packets_tx_err]
mov [esp+32], eax
ret
 
.packets_tx_drop:
mov eax, [eax + NET_DEVICE.packets_tx_drop]
mov [esp+32], eax
ret
 
.packets_tx_ovr:
mov eax, [eax + NET_DEVICE.packets_tx_ovr]
mov [esp+32], eax
ret
 
.packets_rx_err:
mov eax, [eax + NET_DEVICE.packets_rx_err]
mov [esp+32], eax
ret
 
.packets_rx_drop:
mov eax, [eax + NET_DEVICE.packets_rx_drop]
mov [esp+32], eax
ret
 
.packets_rx_ovr:
mov eax, [eax + NET_DEVICE.packets_rx_ovr]
mov [esp+32], eax
ret
 
.state:
mov eax, [eax + NET_DEVICE.link_state]
mov [esp+32], eax
ret
 
 
.doesnt_exist:
.bad_buffer: ; Sanity check failed, exit
mov dword[esp+32], -1
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; System function 76: Low level access to protocol handlers. ;
; ;
;-----------------------------------------------------------------;
align 4
sys_protocols:
cmp bh, NET_DEVICES_MAX ; Check if device number exists
jae .doesnt_exist
 
mov eax, ebx
and eax, 0x0000ff00
shr eax, 6 ; now we have the device num * 4 in eax
cmp [eax + net_device_list], 0 ; check if device is running
je .doesnt_exist
 
push .return ; return address (we will be using jumps instead of calls)
 
mov eax, ebx ; set ax to protocol number
shr eax, 16 ;
 
cmp ax, API_ETH
je eth_api
 
cmp ax, API_IPv4
je ipv4_api
 
cmp ax, API_ICMP
je icmp_api
 
cmp ax, API_UDP
je udp_api
 
cmp ax, API_TCP
je tcp_api
 
cmp ax, API_ARP
je arp_api
 
cmp ax, API_PPPOE
je pppoe_api
 
cmp ax, API_IPv6
je ipv6_api
 
add esp, 4 ; if we reached here, no function was called, so we need to balance stack
 
.doesnt_exist:
mov eax, -1
 
.return:
mov [esp+28+4], eax ; return eax value to the program
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/ethernet.inc
0,0 → 1,346
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; ETHERNET.INC ;;
;; ;;
;; Ethernet network layer for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
ETH_FRAME_MINIMUM = 60
ETH_QUEUE_SIZE = 255
 
struct ETH_header
 
DstMAC dp ? ; destination MAC-address
SrcMAC dp ? ; source MAC-address
Type dw ? ; type of the upper-layer protocol
 
ends
 
struct ETH_DEVICE NET_DEVICE
 
mac dp ?
 
ends
 
iglobal
align 4
 
ETH_BROADCAST dp 0xffffffffffff
 
ETH_frame_queued dd 0 ; Number of queued frames
 
ETH_frame_head dd ETH_frame_head ; Pointer to next frame in the linked list
ETH_frame_tail dd ETH_frame_head ; Pointer to last frame in the linked list
 
endg
 
uglobal
align 4
ETH_input_event dd ?
endg
 
macro eth_init {
 
movi ebx, 1
mov ecx, eth_process_input
call new_sys_threads
test eax, eax
jns @f
DEBUGF DEBUG_NETWORK_ERROR,'K : cannot create kernel thread for ethernet, error %d\n', eax
@@:
 
}
 
;-----------------------------------------------------------------;
; ;
; eth_input: This function is called by ethernet drivers. ;
; Push the received ethernet packet onto the ethernet input queue.;
; ;
; IN: [esp] = Pointer to buffer ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
eth_input:
 
pop eax
 
if defined NETWORK_SANITY_CHECKS
cmp eax, [net_buffs_low]
jb .assert_mbuff
cmp eax, [net_buffs_high]
ja .assert_mbuff
test eax, 0x7ff
jnz .assert_mbuff
end if
 
spin_lock_irqsave
 
cmp [ETH_frame_queued], ETH_QUEUE_SIZE
jae .full
inc [ETH_frame_queued]
 
; Add frame to the end of the linked list
mov [eax + NET_BUFF.NextPtr], ETH_frame_head
 
mov ebx, [ETH_frame_tail]
mov [eax + NET_BUFF.PrevPtr], ebx
 
mov [ETH_frame_tail], eax
mov [ebx + NET_BUFF.NextPtr], eax
 
spin_unlock_irqrestore
 
; Mark it as being an Ethernet Frame
mov [eax + NET_BUFF.type], NET_BUFF_ETH
 
; Now queue an event to process it
xor edx, edx
mov eax, [ETH_input_event]
mov ebx, [eax + EVENT.id]
xor esi, esi
call raise_event
 
ret
 
.full:
mov ebx, [eax + NET_BUFF.device]
inc [ebx + NET_DEVICE.packets_rx_ovr]
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH incoming queue is full, discarding packet!\n"
spin_unlock_irqrestore
stdcall net_buff_free, eax
ret
 
if defined NETWORK_SANITY_CHECKS
.assert_mbuff:
DEBUGF DEBUG_NETWORK_ERROR, "eth_input: invalid buffer 0x%x\n", eax
DEBUGF DEBUG_NETWORK_ERROR, "eth_input: caller=0x%x\n", [esp+4]
xor eax, eax
ret
end if
 
 
 
;-----------------------------------------------------------------;
; ;
; eth_process_input: Process packets from ethernet input queue. ;
; ;
; IN: / ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
eth_process_input:
 
xor esi, esi
mov ecx, MANUAL_DESTROY
call create_event
mov [ETH_input_event], eax
pushf
.wait:
popf
mov eax, [ETH_input_event]
mov ebx, [eax + EVENT.id]
call wait_event
 
.loop:
pushf
cli
cmp [ETH_frame_queued], 0
je .wait
 
dec [ETH_frame_queued]
 
mov esi, [ETH_frame_head]
mov ebx, [esi + NET_BUFF.NextPtr]
 
mov [ETH_frame_head], ebx
mov [ebx + NET_BUFF.PrevPtr], ETH_frame_head
 
popf
 
mov eax, [esi + NET_BUFF.offset]
add eax, esi
mov ecx, [esi + NET_BUFF.length]
mov ebx, [esi + NET_BUFF.device]
 
pushd .loop ; return address for protocol handler
push esi ; keep pointer to NET_BUFF on stack
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_input: size=%u\n", ecx
sub ecx, sizeof.ETH_header
jb .err
 
; Set registers for protocol handlers
lea edx, [eax + sizeof.ETH_header]
mov ax, [eax + ETH_header.Type]
 
; Place protocol handlers here
cmp ax, ETHER_PROTO_IPv4
je ipv4_input
 
cmp ax, ETHER_PROTO_ARP
je arp_input
 
; cmp ax, ETHER_PROTO_IPv6
; je ipv6_input
 
; cmp ax, ETHER_PROTO_PPP_DISCOVERY
; je pppoe_discovery_input
 
; cmp ax, ETHER_PROTO_PPP_SESSION
; je pppoe_session_input
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_input: Unknown packet type=%x\n", ax
 
.drop:
mov eax, [esp]
mov eax, [eax + NET_BUFF.device]
inc [eax + NET_DEVICE.packets_rx_drop]
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_input: dropping\n"
call net_buff_free
ret
 
.err:
mov eax, [esp]
mov eax, [eax + NET_BUFF.device]
inc [eax + NET_DEVICE.packets_rx_err]
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_input: invalid frame received\n"
call net_buff_free
ret
 
 
 
 
;-----------------------------------------------------------------;
; ;
; eth_output ;
; ;
; IN: ax = protocol ;
; ebx = device ptr ;
; ecx = payload size ;
; edx = pointer to destination mac ;
; ;
; OUT: eax = start of net frame / 0 on error ;
; ebx = device ptr ;
; ecx = payload size ;
; edi = start of payload ;
; ;
;-----------------------------------------------------------------;
align 4
eth_output:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_output: size=%u device=%x\n", ecx, ebx
 
cmp ecx, [ebx + ETH_DEVICE.mtu]
ja .too_large
 
push ecx
push ax edx
 
add ecx, sizeof.ETH_header + NET_BUFF.data
stdcall net_buff_alloc, ecx
test eax, eax
jz .out_of_ram
 
mov [eax + NET_BUFF.type], NET_BUFF_ETH
mov [eax + NET_BUFF.device], ebx
mov [eax + NET_BUFF.offset], NET_BUFF.data
lea edi, [eax + NET_BUFF.data]
 
pop esi
movsd
movsw
lea esi, [ebx + ETH_DEVICE.mac]
movsd
movsw
pop ax
stosw
 
lea eax, [edi - sizeof.ETH_header - NET_BUFF.data] ; Set eax to buffer start
pop ecx
 
lea edx, [ecx + sizeof.ETH_header] ; Set edx to complete buffer size
cmp edx, ETH_FRAME_MINIMUM
jbe .adjust_size
.done:
mov [eax + NET_BUFF.length], edx
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_output: ptr=%x size=%u\n", eax, edx
ret
 
.adjust_size:
mov edx, ETH_FRAME_MINIMUM
test edx, edx ; clear zero flag
jmp .done
 
.out_of_ram:
inc [ebx + NET_DEVICE.packets_tx_drop]
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_output: Out of ram!\n"
add esp, 4+2
pop ecx
xor eax, eax
ret
 
.too_large:
inc [eax + NET_DEVICE.packets_tx_err]
DEBUGF DEBUG_NETWORK_VERBOSE, "ETH_output: Packet too large!\n"
xor eax, eax
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; eth_api: Part of system function 76. ;
; ;
; IN: bl = subfunction number ;
; bh = device number ;
; ecx, edx, .. depends on subfunction ;
; ;
; OUT: depends on subfunction ;
; ;
;-----------------------------------------------------------------;
align 4
eth_api:
 
cmp bh, NET_DEVICES_MAX
ja .error
movzx eax, bh
mov eax, dword [net_device_list + 4*eax]
cmp [eax + NET_DEVICE.device_type], NET_DEVICE_ETH
jne .error
 
and ebx, 0xff
cmp ebx, .number
ja .error
jmp dword [.table + 4*ebx]
 
.table:
dd .read_mac ; 0
.number = ($ - .table) / 4 - 1
 
.error:
or eax, -1
ret
 
 
.read_mac:
movzx ebx, word [eax + ETH_DEVICE.mac]
mov eax, dword [eax + ETH_DEVICE.mac + 2]
mov [esp+20+4], ebx ; FIXME
ret
 
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/socket.inc
0,0 → 1,2525
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org, ;;
;; and Clevermouse. ;;
;; ;;
;; Based on code by mike.dld ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
struct SOCKET
 
NextPtr dd ? ; pointer to next socket in list
PrevPtr dd ? ; pointer to previous socket in list
Number dd ? ; socket number
 
mutex MUTEX
 
PID dd ? ; process ID
TID dd ? ; thread ID
Domain dd ? ; INET4/INET6/LOCAL/..
Type dd ? ; RAW/STREAM/DGRAM
Protocol dd ? ; UDP/TCP/ARP/ICMP
errorcode dd ?
device dd ? ; device pointer, paired socket pointer if it's a local socket
 
options dd ?
state dd ?
backlog dw ? ; number of incoming connections that can be queued
 
snd_proc dd ?
rcv_proc dd ?
connect_proc dd ?
 
ends
 
struct IP_SOCKET SOCKET
 
LocalIP rd 4 ; network byte order
RemoteIP rd 4 ; network byte order
ttl db ?
rb 3 ; align
 
ends
 
struct TCP_SOCKET IP_SOCKET
 
LocalPort dw ? ; network byte order
RemotePort dw ? ; network byte order
 
t_state dd ? ; TCB state
t_rxtshift db ?
rb 3 ; align
t_rxtcur dd ?
t_dupacks dd ?
t_maxseg dd ?
t_flags dd ?
 
;---------------
; RFC783 page 21
 
; send sequence
SND_UNA dd ? ; sequence number of unack'ed sent Packets
SND_NXT dd ? ; next send sequence number to use
SND_UP dd ? ; urgent pointer
SND_WL1 dd ? ; the sequence number of the last segment used to update the send window
SND_WL2 dd ? ; the acknowledgment number of the last segment used to update the send window
ISS dd ? ; initial send sequence number
SND_WND dd ? ; send window
 
; receive sequence
RCV_WND dd ? ; receive window
RCV_NXT dd ? ; next receive sequence number to use
RCV_UP dd ? ; urgent pointer
IRS dd ? ; initial receive sequence number
 
;---------------------
; Additional variables
 
; receive variables
RCV_ADV dd ?
 
; retransmit variables
SND_MAX dd ?
 
; congestion control
SND_CWND dd ? ; congestion window
SND_SSTHRESH dd ? ; slow start threshold
 
;----------------------
; Transmit timing stuff
t_idle dd ?
t_rtt dd ? ; round trip time
t_rtseq dd ?
t_srtt dd ? ; smoothed round trip time
t_rttvar dd ?
t_rttmin dd ?
max_sndwnd dd ?
 
;-----------------
; Out-of-band data
t_oobflags dd ?
t_iobc dd ?
t_softerror dd ?
 
 
;---------
; RFC 1323 ; the order of next 4 elements may not change
 
SND_SCALE db ?
RCV_SCALE db ?
requested_s_scale db ?
request_r_scale db ?
 
ts_recent dd ? ; a copy of the most-recent valid timestamp from the other end
ts_recent_age dd ?
last_ack_sent dd ?
 
 
;-------
; Timers
timer_flags dd ?
timer_retransmission dd ? ; rexmt
timer_persist dd ?
timer_keepalive dd ? ; keepalive/syn timeout
timer_timed_wait dd ? ; also used as 2msl timer
timer_connect dd ?
 
; extra
 
ts_ecr dd ? ; timestamp echo reply
ts_val dd ?
 
seg_next dd ? ; re-assembly queue
 
ends
 
struct UDP_SOCKET IP_SOCKET
 
LocalPort dw ? ; in network byte order
RemotePort dw ? ; in network byte order
 
ends
 
struct RING_BUFFER
 
mutex MUTEX
start_ptr dd ? ; Pointer to start of buffer
end_ptr dd ? ; pointer to end of buffer
read_ptr dd ? ; Read pointer
write_ptr dd ? ; Write pointer
size dd ? ; Number of bytes buffered
 
ends
 
struct STREAM_SOCKET TCP_SOCKET
 
rcv RING_BUFFER
snd RING_BUFFER
 
ends
 
struct socket_queue_entry
 
data_ptr dd ?
data_size dd ?
buf_ptr dd ?
 
ends
 
struct socket_options
 
level dd ?
optname dd ?
optlen dd ?
optval dd ?
 
ends
 
SOCKET_STRUCT_SIZE = 4096 ; in bytes
 
SOCKET_QUEUE_SIZE = 10 ; maximum number of incoming packets queued for 1 socket
; the incoming packet queue for sockets is placed in the socket struct itself, at this location from start
SOCKET_QUEUE_LOCATION = (SOCKET_STRUCT_SIZE - SOCKET_QUEUE_SIZE*sizeof.socket_queue_entry - sizeof.queue)
 
uglobal
align 4
 
net_sockets rd 4
last_socket_num dd ?
last_UDP_port dw ? ; last used ephemeral port
last_TCP_port dw ? ;
socket_mutex MUTEX
 
endg
 
 
;-----------------------------------------------------------------;
; ;
; socket_init ;
; ;
;-----------------------------------------------------------------;
macro socket_init {
 
xor eax, eax
mov edi, net_sockets
mov ecx, 5
rep stosd
 
@@:
pseudo_random eax
cmp ax, EPHEMERAL_PORT_MIN
jb @r
cmp ax, EPHEMERAL_PORT_MAX
ja @r
xchg al, ah
mov [last_UDP_port], ax
 
@@:
pseudo_random eax
cmp ax, EPHEMERAL_PORT_MIN
jb @r
cmp ax, EPHEMERAL_PORT_MAX
ja @r
xchg al, ah
mov [last_TCP_port], ax
 
mov ecx, socket_mutex
call mutex_init
 
}
 
;-----------------------------------------------------------------;
; ;
; Sockets API (system function 75) ;
; ;
;-----------------------------------------------------------------;
align 4
sys_socket:
 
mov dword[esp+20], 0 ; Set error code to 0
 
cmp ebx, 255
jz socket_debug
 
cmp ebx, .number
ja .error
jmp dword [.table + 4*ebx]
 
.table:
dd socket_open ; 0
dd socket_close ; 1
dd socket_bind ; 2
dd socket_listen ; 3
dd socket_connect ; 4
dd socket_accept ; 5
dd socket_send ; 6
dd socket_receive ; 7
dd socket_set_opt ; 8
dd socket_get_opt ; 9
dd socket_pair ; 10
.number = ($ - .table) / 4 - 1
 
.error:
mov dword[esp+32], -1
mov dword[esp+20], EINVAL
 
ret
 
;-----------------------------------------------------------------;
; ;
; socket_open: Create a new socket. ;
; ;
; IN: ecx = domain ;
; edx = type ;
; esi = protocol ;
; ;
; OUT: eax = socket number ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_open:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_open: domain=%u type=%u protocol=%x\n", ecx, edx, esi
 
push ecx edx esi
call socket_alloc
pop esi edx ecx
test eax, eax
jz .nobuffs
 
mov [esp+32], edi ; return socketnumber
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_open: socknum=%u\n", edi
 
test edx, SO_NONBLOCK
jz @f
or [eax + SOCKET.options], SO_NONBLOCK
and edx, not SO_NONBLOCK
@@:
 
mov [eax + SOCKET.Domain], ecx
mov [eax + SOCKET.Type], edx
mov [eax + SOCKET.Protocol], esi
mov [eax + SOCKET.connect_proc], connect_notsupp
 
cmp ecx, AF_INET4
jne .no_inet4
 
mov [eax + IP_SOCKET.ttl], 128
 
cmp edx, SOCK_DGRAM
je .udp
 
cmp edx, SOCK_STREAM
je .tcp
 
cmp edx, SOCK_RAW
je .raw
 
.no_inet4:
cmp ecx, AF_PPP
jne .no_ppp
 
cmp esi, PPP_PROTO_ETHERNET
je .pppoe
 
.no_ppp:
.unsupported:
push eax
call socket_free
pop eax
mov dword[esp+20], EOPNOTSUPP
mov dword[esp+32], -1
ret
 
.nobuffs:
mov dword[esp+20], ENOBUFS
mov dword[esp+32], -1
ret
 
.raw:
test esi, esi ; IP_PROTO_IP
jz .raw_ip
 
cmp esi, IP_PROTO_ICMP
je .raw_icmp
 
jmp .unsupported
 
align 4
.udp:
push eax
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue
pop eax
 
mov [eax + SOCKET.Protocol], IP_PROTO_UDP
mov [eax + SOCKET.snd_proc], socket_send_udp
mov [eax + SOCKET.rcv_proc], socket_receive_dgram
mov [eax + SOCKET.connect_proc], udp_connect
ret
 
align 4
.tcp:
mov [eax + SOCKET.Protocol], IP_PROTO_TCP
mov [eax + SOCKET.snd_proc], socket_send_tcp
mov [eax + SOCKET.rcv_proc], socket_receive_tcp
mov [eax + SOCKET.connect_proc], tcp_connect
 
tcp_init_socket eax
ret
 
 
align 4
.raw_ip:
push eax
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue
pop eax
 
mov [eax + SOCKET.snd_proc], socket_send_ip
mov [eax + SOCKET.rcv_proc], socket_receive_dgram
mov [eax + SOCKET.connect_proc], ipv4_connect
ret
 
 
align 4
.raw_icmp:
push eax
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue
pop eax
 
mov [eax + SOCKET.snd_proc], socket_send_icmp
mov [eax + SOCKET.rcv_proc], socket_receive_dgram
mov [eax + SOCKET.connect_proc], ipv4_connect
ret
 
align 4
.pppoe:
push eax
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up data receiving queue
pop eax
 
mov [eax + SOCKET.snd_proc], socket_send_pppoe
mov [eax + SOCKET.rcv_proc], socket_receive_dgram
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_bind: Bind to a local port. ;
; ;
; IN: ecx = socket number ;
; edx = pointer to sockaddr struct ;
; esi = length of sockaddr struct ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_bind:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_bind: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
cmp esi, 2
jb .invalid
 
cmp [eax + UDP_SOCKET.LocalPort], 0 ; Socket can only be bound once
jnz .invalid
 
cmp word[edx], AF_INET4
je .af_inet4
 
cmp word[edx], AF_LOCAL
je .af_local
 
.notsupp:
mov dword[esp+20], EOPNOTSUPP
mov dword[esp+32], -1
ret
 
.invalid:
mov dword[esp+20], EINVAL
mov dword[esp+32], -1
ret
 
.af_local:
; TODO: write code here
mov dword[esp+32], 0
ret
 
.af_inet4:
cmp esi, 6
jb .invalid
 
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP
je .udp
 
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
je .tcp
 
jmp .notsupp
 
.tcp:
.udp:
pushd [edx + 4] ; First, fill in the IP
popd [eax + IP_SOCKET.LocalIP]
 
mov bx, [edx + 2] ; Did caller specify a local port?
test bx, bx
jnz .just_check
call socket_find_port ; Nope, find an ephemeral one
jmp .done
 
.just_check:
call socket_check_port ; Yes, check if it's still available
jz .addrinuse ; ZF is set by socket_check_port on error
 
.done:
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_bind: local ip=%u.%u.%u.%u\n",\
[eax + IP_SOCKET.LocalIP + 0]:1,[eax + IP_SOCKET.LocalIP + 1]:1,\
[eax + IP_SOCKET.LocalIP + 2]:1,[eax + IP_SOCKET.LocalIP + 3]:1
 
mov dword[esp+32], 0
ret
 
.addrinuse:
mov dword[esp+32], -1
mov dword[esp+20], EADDRINUSE
ret
 
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_connect: Connect to the remote host. ;
; ;
; IN: ecx = socket number ;
; edx = pointer to sockaddr struct ;
; esi = length of sockaddr struct ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_connect:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_connect: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
cmp esi, 8
jb .invalid
 
cmp [eax + SOCKET.state], SS_ISCONNECTING
je .already
 
test [eax + SOCKET.options], SO_ACCEPTCON
jnz .notsupp
 
call [eax + SOCKET.connect_proc]
 
mov dword[esp+20], ebx
mov dword[esp+32], eax
ret
 
 
.notsupp:
mov dword[esp+20], EOPNOTSUPP
mov dword[esp+32], -1
ret
 
.invalid:
mov dword[esp+20], EINVAL
mov dword[esp+32], -1
ret
 
.already:
mov dword[esp+20], EALREADY
mov dword[esp+32], -1
ret
 
 
connect_notsupp:
xor eax, eax
dec eax
mov ebx, EOPNOTSUPP
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_listen: Listen for incoming connections. ;
; ;
; IN: ecx = socket number ;
; edx = backlog in edx ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_listen:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_listen: socknum=%u backlog=%u\n", ecx, edx
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
cmp [eax + SOCKET.Domain], AF_INET4
jne .notsupp
 
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
jne .invalid
 
cmp [eax + TCP_SOCKET.LocalPort], 0
je .already
 
cmp [eax + IP_SOCKET.LocalIP], 0
jne @f
push [IPv4_address + 4] ;;; fixme!!!!
pop [eax + IP_SOCKET.LocalIP]
@@:
 
cmp edx, MAX_backlog
jbe @f
mov edx, MAX_backlog
@@:
 
mov [eax + SOCKET.backlog], dx
or [eax + SOCKET.options], SO_ACCEPTCON
mov [eax + TCP_SOCKET.t_state], TCPS_LISTEN
mov [eax + TCP_SOCKET.timer_keepalive], 0 ; disable keepalive timer
 
push eax
init_queue (eax + SOCKET_QUEUE_LOCATION) ; Set up sockets queue
pop eax
 
mov dword[esp+32], 0
ret
 
.notsupp:
mov dword[esp+20], EOPNOTSUPP
mov dword[esp+32], -1
ret
 
.invalid:
mov dword[esp+20], EINVAL
mov dword[esp+32], -1
ret
 
.already:
mov dword[esp+20], EALREADY
mov dword[esp+32], -1
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_accept: Accept an incoming connection. ;
; ;
; IN: ecx = socket number (of listening socket) ;
; edx = ptr to sockaddr struct ;
; esi = length of sockaddr struct ;
; ;
; OUT: eax = newly created socket num ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_accept:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_accept: socknum=%u sockaddr=%x length=%u\n", ecx, edx, esi
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
test [eax + SOCKET.options], SO_ACCEPTCON
jz .invalid
 
cmp [eax + SOCKET.Domain], AF_INET4
jne .notsupp
 
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
jne .invalid
 
.loop:
get_from_queue (eax + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .block
 
; Ok, we got a socket ptr
mov eax, [esi]
 
; Verify that it is (still) a valid socket
call socket_check
jz .invalid
 
; Change sockets thread owner ID to that of the current thread
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.TID], ebx
 
; Return socket number to caller
mov eax, [eax + SOCKET.Number]
mov [esp+32], eax
ret
 
.block:
test [eax + SOCKET.options], SO_NONBLOCK
jnz .wouldblock
 
call socket_block
jmp .loop
 
.wouldblock:
mov dword[esp+20], EWOULDBLOCK
mov dword[esp+32], -1
ret
 
.invalid:
mov dword[esp+20], EINVAL
mov dword[esp+32], -1
ret
 
.notsupp:
mov dword[esp+20], EOPNOTSUPP
mov dword[esp+32], -1
ret
 
;-----------------------------------------------------------------;
; ;
; socket_close: Close the socket (and connection). ;
; ;
; IN: ecx = socket number ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_close:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_close: socknum=%u\n", ecx
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
mov dword[esp+32], 0 ; The socket exists, so we will succeed in closing it.
 
or [eax + SOCKET.options], SO_NONBLOCK ; Mark the socket as non blocking, we dont want it to block any longer!
 
test [eax + SOCKET.state], SS_BLOCKED ; Is the socket still in blocked state?
jz @f
call socket_notify ; Unblock it.
@@:
 
cmp [eax + SOCKET.Domain], AF_INET4
jne .free
 
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
je .tcp
 
.free:
call socket_free
ret
 
.tcp:
test [eax + SOCKET.state], SS_ISCONNECTED
jz @f
test [eax + SOCKET.state], SS_ISDISCONNECTING
jnz @f
call tcp_disconnect
@@:
; TODO:
; ...
; call socket_free
ret
 
 
.invalid:
mov dword[esp+20], EINVAL
mov dword[esp+32], -1
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_receive: Receive some data from the remote end. ;
; ;
; IN: ecx = socket number ;
; edx = addr to application buffer ;
; edx = length of application buffer ;
; edi = flags ;
; ;
; OUT: eax = number of bytes copied ;
; eax = -1 on error ;
; eax = 0 when socket has been closed by the remote end ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_receive:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_receive: socknum=%u bufaddr=%x buflength=%u flags=%x\n", ecx, edx, esi, edi
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
.loop:
push edi
call [eax + SOCKET.rcv_proc]
pop edi
 
test [eax + SOCKET.state], SS_CANTRCVMORE
jnz .last_data
 
cmp ebx, EWOULDBLOCK
jne .return
 
test edi, MSG_DONTWAIT
jnz .return_err
 
test [eax + SOCKET.options], SO_NONBLOCK
jnz .return_err
 
call socket_block
jmp .loop
 
 
.invalid:
push EINVAL
pop ebx
.return_err:
mov ecx, -1
.return:
mov [esp+20], ebx
mov [esp+32], ecx
ret
 
.last_data:
test ecx, ecx
jz .return
call socket_notify ; Call me again!
jmp .return
 
 
 
 
align 4
socket_receive_dgram:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_receive: DGRAM\n"
 
test edi, MSG_PEEK
jnz .peek
 
mov ebx, esi ; buffer length
 
get_from_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .wouldblock ; sets esi only on success.
mov ecx, [esi + socket_queue_entry.data_size]
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_receive: %u bytes data\n", ecx
 
cmp ecx, ebx ; If data segment does not fit in applications buffer, abort
ja .too_small
 
push eax ecx
push [esi + socket_queue_entry.buf_ptr] ; save the buffer addr so we can clear it later
mov esi, [esi + socket_queue_entry.data_ptr]
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_receive: Source buffer=%x real addr=%x\n", [esp], esi
 
; copy the data from kernel buffer to application buffer
mov edi, edx ; bufferaddr
shr ecx, 1
jnc .nb
movsb
.nb:
shr ecx, 1
jnc .nw
movsw
.nw:
test ecx, ecx
jz .nd
rep movsd
.nd:
 
call net_buff_free
pop ecx eax ; return number of bytes copied to application
cmp [eax + SOCKET_QUEUE_LOCATION + queue.size], 0
je @f
call socket_notify ; Queue another network event
@@:
xor ebx, ebx ; errorcode = 0 (no error)
ret
 
.too_small:
mov ecx, -1
push EMSGSIZE
pop ebx
ret
 
.wouldblock:
push EWOULDBLOCK
pop ebx
ret
 
.peek:
xor ebx, ebx
xor ecx, ecx
cmp [eax + SOCKET_QUEUE_LOCATION + queue.size], 0
je @f
mov esi, [eax + SOCKET_QUEUE_LOCATION + queue.r_ptr]
mov ecx, [esi + socket_queue_entry.data_size]
@@:
ret
 
align 4
socket_receive_tcp:
 
call socket_receive_stream
 
test ecx, ecx
jz @f
push eax ebx ecx
call tcp_output
pop ecx ebx eax
@@:
 
ret
 
 
align 4
socket_receive_local:
 
; does this socket have a PID yet?
cmp [eax + SOCKET.PID], 0
jne @f
 
; Change PID to that of current process
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx
mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :(
@@:
 
mov [eax + SOCKET.rcv_proc], socket_receive_stream
 
; ... continue to SOCKET_receive_stream
 
align 4
socket_receive_stream:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_receive: STREAM\n"
 
cmp [eax + STREAM_SOCKET.rcv.size], 0
je .wouldblock
 
test edi, MSG_PEEK
jnz .peek
 
mov ecx, esi
mov edi, edx
xor edx, edx
 
push eax
add eax, STREAM_SOCKET.rcv
call socket_ring_read ; copy data from kernel buffer to application buffer
call socket_ring_free ; free read memory
pop eax
 
cmp [eax + STREAM_SOCKET.rcv.size], 0
jne .more_data
xor ebx, ebx ; errorcode = 0 (no error)
ret
 
.more_data:
call socket_notify ; Queue another network event
xor ebx, ebx ; errorcode = 0 (no error)
ret
 
.wouldblock:
push EWOULDBLOCK
pop ebx
xor ecx, ecx
ret
 
.peek:
mov ecx, [eax + STREAM_SOCKET.rcv.size]
xor ebx, ebx
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_send: Send some data to the remote end. ;
; ;
; IN: ecx = socket number ;
; edx = pointer to data ;
; esi = data length ;
; edi = flags ;
; ;
; OUT: eax = number of bytes sent ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_send:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_send: socknum=%u data ptr=%x length=%u flags=%x\n", ecx, edx, esi, edi
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
mov ecx, esi
mov esi, edx
 
jmp [eax + SOCKET.snd_proc]
 
.invalid:
mov dword[esp+20], EINVAL
mov dword[esp+32], -1
ret
 
 
align 4
socket_send_udp:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_send: UDP\n"
 
mov [esp+32], ecx
call udp_output
cmp eax, -1
je .error
ret
 
.error:
mov dword[esp+32], -1
mov dword[esp+20], EMSGSIZE ; FIXME: UDP_output should return error codes!
ret
 
 
align 4
socket_send_tcp:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_send: TCP\n"
 
push eax
add eax, STREAM_SOCKET.snd
call socket_ring_write
pop eax
 
mov [esp+32], ecx
mov [eax + SOCKET.errorcode], 0
push eax
call tcp_output ; FIXME: this doesnt look pretty, does it?
pop eax
mov eax, [eax + SOCKET.errorcode]
mov [esp+20], eax
ret
 
 
align 4
socket_send_ip:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_send: IPv4\n"
 
mov [esp+32], ecx
call ipv4_output_raw
cmp eax, -1
je .error
ret
 
.error:
mov dword[esp+32], eax
mov dword[esp+20], ebx
ret
 
 
align 4
socket_send_icmp:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_send: ICMP\n"
 
mov [esp+32], ecx
call icmp_output_raw
cmp eax, -1
je .error
ret
 
.error:
mov dword[esp+32], eax
mov dword[esp+20], ebx
ret
 
 
align 4
socket_send_pppoe:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_send: PPPoE\n"
 
mov [esp+32], ecx
mov ebx, [eax + SOCKET.device]
 
call pppoe_discovery_output ; FIXME: errorcodes
cmp eax, -1
je .error
ret
 
.error:
mov dword[esp+32], -1
mov dword[esp+20], EMSGSIZE
ret
 
 
 
align 4
socket_send_local:
 
; does this socket have a PID yet?
cmp [eax + SOCKET.PID], 0
jne @f
 
; Change PID to that of current process
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx
mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :(
@@:
mov [eax + SOCKET.snd_proc], socket_send_local_initialized
 
align 4
socket_send_local_initialized:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_send: LOCAL\n"
 
; get the other side's socket and check if it still exists
mov eax, [eax + SOCKET.device]
call socket_check
jz .invalid
 
; allright, shove in the data!
push eax
add eax, STREAM_SOCKET.rcv
call socket_ring_write
pop eax
 
; return the number of written bytes (or errorcode) to application
mov [esp+32], ecx
 
; and notify the other end
call socket_notify
 
ret
 
.invalid:
mov dword[esp+32], -1
mov dword[esp+20], EINVAL
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_get_opt: Read a socket option ;
; ;
; IN: ecx = socket number ;
; edx = pointer to socket options struct ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_get_opt:
 
; FIXME:
; At moment, uses only pseudo-optname -2 for get last_ack_number for TCP.
; TODO: find best way to notify that send()'ed data were acknowledged
; Also pseudo-optname -3 is valid and returns socket state, one of TCPS_*.
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_get_opt\n"
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
cmp dword [edx], IP_PROTO_TCP
jne .invalid
cmp dword [edx+4], -2
je @f
cmp dword [edx+4], -3
jne .invalid
@@:
; mov eax, [edx+12]
; test eax, eax
; jz .fail
; cmp dword [eax], 4
; mov dword [eax], 4
; jb .fail
; stdcall net_socket_num_to_addr, ecx
; test eax, eax
; jz .fail
; ; todo: check that eax is really TCP socket
; mov ecx, [eax + TCP_SOCKET.last_ack_number]
; cmp dword [edx+4], -2
; jz @f
; mov ecx, [eax + TCP_SOCKET.state]
@@:
mov eax, [edx+8]
test eax, eax
jz @f
mov [eax], ecx
@@:
mov dword [esp+32], 0
ret
 
.invalid:
mov dword[esp+32], -1
mov dword[esp+20], EINVAL
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_set_options: Set a socket option. ;
; ;
; IN: ecx = socket number ;
; edx = pointer to socket options struct ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_set_opt:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt\n"
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
cmp [edx + socket_options.level], IP_PROTO_IP
je .ip
cmp [edx + socket_options.level], SOL_SOCKET
jne .invalid
 
.socket:
cmp [edx + socket_options.optname], SO_BINDTODEVICE
jne .invalid
 
.bind:
cmp [edx + socket_options.optlen], 0
je .unbind
 
movzx edx, byte[edx + socket_options.optval]
cmp edx, NET_DEVICES_MAX
ja .invalid
 
mov edx, [net_device_list + 4*edx]
test edx, edx
jz .already
mov [eax + SOCKET.device], edx
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_set_opt: Bound socket %x to device %x\n", eax, edx
 
mov dword[esp+32], 0 ; success!
ret
 
.unbind:
mov [eax + SOCKET.device], 0
 
mov dword[esp+32], 0 ; success!
ret
 
.ip:
cmp [edx + socket_options.optname], IP_TTL
jne .invalid
 
.ttl:
mov bl, byte[edx + socket_options.optval]
mov [eax + IP_SOCKET.ttl], bl
 
mov dword[esp+32], 0 ; success!
ret
 
.already:
mov dword[esp+20], EALREADY
mov dword[esp+32], -1
ret
 
.invalid:
mov dword[esp+20], EINVAL
mov dword[esp+32], -1
ret
 
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_pair: Allocate a pair of linked local sockets. ;
; ;
; IN: / ;
; ;
; OUT: eax = socket1 num on success ;
; eax = -1 on error ;
; ebx = socket2 num on success ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_pair:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_pair\n"
 
call socket_alloc
test eax, eax
jz .nomem1
mov [esp+32], edi ; application's eax
 
mov [eax + SOCKET.Domain], AF_LOCAL
mov [eax + SOCKET.Type], SOCK_STREAM
mov [eax + SOCKET.Protocol], 0 ;;; CHECKME
mov [eax + SOCKET.snd_proc], socket_send_local
mov [eax + SOCKET.rcv_proc], socket_receive_local
mov [eax + SOCKET.PID], 0
mov ebx, eax
 
call socket_alloc
test eax, eax
jz .nomem2
mov [esp+20], edi ; application's ebx
 
mov [eax + SOCKET.Domain], AF_LOCAL
mov [eax + SOCKET.Type], SOCK_STREAM
mov [eax + SOCKET.Protocol], 0 ;;; CHECKME
mov [eax + SOCKET.snd_proc], socket_send_local
mov [eax + SOCKET.rcv_proc], socket_receive_local
mov [eax + SOCKET.PID], 0
 
; Link the two sockets to eachother
mov [eax + SOCKET.device], ebx
mov [ebx + SOCKET.device], eax
 
lea eax, [eax + STREAM_SOCKET.rcv]
call socket_ring_create
test eax, eax
jz .nomem2
 
lea eax, [ebx + STREAM_SOCKET.rcv]
call socket_ring_create
test eax, eax
jz .nomem2
 
ret
 
.nomem2:
mov eax, [esp+20]
call socket_free
 
.nomem1:
mov eax, [esp+32]
call socket_free
 
mov dword[esp+32], -1
mov dword[esp+20], ENOMEM
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_debug: Copy socket variables to application buffer. ;
; ;
; IN: ecx = socket number ;
; edx = pointer to application buffer ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = errorcode on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_debug:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_debug\n"
 
mov edi, edx
 
test ecx, ecx
jz .returnall
 
call socket_num_to_ptr
test eax, eax
jz .invalid
 
mov esi, eax
mov ecx, SOCKET_STRUCT_SIZE/4
rep movsd
 
mov dword[esp+32], 0
ret
 
.returnall:
mov ebx, net_sockets
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
test ebx, ebx
jz .done
mov eax, [ebx + SOCKET.Number]
stosd
jmp .next_socket
.done:
xor eax, eax
stosd
mov dword[esp+32], eax
ret
 
.invalid:
mov dword[esp+32], -1
mov dword[esp+20], EINVAL
ret
 
 
;-----------------------------------------------------------------;
; ____ ____ ;
; \ / End of sockets API \ / ;
; \/ \/ ;
; () Internally used functions follow () ;
; ;
;-----------------------------------------------------------------;
 
 
;-----------------------------------------------------------------;
; ;
; socket_find_port: ;
; Fill in the local port number for TCP and UDP sockets ;
; This procedure always works because the number of sockets is ;
; limited to a smaller number then the number of possible ports ;
; ;
; IN: eax = socket pointer ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_find_port:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_find_port\n"
 
push ebx esi ecx
 
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP
je .udp
 
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
je .tcp
 
pop ecx esi ebx
ret
 
.udp:
mov bx, [last_UDP_port]
call .findit
mov [last_UDP_port], bx
 
pop ecx esi ebx
ret
 
.tcp:
mov bx, [last_TCP_port]
call .findit
mov [last_TCP_port], bx
 
pop ecx esi ebx
ret
 
 
.restart:
mov bx, MIN_EPHEMERAL_PORT_N
.findit:
cmp bx, MAX_EPHEMERAL_PORT_N
je .restart
 
add bh, 1
adc bl, 0
 
call socket_check_port
jz .findit
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_check_port: (to be used with AF_INET only!) ;
; Checks if a local port number is unused ;
; If the proposed port number is unused, it is filled in in the ;
; socket structure. ;
; ;
; IN: eax = socket ptr ;
; bx = proposed socket number (network byte order) ;
; ;
; OUT: ZF = set on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_check_port:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_check_port: "
 
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
mov ecx, [eax + SOCKET.Protocol]
mov edx, [eax + IP_SOCKET.LocalIP]
mov esi, net_sockets
 
.next_socket:
mov esi, [esi + SOCKET.NextPtr]
or esi, esi
jz .port_ok
 
cmp [esi + SOCKET.Protocol], ecx
jne .next_socket
 
cmp [esi + IP_SOCKET.LocalIP], edx
jne .next_socket
 
cmp [esi + UDP_SOCKET.LocalPort], bx
jne .next_socket
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "local port %x already in use\n", bx ; FIXME: find a way to print big endian values with debugf
ret
 
.port_ok:
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "local port %x is free\n", bx ; FIXME: find a way to print big endian values with debugf
mov [eax + UDP_SOCKET.LocalPort], bx
or bx, bx ; clear the zero-flag
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_input: Update a (stateless) socket with received data. ;
; ;
; Note: The socket's mutex should already be set ! ;
; ;
; IN: eax = socket ptr ;
; ecx = data size ;
; esi = ptr to data ;
; [esp] = ptr to buf ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_input:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_input: socket=%x, data=%x size=%u\n", eax, esi, ecx
 
push ecx
push esi
mov esi, esp
 
add_to_queue (eax + SOCKET_QUEUE_LOCATION), SOCKET_QUEUE_SIZE, sizeof.socket_queue_entry, .full
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_input: success\n"
add esp, sizeof.socket_queue_entry
 
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
popa
 
jmp socket_notify
 
.full:
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_input: socket %x is full!\n", eax
 
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
popa
 
add esp, 8
call net_buff_free
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_ring_create: Create a ringbuffer for sockets. ;
; ;
; IN: eax = ptr to ring struct ;
; ;
; OUT: eax = 0 on error ;
; eax = start ptr ;
; ;
;-----------------------------------------------------------------;
align 4
socket_ring_create:
 
push esi
mov esi, eax
 
push edx
stdcall create_ring_buffer, SOCKET_BUFFER_SIZE, PG_SWR
pop edx
test eax, eax
jz .fail
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_ring_create: %x\n", eax
 
pusha
lea ecx, [esi + RING_BUFFER.mutex]
call mutex_init
popa
 
mov [esi + RING_BUFFER.start_ptr], eax
mov [esi + RING_BUFFER.write_ptr], eax
mov [esi + RING_BUFFER.read_ptr], eax
mov [esi + RING_BUFFER.size], 0
add eax, SOCKET_BUFFER_SIZE
mov [esi + RING_BUFFER.end_ptr], eax
mov eax, esi
 
pop esi
ret
 
.fail:
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_ring_create: Out of memory!\n"
pop esi
ret
 
;-----------------------------------------------------------------;
; ;
; socket_ring_write: Write data to ring buffer. ;
; ;
; IN: eax = ptr to ring struct ;
; ecx = data size ;
; esi = ptr to data ;
; ;
; OUT: ecx = number of bytes stored ;
; ;
;-----------------------------------------------------------------;
align 4
socket_ring_write:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: ringbuff=%x ptr=%x size=%u\n", eax, esi, ecx
 
; lock mutex
pusha
lea ecx, [eax + RING_BUFFER.mutex]
call mutex_lock ; TODO: check what registers this function actually destroys
popa
 
; calculate available size
mov edi, SOCKET_BUFFER_SIZE
sub edi, [eax + RING_BUFFER.size] ; available buffer size in edi
cmp ecx, edi
jbe .copy
mov ecx, edi
.copy:
mov edi, [eax + RING_BUFFER.write_ptr]
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_ring_write: %u bytes from %x to %x\n", ecx, esi, edi
 
; update write ptr
push edi
add edi, ecx
cmp edi, [eax + RING_BUFFER.end_ptr]
jb @f
sub edi, SOCKET_BUFFER_SIZE ; WRAP
@@:
mov [eax + RING_BUFFER.write_ptr], edi
pop edi
 
; update size
add [eax + RING_BUFFER.size], ecx
 
; copy the data
push ecx
shr ecx, 1
jnc .nb
movsb
.nb:
shr ecx, 1
jnc .nw
movsw
.nw:
test ecx, ecx
jz .nd
rep movsd
.nd:
pop ecx
 
; unlock mutex
pusha
lea ecx, [eax + RING_BUFFER.mutex]
call mutex_unlock ; TODO: check what registers this function actually destroys
popa
 
ret
 
;-----------------------------------------------------------------;
; ;
; socket_ring_read: Read from ring buffer ;
; ;
; IN: eax = ring struct ptr ;
; ecx = bytes to read ;
; edx = offset ;
; edi = ptr to buffer start ;
; ;
; OUT: eax = unchanged ;
; ecx = number of bytes read (0 on error) ;
; edx = destroyed ;
; esi = destroyed ;
; edi = ptr to buffer end ;
; ;
;-----------------------------------------------------------------;
align 4
socket_ring_read:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: ringbuff=%x ptr=%x size=%u offset=%x\n", eax, edi, ecx, edx
 
pusha
lea ecx, [eax + RING_BUFFER.mutex]
call mutex_lock ; TODO: check what registers this function actually destroys
popa
 
mov esi, [eax + RING_BUFFER.read_ptr]
add esi, edx ; esi = start_ptr + offset
 
neg edx
add edx, [eax + RING_BUFFER.size] ; edx = snd.size - offset
jle .no_data_at_all
 
pusha
lea ecx, [eax + RING_BUFFER.mutex]
call mutex_unlock ; TODO: check what registers this function actually destroys
popa
 
cmp ecx, edx
ja .less_data
 
.copy:
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_ring_read: %u bytes from %x to %x\n", ecx, esi, edi
push ecx
shr ecx, 1
jnc .nb
movsb
.nb:
shr ecx, 1
jnc .nw
movsw
.nw:
test ecx, ecx
jz .nd
rep movsd
.nd:
pop ecx
ret
 
.no_data_at_all:
pusha
lea ecx, [eax + RING_BUFFER.mutex]
call mutex_unlock ; TODO: check what registers this function actually destroys
popa
 
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_ring_read: no data at all!\n"
xor ecx, ecx
ret
 
.less_data:
mov ecx, edx
jmp .copy
 
 
;-----------------------------------------------------------------;
; ;
; socket_ring_free: Free data from a ringbuffer. ;
; ;
; IN: eax = ptr to ring struct ;
; ecx = data size ;
; ;
; OUT: ecx = number of freed bytes ;
; ;
;-----------------------------------------------------------------;
align 4
socket_ring_free:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_ring_free: %u bytes from ring %x\n", ecx, eax
 
push eax ecx
lea ecx, [eax + RING_BUFFER.mutex]
call mutex_lock ; TODO: check what registers this function actually destroys
pop ecx eax
 
sub [eax + RING_BUFFER.size], ecx
jb .error
add [eax + RING_BUFFER.read_ptr], ecx
 
mov edx, [eax + RING_BUFFER.end_ptr]
cmp [eax + RING_BUFFER.read_ptr], edx
jb @f
sub [eax + RING_BUFFER.read_ptr], SOCKET_BUFFER_SIZE
@@:
 
push eax ecx
lea ecx, [eax + RING_BUFFER.mutex] ; TODO: check what registers this function actually destroys
call mutex_unlock
pop ecx eax
 
ret
 
.error: ; we could free all available bytes, but that would be stupid, i guess..
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_ring_free: buffer=%x error!\n", eax
add [eax + RING_BUFFER.size], ecx
 
push eax
lea ecx, [eax + RING_BUFFER.mutex]
call mutex_unlock ; TODO: check what registers this function actually destroys
pop eax
 
xor ecx, ecx
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_block: Suspend the thread attached to a socket. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: eax = unchanged ;
; ;
;-----------------------------------------------------------------;
align 4
socket_block:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_block: %x\n", eax
 
push eax
 
pushf
cli
; Set the 'socket is blocked' flag
or [eax + SOCKET.state], SS_BLOCKED
 
; Suspend the thread
push edx
mov edx, [TASK_BASE]
mov [edx + TASKDATA.state], TSTATE_RUN_SUSPENDED
 
; Remember the thread ID so we can wake it up again
mov edx, [edx + TASKDATA.pid]
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_block: suspending thread: %u\n", edx
mov [eax + SOCKET.TID], edx
pop edx
popf
 
call change_task
pop eax
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_block: continuing\n"
 
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_notify: Wake up socket owner thread. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: eax = unchanged ;
; ;
;-----------------------------------------------------------------;
align 4
socket_notify:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_notify: %x\n", eax
 
call socket_check
jz .error
 
; Find the associated thread's TASK_DATA
push ebx ecx esi
mov ebx, [eax + SOCKET.TID]
test ebx, ebx
jz .error2
xor ecx, ecx
inc ecx
mov esi, TASK_DATA
.next:
cmp [esi + TASKDATA.pid], ebx
je .found
inc ecx
add esi, sizeof.TASKDATA
cmp ecx, [thread_count]
jbe .next
 
.error2:
; PID not found, TODO: close socket!
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_notify: error finding thread 0x%x !\n", ebx
pop esi ecx ebx
ret
 
.error:
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_notify: invalid socket ptr: 0x%x !\n", eax
ret
 
.found:
test [eax + SOCKET.state], SS_BLOCKED
jnz .un_block
 
; Socket and thread exists and socket is of non blocking type.
; We'll try to flag an event to the thread.
shl ecx, 8
or [SLOT_BASE + ecx + APPDATA.occurred_events], EVENT_NETWORK
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_notify: poking thread %u!\n", ebx
pop esi ecx ebx
ret
 
 
.un_block:
; Socket and thread exists and socket is of blocking type
; We'll try to unblock it.
and [eax + SOCKET.state], not SS_BLOCKED ; Clear the 'socket is blocked' flag
mov [esi + TASKDATA.state], TSTATE_RUNNING ; Run the thread
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_notify: Unblocked socket!\n"
pop esi ecx ebx
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_alloc: Allocate memory for socket and put new socket ;
; into the list. Newly created socket is initialized with calling ;
; PID and given a socket number. ;
; ;
; IN: / ;
; ;
; OUT: eax = socket ptr on success ;
; eax = 0 on error ;
; edi = socket number on success ;
; ;
;-----------------------------------------------------------------;
align 4
socket_alloc:
 
push ebx
 
stdcall kernel_alloc, SOCKET_STRUCT_SIZE
or eax, eax
jz .nomem
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: ptr=%x\n", eax
 
; zero-initialize allocated memory
push eax
mov edi, eax
mov ecx, SOCKET_STRUCT_SIZE / 4
xor eax, eax
rep stosd
pop eax
 
; set send-and receive procedures to return -1
mov [eax + SOCKET.snd_proc], .not_yet
mov [eax + SOCKET.rcv_proc], .not_yet
 
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
; find first free socket number and use it
mov edi, [last_socket_num]
.next_socket_number:
inc edi
jz .next_socket_number ; avoid socket nr 0
cmp edi, -1
je .next_socket_number ; avoid socket nr -1
mov ebx, net_sockets
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
test ebx, ebx
jz .last_socket
 
cmp [ebx + SOCKET.Number], edi
jne .next_socket
jmp .next_socket_number
 
.last_socket:
mov [last_socket_num], edi
mov [eax + SOCKET.Number], edi
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_alloc: number=%u\n", edi
 
; Fill in PID
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
mov [eax + SOCKET.PID], ebx
mov [eax + SOCKET.TID], ebx ; currently TID = PID in kolibrios :(
 
; init mutex
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_init
popa
 
; add socket to the list by re-arranging some pointers
mov ebx, [net_sockets + SOCKET.NextPtr]
 
mov [eax + SOCKET.PrevPtr], net_sockets
mov [eax + SOCKET.NextPtr], ebx
 
test ebx, ebx
jz @f
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_lock
popa
 
mov [ebx + SOCKET.PrevPtr], eax
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
@@:
 
mov [net_sockets + SOCKET.NextPtr], eax
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
pop ebx
 
ret
 
.nomem:
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_alloc: Out of memory!\n"
pop ebx
ret
 
.not_yet:
mov dword[esp+20], ENOTCONN
mov dword[esp+32], -1
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_free: Free socket data memory and remove socket from ;
; the list. Caller should lock and unlock socket_mutex. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_free:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_free: %x\n", eax
 
call socket_check
jz .error
 
push ebx
 
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
popa
 
cmp [eax + SOCKET.Type], SOCK_STREAM
jne .no_stream
 
mov ebx, eax
cmp [eax + STREAM_SOCKET.rcv.start_ptr], 0
je @f
stdcall free_kernel_space, [eax + STREAM_SOCKET.rcv.start_ptr]
@@:
cmp [ebx + STREAM_SOCKET.snd.start_ptr], 0
je @f
stdcall free_kernel_space, [ebx + STREAM_SOCKET.snd.start_ptr]
@@:
mov eax, ebx
.no_stream:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_free: freeing socket %x\n", eax
push eax ; this will be passed to kernel_free
mov ebx, [eax + SOCKET.NextPtr]
mov eax, [eax + SOCKET.PrevPtr]
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_free: linking socket %x to socket %x\n", eax, ebx
 
test eax, eax
jz @f
mov [eax + SOCKET.NextPtr], ebx
@@:
 
test ebx, ebx
jz @f
mov [ebx + SOCKET.PrevPtr], eax
@@:
 
call kernel_free
pop ebx
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_free: success!\n"
 
.error:
ret
 
.error1:
pop ebx
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_free: error!\n"
DEBUGF DEBUG_NETWORK_ERROR, "socket ptr=0x%x caller=0x%x\n", eax, [esp]
ret
 
;-----------------------------------------------------------------;
; ;
; socket_fork: Create a child socket. ;
; ;
; IN: ebx = socket number ;
; ;
; OUT: eax = child socket number on success ;
; eax = 0 on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_fork:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_fork: %x\n", ebx
 
; Exit if backlog queue is full
mov eax, [ebx + SOCKET_QUEUE_LOCATION + queue.size]
cmp ax, [ebx + SOCKET.backlog]
jae .fail
 
; Allocate new socket
push ebx
call socket_alloc
pop ebx
test eax, eax
jz .fail
 
push eax
mov esi, esp
add_to_queue (ebx + SOCKET_QUEUE_LOCATION), MAX_backlog, 4, .fail2
pop eax
 
; Copy structure from current socket to new
; We start at PID to preserve the socket num, 2 pointers and mutex
; TID will be filled in later
lea esi, [ebx + SOCKET.PID]
lea edi, [eax + SOCKET.PID]
mov ecx, (SOCKET_QUEUE_LOCATION - SOCKET.PID + 3)/4
rep movsd
 
and [eax + SOCKET.options], not SO_ACCEPTCON
 
; Notify owner of parent socket
push eax
mov eax, ebx
call socket_notify
pop eax
 
ret
 
.fail2:
add esp, 4+4+4
.fail:
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_fork: failed\n"
xor eax, eax
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_num_to_ptr: Get socket structure address by its number. ;
; ;
; IN: ecx = socket number ;
; ;
; OUT: eax = socket ptr ;
; eax = 0 on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_num_to_ptr:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_num_to_ptr: num=%u ", ecx
 
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
mov eax, net_sockets
.next_socket:
mov eax, [eax + SOCKET.NextPtr]
test eax, eax
jz .error
cmp [eax + SOCKET.Number], ecx
jne .next_socket
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ptr=%x\n", eax
ret
 
.error:
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: socket %u not found!\n", eax
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_num_to_ptr: caller = 0x%x\n", [esp]
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_ptr_to_num: Get socket number by its address. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: eax = socket number ;
; eax = 0 on error ;
; ZF = set on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_ptr_to_num:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_ptr_to_num: ptr=%x ", eax
 
call socket_check
jz .error
 
mov eax, [eax + SOCKET.Number]
 
DEBUGF DEBUG_NETWORK_VERBOSE, "num=%u\n", eax
ret
 
.error:
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_ptr_to_num: not found\n", eax
ret
 
 
;-----------------------------------------------------------------;
; ;
; socket_check: Checks if the given ptr is really a socket ptr. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: eax = 0 on error ;
; ZF = set on error ;
; ;
;-----------------------------------------------------------------;
align 4
socket_check:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_check: %x\n", eax
 
test eax, eax
jz .error
push ebx
mov ebx, net_sockets
 
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .done
cmp ebx, eax
jnz .next_socket
 
.done:
mov eax, ebx
test eax, eax
pop ebx
ret
 
.error:
DEBUGF DEBUG_NETWORK_ERROR, "SOCKET_check: called with argument 0\n"
DEBUGF DEBUG_NETWORK_ERROR, "stack: 0x%x, 0x%x, 0x%x\n", [esp], [esp+4], [esp+8]
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_check_owner: Check if the caller app owns the socket. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: ZF = true/false ;
; ;
;-----------------------------------------------------------------;
align 4
socket_check_owner:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_check_owner: %x\n", eax
 
push ebx
mov ebx, [TASK_BASE]
mov ebx, [ebx + TASKDATA.pid]
cmp [eax + SOCKET.PID], ebx
pop ebx
 
ret
 
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_process_end: Kernel calls this function when a certain ;
; process ends. This function will check if the process had any ;
; open sockets and update them accordingly (clean up). ;
; ;
; IN: edx = pid ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_process_end:
 
ret ; FIXME
 
cmp [net_sockets + SOCKET.NextPtr], 0 ; Are there any active sockets at all?
je .quickret ; nope, exit immediately
 
; TODO: run the following code in another thread, to avoid deadlock
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: %x\n", edx
 
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
push ebx
mov ebx, net_sockets
 
.next_socket:
mov ebx, [ebx + SOCKET.NextPtr]
.next_socket_test:
test ebx, ebx
jz .done
 
cmp [ebx + SOCKET.PID], edx
jne .next_socket
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_process_end: killing socket %x\n", ebx
 
mov [ebx + SOCKET.PID], 0
mov eax, ebx
mov ebx, [ebx + SOCKET.NextPtr]
 
pusha
cmp [eax + SOCKET.Domain], AF_INET4
jne .free
 
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
jne .free
 
call tcp_disconnect
jmp .closed
 
.free:
call socket_free
 
.closed:
popa
jmp .next_socket_test
 
.done:
pop ebx
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
.quickret:
ret
 
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_is_connecting: Update socket state. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_is_connecting:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_is_connecting: %x\n", eax
 
and [eax + SOCKET.state], not (SS_ISCONNECTED + SS_ISDISCONNECTING + SS_ISCONFIRMING)
or [eax + SOCKET.state], SS_ISCONNECTING
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_is_connected: Update socket state. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_is_connected:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_is_connected: %x\n", eax
 
and [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISDISCONNECTING + SS_ISCONFIRMING)
or [eax + SOCKET.state], SS_ISCONNECTED
jmp socket_notify
 
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_is_disconnecting: Update socket state. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_is_disconnecting:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnecting: %x\n", eax
 
and [eax + SOCKET.state], not (SS_ISCONNECTING)
or [eax + SOCKET.state], SS_ISDISCONNECTING + SS_CANTRCVMORE + SS_CANTSENDMORE
jmp socket_notify
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_is_disconnected: Update socket state. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_is_disconnected:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_is_disconnected: %x\n", eax
 
and [eax + SOCKET.state], not (SS_ISCONNECTING + SS_ISCONNECTED + SS_ISDISCONNECTING)
or [eax + SOCKET.state], SS_CANTRCVMORE + SS_CANTSENDMORE
jmp socket_notify
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_cant_recv_more: Update socket state. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_cant_recv_more:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_cant_recv_more: %x\n", eax
 
or [eax + SOCKET.state], SS_CANTRCVMORE
jmp socket_notify
 
 
 
;-----------------------------------------------------------------;
; ;
; socket_cant_send_more: Update socket state. ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
socket_cant_send_more:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "SOCKET_cant_send_more: %x\n", eax
 
or [eax + SOCKET.state], SS_CANTSENDMORE
mov [eax + SOCKET.snd_proc], .notconn
jmp socket_notify
 
.notconn:
mov dword[esp+20], ENOTCONN
mov dword[esp+32], -1
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/loopback.inc
0,0 → 1,176
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; loopback.inc ;;
;; ;;
;; LoopBack device for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
iglobal
align 4
 
LOOPBACK_DEVICE:
 
.device_type dd NET_DEVICE_LOOPBACK
.mtu dd 4096
.name dd .namestr
 
.unload dd loop_dummy
.reset dd loop_dummy
.transmit dd loop_input
 
.bytes_tx dq 0
.bytes_rx dq 0
.packets_tx dd 0
.packets_rx dd 0
 
.link_state dd -1
.hwacc dd NET_HWACC_TCP_IPv4_IN + NET_HWACC_TCP_IPv4_OUT
 
.namestr db 'loopback', 0
 
endg
 
 
macro loop_init {
local .fail
 
mov ebx, LOOPBACK_DEVICE
call net_add_device
 
cmp eax, -1
je .fail
 
mov [IPv4_address], 127 + 1 shl 24
mov [IPv4_subnet], 255
mov [IPv4_broadcast], 0xffffff00 + 127
 
.fail:
}
 
;-----------------------------------------------------------------;
; ;
; loop_dummy ;
; ;
; IN: / ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
loop_dummy:
ret
 
;-----------------------------------------------------------------;
; ;
; loop_input ;
; ;
; IN: [esp+4] = Pointer to buffer ;
; ;
; OUT: eax = 0 on success, errorcode otherwise ;
; ;
;-----------------------------------------------------------------;
align 4
loop_input:
 
mov eax, [esp+4]
 
; Update stats
inc [LOOPBACK_DEVICE.packets_tx]
inc [LOOPBACK_DEVICE.packets_rx]
 
mov ecx, [eax + NET_BUFF.length]
add dword[LOOPBACK_DEVICE.bytes_rx], ecx
adc dword[LOOPBACK_DEVICE.bytes_rx + 4], 0
add dword[LOOPBACK_DEVICE.bytes_tx], ecx
adc dword[LOOPBACK_DEVICE.bytes_tx + 4], 0
 
DEBUGF DEBUG_NETWORK_VERBOSE, "LOOP_input: ptr=%x size=%u\n", eax, ecx
 
; Reverse buffptr and returnaddr on stack
pop edx edi
push edx .done edi
 
; Set registers for protocol handlers
lea edx, [eax + NET_BUFF.data]
mov ebx, [eax + NET_BUFF.device]
mov eax, [eax + NET_BUFF.type]
 
; Place protocol handlers here
cmp eax, AF_INET4
je ipv4_input
 
DEBUGF DEBUG_NETWORK_VERBOSE, "LOOP_input: Unknown packet type=%x\n", eax
 
.dump:
DEBUGF DEBUG_NETWORK_VERBOSE, "LOOP_input: dumping\n"
call net_buff_free
 
or eax, -1
ret
 
.done:
xor eax, eax
ret
 
 
;-----------------------------------------------------------------;
; ;
; loop_output ;
; ;
; IN: ecx = packet size ;
; edi = address family ;
; ;
; OUT: eax = start of net frame / 0 on error ;
; ebx = to device structure ;
; ecx = unchanged (packet size of embedded data) ;
; edi = start of payload ;
; ;
;-----------------------------------------------------------------;
align 4
loop_output:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "LOOP_output\n"
 
cmp ecx, [LOOPBACK_DEVICE.mtu]
ja .too_large
 
push ecx edi
add ecx, NET_BUFF.data
stdcall net_buff_alloc, ecx
test eax, eax
jz .out_of_ram
 
pop edi
mov [eax + NET_BUFF.type], edi
mov ebx, LOOPBACK_DEVICE
mov [eax + NET_BUFF.device], ebx
pop ecx
mov [eax + NET_BUFF.length], ecx
lea edi, [eax + NET_BUFF.data]
 
DEBUGF DEBUG_NETWORK_VERBOSE, "LOOP_output: ptr=%x size=%u\n", eax, ecx
ret
 
.too_large:
DEBUGF DEBUG_NETWORK_ERROR, "LOOP_output: packet is too large\n"
xor eax, eax
ret
 
.out_of_ram:
DEBUGF DEBUG_NETWORK_ERROR, "LOOP_output: out of memory\n"
add esp, 4+4
xor eax, eax
ret
 
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/tcp_output.inc
0,0 → 1,754
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; Based on the code of 4.4BSD ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
TCP_BIT_SENDALOT = 1 shl 0
 
;-----------------------------------------------------------------;
; ;
; tcp_output ;
; ;
; IN: eax = socket pointer ;
; ;
; OUT: eax = 0 on success/errorcode ;
; ;
;-----------------------------------------------------------------;
align 4
proc tcp_output
 
locals
temp_bits db ?
rcv_window dd ?
endl
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: socket=%x state=%u\n", eax, [eax + TCP_SOCKET.t_state]
 
push eax
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
pop eax
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: socket locked\n"
 
; We'll detect the length of the data to be transmitted, and flags to be used
; If there is some data, or any critical controls to send (SYN / RST), then transmit
; Otherwise, investigate further
 
mov ebx, [eax + TCP_SOCKET.SND_MAX]
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
jbe .not_idle
 
mov ebx, [eax + TCP_SOCKET.t_idle]
cmp ebx, [eax + TCP_SOCKET.t_rxtcur]
jbe .not_idle
 
; We have been idle for a while and no ACKS are expected to clock out any data we send..
; Slow start to get ack "clock" running again.
 
mov ebx, [eax + TCP_SOCKET.t_maxseg]
mov [eax + TCP_SOCKET.SND_CWND], ebx
 
.not_idle:
.again:
mov [temp_bits], 0
 
; Calculate offset
 
mov ebx, [eax + TCP_SOCKET.SND_NXT]
sub ebx, [eax + TCP_SOCKET.SND_UNA]
 
; Determine window
 
mov ecx, [eax + TCP_SOCKET.SND_WND]
cmp ecx, [eax + TCP_SOCKET.SND_CWND]
jb @f
mov ecx, [eax + TCP_SOCKET.SND_CWND]
@@:
 
; get flags in dl
 
call tcp_outflags
 
;------------------------
; data being forced out ?
 
; If in persist timeout with window of 0, send 1 byte.
; Otherwise, if window is small but nonzero, and timer expired,
; we will send what we can and go to transmit state
 
test [eax + TCP_SOCKET.t_flags], TF_FORCE
jz .no_force
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: forcing data out\n"
 
test ecx, ecx
jnz .no_zero_window
 
cmp ebx, [eax + STREAM_SOCKET.snd.size]
jae @f
and dl, not (TH_FIN)
@@:
 
inc ecx
jmp .no_force
 
.no_zero_window:
and [eax + TCP_SOCKET.timer_flags], not timer_flag_persist
mov [eax + TCP_SOCKET.t_rxtshift], 0
 
.no_force:
 
;--------------------------------
; Calculate how much data to send
 
mov esi, [eax + STREAM_SOCKET.snd.size]
cmp esi, ecx
jb @f
mov esi, ecx
@@:
sub esi, ebx
 
;------------------------
; check for window shrink
 
; If FIN has been sent, but not ACKed, but we havent been called to retransmit, esi will be -1
; Otherwise, window shrank after we sent into it.
 
jge .not_persist
 
; enter persist state
 
xor esi, esi
 
; If window shrank to 0
 
test ecx, ecx
jnz @f
 
; cancel pending retransmit
 
and [eax + TCP_SOCKET.timer_flags], not timer_flag_retransmission
 
; pull SND_NXT back to (closed) window, We will enter persist state below.
 
push [eax + TCP_SOCKET.SND_UNA]
pop [eax + TCP_SOCKET.SND_NXT]
@@:
 
; If window didn't close completely, just wait for an ACK
 
.not_persist:
 
;---------------------------
; Send one segment at a time
 
cmp esi, [eax + TCP_SOCKET.t_maxseg]
jbe @f
mov esi, [eax + TCP_SOCKET.t_maxseg]
or [temp_bits], TCP_BIT_SENDALOT
@@:
 
;--------------------------------------------
; Turn of FIN flag if send buffer not emptied
 
mov edi, [eax + TCP_SOCKET.SND_NXT]
add edi, esi
sub edi, [eax + TCP_SOCKET.SND_UNA]
cmp edi, [eax + STREAM_SOCKET.snd.size]
jae @f
and dl, not (TH_FIN)
@@:
 
;-------------------------------
; calculate window advertisement
 
xor ecx, ecx
test [eax + SOCKET.state], SS_CANTRCVMORE
jnz @f
mov ecx, SOCKET_BUFFER_SIZE
sub ecx, [eax + STREAM_SOCKET.rcv.size]
@@:
 
;------------------------------
; Sender silly window avoidance
 
test esi, esi
jz .len_zero
 
cmp esi, [eax + TCP_SOCKET.t_maxseg]
je .send
 
add ebx, esi ; offset + length
cmp ebx, [eax + STREAM_SOCKET.snd.size]
jb @f
 
test [eax + TCP_SOCKET.t_flags], TF_NODELAY
jnz .send
 
mov ebx, [eax + TCP_SOCKET.SND_MAX]
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
je .send
@@:
 
test [eax + TCP_SOCKET.t_flags], TF_FORCE
jnz .send
 
mov ebx, [eax + TCP_SOCKET.max_sndwnd]
shr ebx, 1
cmp esi, ebx
jae .send
 
mov ebx, [eax + TCP_SOCKET.SND_NXT]
cmp ebx, [eax + TCP_SOCKET.SND_MAX]
jb .send
 
.len_zero:
 
;----------------------------------------
; Check if a window update should be sent
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: window=%d\n", ecx
 
; Compare available window to amount of window known to peer (as advertised window less next expected input)
; If the difference is at least two max size segments, or at least 50% of the maximum possible window,
; Then we want to send a window update to the peer.
 
test ecx, ecx
jz .no_window
 
push ecx
mov cl, [eax + TCP_SOCKET.RCV_SCALE]
mov ebx, TCP_max_win
shl ebx, cl
pop ecx
sub ebx, [eax + TCP_SOCKET.RCV_ADV]
add ebx, [eax + TCP_SOCKET.RCV_NXT]
 
cmp ebx, ecx
jl @f
mov ebx, ecx
@@:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: we can increase window by %d bytes\n", ebx
 
mov edi, [eax + TCP_SOCKET.t_maxseg]
shl edi, 1
cmp ebx, edi
jae .send
 
cmp ebx, SOCKET_BUFFER_SIZE/2
jae .send
 
.no_window:
 
;--------------------------
; Should a segment be sent?
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: Should a segment be sent?\n"
 
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW ; we need to ACK
jnz .send
 
test dl, TH_SYN + TH_RST ; we need to send a SYN or RST
jnz .send
 
mov ebx, [eax + TCP_SOCKET.SND_UP] ; when urgent pointer is beyond start of send bufer
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
ja .send
 
; Do we need to send a FIN according to our state?
 
test dl, TH_FIN
jz .enter_persist ; no reason to send, enter persist state
 
; Do so if we didnt do it already
 
test [eax + TCP_SOCKET.t_flags], TF_SENTFIN
jz .send
 
; Or when we need to retransmit the FIN
 
mov ebx, [eax + TCP_SOCKET.SND_NXT]
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
je .send
 
;--------------------
; Enter persist state
 
.enter_persist:
 
cmp [eax + STREAM_SOCKET.snd.size], 0 ; Data ready to send?
je @f
test [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission or timer_flag_persist
jnz @f
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: Entering persist state\n"
 
mov [eax + TCP_SOCKET.t_rxtshift], 0
call tcp_set_persist
@@:
 
;----------------------------
; No reason to send a segment
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_output: No reason to send a segment\n"
 
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
popa
 
xor eax, eax
ret
 
 
;-----------------------------------------------
;
; Send a segment
;
; eax = socket pointer
; esi = data len
; dl = flags
;
;-----------------------------------------------
.send:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: socket=%x length=%u flags=%x\n", eax, esi, dl
 
push eax ; save socket ptr
push esi ; and data length too
mov edi, sizeof.TCP_header ; edi will contain headersize
 
;------------------------------------
; Send options with first SYN segment
 
test dl, TH_SYN
jz .options_done
 
push [eax + TCP_SOCKET.ISS]
pop [eax + TCP_SOCKET.SND_NXT]
 
test [eax + TCP_SOCKET.t_flags], TF_NOOPT
jnz .options_done
 
mov ecx, 1460 ;;;; FIXME: use routing blablabla to determine MSS
or ecx, TCP_OPT_MAXSEG shl 24 + 4 shl 16
bswap ecx
push ecx
add di, 4
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: added maxseg option\n"
 
test [eax + TCP_SOCKET.t_flags], TF_REQ_SCALE
jz .no_scale
 
test dl, TH_ACK
jz .scale_opt
 
test [eax + TCP_SOCKET.t_flags], TF_RCVD_SCALE
jz .no_scale
 
.scale_opt:
mov cl, [eax + TCP_SOCKET.request_r_scale]
mov ch, TCP_OPT_NOP
pushw cx
pushw TCP_OPT_WINDOW + 3 shl 8
add di, 4
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: added scale option\n"
 
.no_scale:
.no_syn:
 
;------------------------------------
; Make the timestamp option if needed
 
test [eax + TCP_SOCKET.t_flags], TF_REQ_TSTMP
jz .no_timestamp
 
test dl, TH_RST
jnz .no_timestamp
 
test dl, TH_ACK
jz .timestamp
 
test [eax + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
jz .no_timestamp
 
.timestamp:
pushd 0
pushd [timer_ticks]
pushd TCP_OPT_NOP + TCP_OPT_NOP shl 8 + TCP_OPT_TIMESTAMP shl 16 + 10 shl 24
add di, 12
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: added timestamp\n"
 
.no_timestamp:
 
; <Add additional options here>
 
.options_done:
 
; eax = socket ptr
; edx = flags
; edi = header size
; esi = data len
 
;---------------------------------------------
; check if we dont exceed the max segment size
 
add esi, edi ; total TCP segment size
cmp esi, [eax + TCP_SOCKET.t_maxseg]
jbe .no_overflow
 
mov esi, [eax + TCP_SOCKET.t_maxseg]
or [temp_bits], TCP_BIT_SENDALOT
.no_overflow:
 
; Update stats
 
test esi, esi
jz .zero_data
 
test [eax + TCP_SOCKET.t_flags], TF_FORCE
jz @f
cmp esi, 1
jne @f
inc [TCPS_sndprobe]
jmp .eos
@@:
 
mov ebx, [eax + TCP_SOCKET.SND_NXT]
cmp ebx, [eax + TCP_SOCKET.SND_MAX]
jae @f
inc [TCPS_sndrexmitpack]
add [TCPS_sndrexmitbyte], esi
jmp .eos
@@:
inc [TCPS_sndpack]
add [TCPS_sndbyte], esi
jmp .eos
 
.zero_data:
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW
jz @f
inc [TCPS_sndacks]
jmp .eos
@@:
test dl, TH_SYN + TH_FIN + TH_RST
jz @f
inc [TCPS_sndctrl]
jmp .eos
@@:
mov ebx, [eax + TCP_SOCKET.SND_UP]
cmp ebx, [eax + TCP_SOCKET.SND_UNA]
jb @f
inc [TCPS_sndurg]
jmp .eos
@@:
inc [TCPS_sndwinup]
 
.eos:
 
;---------------------------------------------------
; Dont increase sequence number when resending a FIN
 
test dl, TH_FIN
jz .no_fin_retransmit
 
test [eax + TCP_SOCKET.t_flags], TF_SENTFIN
jz .no_fin_retransmit
 
mov ebx, [eax + TCP_SOCKET.SND_NXT]
cmp ebx, [eax + TCP_SOCKET.SND_MAX]
jne .no_fin_retransmit
 
dec [eax + TCP_SOCKET.SND_NXT]
 
.no_fin_retransmit:
 
;----------------------------------------------------
; Calculate the receive window.
; Dont shrink window, but avoid silly window syndrome
 
xor ebx, ebx
test [eax + SOCKET.state], SS_CANTRCVMORE
jnz @f
mov ebx, SOCKET_BUFFER_SIZE
sub ebx, [eax + STREAM_SOCKET.rcv.size]
 
cmp ebx, SOCKET_BUFFER_SIZE/4
jge @f
cmp ebx, [eax + TCP_SOCKET.t_maxseg]
jge @f
xor ebx, ebx
@@:
 
 
mov cl, [eax + TCP_SOCKET.RCV_SCALE]
push eax
mov eax, TCP_max_win
shl eax, cl
cmp ebx, eax
jle @f
mov ebx, eax
@@:
pop eax
 
 
mov ecx, [eax + TCP_SOCKET.RCV_ADV]
sub ecx, [eax + TCP_SOCKET.RCV_NXT]
cmp ebx, ecx
jg @f
mov ebx, ecx
@@:
 
;; TODO URGENT POINTER
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: window=%u\n", ebx
mov [rcv_window], ebx
 
mov cl, [eax + TCP_SOCKET.RCV_SCALE]
shr ebx, cl
xchg bl, bh
 
;-----------------------------------------------------------------
; Start by pushing all TCP header values in reverse order on stack
; (essentially, creating the tcp header on the stack!)
 
pushw 0 ; UrgentPointer
pushw 0 ; Checksum
pushw bx ; Window
shl edi, 2 ; DataOffset
shl dx, 8
or dx, di ; Flags
pushw dx
shr edi, 2 ; DataOffset
 
push [eax + TCP_SOCKET.RCV_NXT] ; AckNumber
ntohd [esp]
 
push [eax + TCP_SOCKET.SND_NXT] ; SequenceNumber
ntohd [esp]
 
push [eax + TCP_SOCKET.RemotePort] ; DestinationPort
push [eax + TCP_SOCKET.LocalPort] ; SourcePort
 
push edi ; header size
 
;---------------------
; Create the IP packet
 
mov ecx, esi
mov ebx, [eax + IP_SOCKET.device]
mov edx, [eax + IP_SOCKET.LocalIP] ; source ip
mov edi, [eax + IP_SOCKET.RemoteIP] ; dest ip
mov al, [eax + IP_SOCKET.ttl]
mov ah, IP_PROTO_TCP
call ipv4_output
jz .ip_error
 
;------------------------------------------
; Move TCP header from stack to TCP segment
 
push ecx
mov ecx, [esp + 4]
lea esi, [esp + 8]
shr ecx, 2 ; count is in bytes, we will work with dwords
rep movsd
pop ecx ; full TCP packet size
 
pop esi ; headersize
add esp, esi ; remove it from stack
 
push eax ; packet ptr for send proc
 
mov edx, edi ; begin of data
sub edx, esi ; begin of packet (edi = begin of data)
push ecx
sub ecx, esi ; data size
 
;--------------
; Copy the data
 
; eax = ptr to ring struct
; ecx = buffer size
; edi = ptr to buffer
 
mov eax, [esp + 12] ; get socket ptr
 
push edx
push [eax + TCP_SOCKET.SND_NXT] ; we'll need this for timing the transmission
test ecx, ecx
jz .nodata
mov edx, [eax + TCP_SOCKET.SND_NXT]
add [eax + TCP_SOCKET.SND_NXT], ecx ; update sequence number
sub edx, [eax + TCP_SOCKET.SND_UNA] ; offset
add eax, STREAM_SOCKET.snd
call socket_ring_read
.nodata:
pop edi
pop esi ; begin of data
pop ecx ; full packet size
mov eax, [esp + 8] ; socket ptr
 
;----------------------------
; initialize retransmit timer
 
;TODO: check t_force and persist
 
test [esi + TCP_header.Flags], TH_SYN + TH_FIN ; syn and fin take a sequence number
jz @f
inc [eax + TCP_SOCKET.SND_NXT]
test [esi + TCP_header.Flags], TH_FIN
jz @f
or [eax + TCP_SOCKET.t_flags], TF_SENTFIN ; if we sent a fin, set the sentfin flag
@@:
 
mov edx, [eax + TCP_SOCKET.SND_NXT]
cmp edx, [eax + TCP_SOCKET.SND_MAX] ; is this a retransmission?
jbe @f
mov [eax + TCP_SOCKET.SND_MAX], edx ; [eax + TCP_SOCKET.SND_NXT] from before we updated it
 
cmp [eax + TCP_SOCKET.t_rtt], 0 ; are we currently timing anything?
je @f
mov [eax + TCP_SOCKET.t_rtt], 1 ; nope, start transmission timer
mov [eax + TCP_SOCKET.t_rtseq], edi
inc [TCPS_segstimed]
@@:
 
; set retransmission timer if not already set, and not doing an ACK or keepalive probe
 
test [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
jnz .retransmit_set
 
cmp edx, [eax + TCP_SOCKET.SND_UNA] ; edx is still [eax + TCP_SOCKET.SND_NXT]
je .retransmit_set
 
mov edx, [eax + TCP_SOCKET.t_rxtcur]
mov [eax + TCP_SOCKET.timer_retransmission], edx
or [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
 
test [eax + TCP_SOCKET.timer_flags], timer_flag_persist
jz .retransmit_set
and [eax + TCP_SOCKET.timer_flags], not timer_flag_persist
mov [eax + TCP_SOCKET.t_rxtshift], 0
.retransmit_set:
 
;--------------------
; Create the checksum
 
xor dx, dx
test [ebx + NET_DEVICE.hwacc], NET_HWACC_TCP_IPv4_OUT
jnz .checksum_ok
 
tcp_checksum (eax + IP_SOCKET.LocalIP), (eax + IP_SOCKET.RemoteIP)
 
.checksum_ok:
mov [esi + TCP_header.Checksum], dx
 
;----------------
; Send the packet
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: Sending with device %x\n", ebx
call [ebx + NET_DEVICE.transmit]
jnz .send_error
 
;---------------
; Ok, data sent!
 
pop ecx
pop eax
 
call net_ptr_to_num4
inc [TCP_segments_tx + edi]
inc [TCPS_sndtotal]
 
; update advertised receive window
 
mov ecx, [rcv_window]
test ecx, ecx
jz @f
add ecx, [eax + TCP_SOCKET.RCV_NXT]
cmp ecx, [eax + TCP_SOCKET.RCV_ADV]
jbe @f
mov [eax + TCP_SOCKET.RCV_ADV], ecx
@@:
 
; update last ack sent
 
push [eax + TCP_SOCKET.RCV_NXT]
pop [eax + TCP_SOCKET.last_ack_sent]
 
; clear the ACK flags
 
and [eax + TCP_SOCKET.t_flags], not (TF_ACKNOW + TF_DELACK)
 
;--------------
; unlock socket
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: unlocking socket 0x%x\n", eax
 
push eax
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
pop eax
 
;-----------------------------
; Check if we need more output
 
test [temp_bits], TCP_BIT_SENDALOT
jnz tcp_output.again
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_send: success!\n"
 
xor eax, eax
ret
 
 
.ip_error:
pop ecx
add esp, ecx
add esp, 4
pop eax
 
mov [eax + TCP_SOCKET.timer_retransmission], TCP_time_re_min
or [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
 
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
 
DEBUGF DEBUG_NETWORK_ERROR, "TCP_send: IP error\n"
 
or eax, -1
ret
 
 
.send_error:
add esp, 4
pop eax
 
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
 
DEBUGF DEBUG_NETWORK_ERROR, "TCP_send: sending failed\n"
 
or eax, -2
ret
 
 
endp
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/tcp_subr.inc
0,0 → 1,619
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; Based on the code of 4.4BSD ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
align 4
iglobal
TCP_backoff db 0,1,2,3,4,5,6,6,6,6,6,6,6
endg
 
macro tcp_checksum IP1, IP2 {
 
;-------------
; Pseudoheader
 
; protocol type
mov edx, IP_PROTO_TCP
 
; source address
add dl, byte [IP1+1]
adc dh, byte [IP1+0]
adc dl, byte [IP1+3]
adc dh, byte [IP1+2]
 
; destination address
adc dl, byte [IP2+1]
adc dh, byte [IP2+0]
adc dl, byte [IP2+3]
adc dh, byte [IP2+2]
 
; size
adc dl, cl
adc dh, ch
 
adc edx, 0
 
;---------------------
; Real header and data
 
push esi
call checksum_1
call checksum_2
pop esi
 
} ; returns in dx only
 
 
 
 
macro tcp_sendseqinit ptr {
 
push edi ;;;; FIXME: i dont like this static use of edi
mov edi, [ptr + TCP_SOCKET.ISS]
mov [ptr + TCP_SOCKET.SND_UP], edi
mov [ptr + TCP_SOCKET.SND_MAX], edi
mov [ptr + TCP_SOCKET.SND_NXT], edi
mov [ptr + TCP_SOCKET.SND_UNA], edi
pop edi
 
}
 
 
 
macro tcp_rcvseqinit ptr {
 
push edi
mov edi, [ptr + TCP_SOCKET.IRS]
inc edi ; SYN ocupies a sequence number
mov [ptr + TCP_SOCKET.RCV_NXT], edi
mov [ptr + TCP_SOCKET.RCV_ADV], edi
pop edi
 
}
 
 
 
macro tcp_init_socket socket {
 
; new tcp control block
 
mov [socket + TCP_SOCKET.t_maxseg], TCP_mss_default
mov [socket + TCP_SOCKET.t_flags], TF_REQ_SCALE or TF_REQ_TSTMP
 
mov [socket + TCP_SOCKET.t_srtt], TCP_time_srtt_default
mov [socket + TCP_SOCKET.t_rttvar], TCP_time_rtt_default * 4
mov [socket + TCP_SOCKET.t_rttmin], TCP_time_re_min
;;; TODO: TCP_time_rangeset
 
mov [socket + TCP_SOCKET.SND_CWND], TCP_max_win shl TCP_max_winshift
mov [socket + TCP_SOCKET.SND_SSTHRESH], TCP_max_win shl TCP_max_winshift
 
mov [socket + TCP_SOCKET.RCV_SCALE], 0
mov [socket + TCP_SOCKET.SND_SCALE], 0
 
}
 
 
;-----------------------------------------------------------------;
; ;
; tcp_pull_out_of_band ;
; ;
; IN: eax = ? ;
; ebx = socket ptr ;
; edx = tcp packet ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_pull_out_of_band:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "tcp_pull_out_of_band\n"
 
;;;; 1282-1305
 
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; tcp_drop ;
; ;
; IN: eax = socket ptr ;
; ebx = error number ;
; ;
; OUT: eax = socket ptr ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_drop:
 
;;; TODO: check if error code is "Connection timed out' and handle accordingly
 
DEBUGF DEBUG_NETWORK_VERBOSE, "tcp_drop: %x\n", eax
 
cmp [eax + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
jb .no_syn_received
 
mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED
 
push eax
call tcp_output
pop eax
 
inc [TCPS_drops]
 
mov [eax + SOCKET.errorcode], ebx
jmp tcp_close
 
.no_syn_received:
inc [TCPS_conndrops]
 
mov [eax + SOCKET.errorcode], ebx
jmp tcp_close
 
 
;-----------------------------------------------------------------;
; ;
; tcp_disconnect ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: eax = socket ptr / 0 ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_disconnect:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_disconnect: %x\n", eax
 
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
jb tcp_close ; Connection not yet synchronised, just get rid of the socket
 
test [eax + SOCKET.options], SO_LINGER
jz .nolinger
 
; TODO: implement LINGER
; cmp [eax + SOCKET.so_linger], 0
; je TCP_drop
 
.nolinger:
call socket_is_disconnecting
 
push eax
add eax, STREAM_SOCKET.rcv
mov ecx, [eax + RING_BUFFER.size]
call socket_ring_free
pop eax
 
call tcp_usrclosed
 
test eax, eax
jz @f
push eax
call tcp_output
pop eax
@@:
ret
 
 
;-----------------------------------------------------------------;
; ;
; tcp_close ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_close:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_close: %x\n", eax
 
;;; TODO: update RTT and mean deviation
;;; TODO: update slow start threshold
 
call socket_is_disconnected
call socket_free
 
inc [TCPS_closed]
 
xor eax, eax
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; tcp_outflags ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: edx = flags ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_outflags:
 
mov edx, [eax + TCP_SOCKET.t_state]
movzx edx, byte[edx + .flaglist]
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_outflags: socket=%x flags=%x\n", eax, dl
 
ret
 
.flaglist:
db TH_RST + TH_ACK ; TCPS_CLOSED
db 0 ; TCPS_LISTEN
db TH_SYN ; TCPS_SYN_SENT
db TH_SYN + TH_ACK ; TCPS_SYN_RECEIVED
db TH_ACK ; TCPS_ESTABLISHED
db TH_ACK ; TCPS_CLOSE_WAIT
db TH_FIN + TH_ACK ; TCPS_FIN_WAIT_1
db TH_FIN + TH_ACK ; TCPS_CLOSING
db TH_FIN + TH_ACK ; TCPS_LAST_ACK
db TH_ACK ; TCPS_FIN_WAIT_2
db TH_ACK ; TCPS_TIME_WAIT
 
 
;-----------------------------------------------------------------;
; ;
; TCP_respond: Fast way to send an ACK/RST/keepalive segment. ;
; ;
; IN: ebx = socket ptr ;
; cl = flags ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_respond:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_respond_socket: socket=%x flags=%x\n", ebx, cl
 
;---------------------
; Create the IP packet
 
push cx ebx
mov edx, [ebx + IP_SOCKET.LocalIP]
mov edi, [ebx + IP_SOCKET.RemoteIP]
mov al, [ebx + IP_SOCKET.ttl]
mov ah, IP_PROTO_TCP
mov ecx, sizeof.TCP_header
mov ebx, [ebx + IP_SOCKET.device]
call ipv4_output
jz .error
pop esi cx
push eax
 
;-----------------------------------------------
; Fill in the TCP header by using the socket ptr
 
mov ax, [esi + TCP_SOCKET.LocalPort]
stosw
mov ax, [esi + TCP_SOCKET.RemotePort]
stosw
mov eax, [esi + TCP_SOCKET.SND_NXT]
bswap eax
stosd
mov eax, [esi + TCP_SOCKET.RCV_NXT]
bswap eax
stosd
mov al, 0x50 ; Dataoffset: 20 bytes (TCP_header.DataOffset)
stosb
mov al, cl
stosb
mov eax, SOCKET_BUFFER_SIZE
sub eax, [esi + STREAM_SOCKET.rcv.size]
cmp eax, TCP_max_win
jbe .lessthanmax
mov eax, TCP_max_win
.lessthanmax:
mov cl, [esi + TCP_SOCKET.RCV_SCALE]
shr eax, cl
 
xchg al, ah
stosw ; window
xor eax, eax
stosd ; checksum + urgentpointer
 
;---------------------
; Fill in the checksum
 
.checksum:
sub edi, sizeof.TCP_header
mov ecx, sizeof.TCP_header
xchg esi, edi
tcp_checksum (edi + IP_SOCKET.LocalIP), (edi + IP_SOCKET.RemoteIP)
mov [esi+TCP_header.Checksum], dx
 
;--------------------
; And send the segment
 
call [ebx + NET_DEVICE.transmit]
test eax, eax
jnz @f
call net_ptr_to_num4
inc [TCP_segments_tx + edi]
@@:
ret
 
.error:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_respond_socket: failed\n"
add esp, 2 + 4
 
ret
 
 
;-----------------------------------------------------------------;
; ;
; tcp_respond_segment ;
; ;
; IN: ebx = device ptr ;
; edx = segment ptr (a previously received segment) ;
; edi = ptr to IPv4 header ;
; cl = flags ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_respond_segment:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_respond_segment: frame=%x flags=%x\n", edx, cl
 
;---------------------
; Create the IP packet
 
push cx edx
mov edx, [edi + IPv4_header.DestinationAddress]
mov edi, [edi + IPv4_header.SourceAddress]
mov ecx, sizeof.TCP_header
mov ax, IP_PROTO_TCP shl 8 + 128
call ipv4_output
jz .error
pop esi cx
 
push eax
 
;---------------------------------------------------
; Fill in the TCP header by using a received segment
 
mov ax, [esi + TCP_header.DestinationPort]
stosw
mov ax, [esi + TCP_header.SourcePort]
stosw
mov eax, [esi + TCP_header.AckNumber]
bswap eax
stosd
xor eax, eax
stosd
mov al, 0x50 ; Dataoffset: 20 bytes (sizeof.TCP_header/4 shl 4)
stosb
mov al, cl
stosb
mov ax, 1280
rol ax, 8
stosw ; window
xor eax, eax
stosd ; checksum + urgentpointer
 
;---------------------
; Fill in the checksum
 
lea esi, [edi - sizeof.TCP_header]
mov ecx, sizeof.TCP_header
tcp_checksum (esi - sizeof.IPv4_header + IPv4_header.DestinationAddress),\ ; FIXME
(esi - sizeof.IPv4_header + IPv4_header.SourceAddress)
mov [esi + TCP_header.Checksum], dx
 
;--------------------
; And send the segment
 
call [ebx + NET_DEVICE.transmit]
test eax, eax
jnz @f
call net_ptr_to_num4
inc [TCP_segments_tx + edi]
@@:
ret
 
.error:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_respond_segment: failed\n"
add esp, 2+4
 
ret
 
 
macro tcpt_rangeset timer, value, min, max {
 
local .min
local .max
local .done
 
cmp value, min
jb .min
cmp value, max
ja .max
mov timer, value
jmp .done
.min:
mov timer, min
jmp .done
.max:
mov timer, max
.done:
}
 
;-----------------------------------------------------------------;
; ;
; tcp_set_persist ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_set_persist:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_set_persist\n"
 
; First, check if retransmit timer is not set, retransmit and persist are mutually exclusive
 
test [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
jnz .exit
 
; calculate RTO
push ebx
mov ebx, [eax + TCP_SOCKET.t_srtt]
shr ebx, 2
add ebx, [eax + TCP_SOCKET.t_rttvar]
shr ebx, 1
 
mov cl, [eax + TCP_SOCKET.t_rxtshift]
shl ebx, cl
 
; Start/restart persistance timer.
 
tcpt_rangeset [eax + TCP_SOCKET.timer_persist], ebx, TCP_time_pers_min, TCP_time_pers_max
or [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
pop ebx
 
cmp [eax + TCP_SOCKET.t_rxtshift], TCP_max_rxtshift
jae @f
inc [eax + TCP_SOCKET.t_rxtshift]
@@:
.exit:
 
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; tcp_xmit_timer: Calculate new smoothed RTT. ;
; ;
; IN: eax = rtt ;
; ebx = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_xmit_timer:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_xmit_timer: socket=0x%x rtt=%d0ms\n", ebx, eax
 
inc [TCPS_rttupdated]
 
cmp [ebx + TCP_SOCKET.t_rtt], 0
je .no_rtt_yet
 
; srtt is stored as a fixed point with 3 bits after the binary point.
; The following magic is equivalent of the smoothing algorithm in rfc793 with an alpha of .875
; (srtt = rtt/8 + srtt*7/8 in fixed point)
; Adjust rtt to origin 0.
 
push ecx
mov ecx, [ebx + TCP_SOCKET.t_srtt]
shr ecx, TCP_RTT_SHIFT
sub eax, ecx
dec eax
pop ecx
 
add [ebx + TCP_SOCKET.t_srtt], eax
ja @f
mov [ebx + TCP_SOCKET.t_srtt], 1
@@:
 
; We accumulate a smoothed rtt variance (actually, a smoothed mean difference),
; then set the retransmit timer to smoothed rtt + 4 times the smoothed variance.
; rttvar is stored as fixed point with 2 bits after the binary point.
; The following is equivalent to rfc793 smoothing with an alpha of .75
; (rttvar = rttvar*3/4 + delta/4) (delta = eax)
 
; get abs(eax)
push edx
cdq
xor eax, edx
sub eax, edx
 
mov edx, [ebx + TCP_SOCKET.t_rttvar]
shr edx, TCP_RTTVAR_SHIFT
sub eax, edx
pop edx
 
add [ebx + TCP_SOCKET.t_rttvar], eax
ja @f
mov [ebx + TCP_SOCKET.t_rttvar], 1
@@:
ret
 
 
.no_rtt_yet:
push ecx
mov ecx, eax
shl ecx, TCP_RTT_SHIFT
mov [ebx + TCP_SOCKET.t_srtt], ecx
 
shl eax, TCP_RTTVAR_SHIFT - 1
mov [ebx + TCP_SOCKET.t_rttvar], eax
pop ecx
 
ret
 
 
;-----------------------------------------------------------------;
; ;
; tcp_mss: Update maximum segment size ;
; ;
; IN: eax = max segment size ;
; ebx = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_mss:
 
cmp eax, 1420 ; FIXME
jbe @f
mov eax, 1420
@@:
mov [ebx + TCP_SOCKET.t_maxseg], eax
 
 
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; tcp_reassemble ;
; ;
; IN: ebx = socket ptr ;
; edx = segment ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_reassemble:
 
;;;;; TODO
 
ret
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/tcp_input.inc
0,0 → 1,1927
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; Based on the algorithms used in 4.4BSD ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
TCP_BIT_NEEDOUTPUT = 1 shl 0
TCP_BIT_TIMESTAMP = 1 shl 1
TCP_BIT_DROPSOCKET = 1 shl 2
TCP_BIT_FIN_IS_ACKED = 1 shl 3
 
;-----------------------------------------------------------------;
; ;
; TCP_input: Add a segment to the incoming TCP queue. ;
; ;
; IN: [esp] = ptr to buffer ;
; ebx = ptr to device struct ;
; ecx = TCP segment size ;
; edx = ptr to IPv4 header ;
; esi = ptr to TCP segment ;
; edi = interface number*4 ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_input:
 
; record the current time
push [timer_ticks] ; in 1/100 seconds
push ebx ecx esi edx ; mind the order (see TCP_queue_entry struct)
mov esi, esp
 
push edi
add_to_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .fail
pop edi
add esp, sizeof.TCP_queue_entry
 
inc [TCP_segments_rx + edi]
 
xor edx, edx
mov eax, [TCP_input_event]
mov ebx, [eax + EVENT.id]
xor esi, esi
call raise_event
 
ret
 
.fail:
pop edi
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP incoming queue is full, discarding packet!\n"
 
call net_ptr_to_num4
inc [TCP_segments_missed + edi]
 
add esp, sizeof.TCP_queue_entry - 4
call net_buff_free
ret
 
 
;-----------------------------------------------------------------;
; ;
; TCP_process_input: Process segments from the incoming TCP queue.;
; ;
; IN: / ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
proc tcp_process_input
 
locals
dataoffset dd ?
timestamp dd ?
temp_bits db ?
device dd ?
endl
 
xor esi, esi
mov ecx, MANUAL_DESTROY
call create_event
mov [TCP_input_event], eax
 
.wait:
mov eax, [TCP_input_event]
mov ebx, [eax + EVENT.id]
call wait_event
 
.loop:
get_from_queue TCP_queue, TCP_QUEUE_SIZE, sizeof.TCP_queue_entry, .wait
 
push [esi + TCP_queue_entry.timestamp]
pop [timestamp]
push [esi + TCP_queue_entry.buffer_ptr]
 
mov ebx, [esi + TCP_queue_entry.device_ptr]
mov [device], ebx
mov ecx, [esi + TCP_queue_entry.segment_size]
mov edi, [esi + TCP_queue_entry.ip_ptr] ; ptr to ipv4 header
mov esi, [esi + TCP_queue_entry.segment_ptr] ; change esi last
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: size=%u time=%d\n", ecx, [timer_ticks]
 
mov edx, esi
 
; Verify the checksum (if not already done by hw)
 
test [ebx + NET_DEVICE.hwacc], NET_HWACC_TCP_IPv4_IN
jnz .checksum_ok
 
push ecx esi
pushw [esi + TCP_header.Checksum]
mov [esi + TCP_header.Checksum], 0
tcp_checksum (edi+IPv4_header.SourceAddress), (edi+IPv4_header.DestinationAddress)
pop cx ; previous checksum
cmp cx, dx
pop edx ecx
jne .drop_no_socket
.checksum_ok:
 
; Verify the data offset
 
movzx eax, [edx + TCP_header.DataOffset]
and al, 0xf0 ; Calculate TCP segment header size (throwing away unused reserved bits in TCP header)
shr al, 2
cmp al, sizeof.TCP_header ; Now see if it's at least the size of a standard TCP header
jb .drop_no_socket ; If not, drop the packet
mov [dataoffset], eax
 
sub ecx, eax ; substract TCP header size from total segment size
jb .drop_no_socket ; If total segment size is less then the advertised header size, drop packet
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: %u bytes of data\n", ecx
 
;-------------------------------------------
; Convert Big-endian values to little endian
 
ntohd [edx + TCP_header.SequenceNumber]
ntohd [edx + TCP_header.AckNumber]
 
ntohw [edx + TCP_header.Window]
ntohw [edx + TCP_header.UrgentPointer]
 
;-----------------------------------------------------------------------------------
;
; Find the socket pointer
;
;-----------------------------------------------------------------------------------
 
; IP Packet TCP Destination Port = local Port
; (IP Packet SenderAddress = Remote IP) OR (Remote IP = 0)
; (IP Packet TCP Source Port = remote Port) OR (remote Port = 0)
 
.findpcb:
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
mov ebx, net_sockets
mov si, [edx + TCP_header.DestinationPort]
 
.socket_loop:
mov ebx, [ebx + SOCKET.NextPtr]
or ebx, ebx
jz .no_socket ;respond_seg_reset
 
cmp [ebx + SOCKET.Domain], AF_INET4
jne .socket_loop
 
cmp [ebx + SOCKET.Protocol], IP_PROTO_TCP
jne .socket_loop
 
cmp [ebx + TCP_SOCKET.LocalPort], si
jne .socket_loop
 
mov eax, [ebx + IP_SOCKET.RemoteIP]
cmp eax, [edi + IPv4_header.SourceAddress]
je @f
test eax, eax
jnz .socket_loop
@@:
 
mov ax, [ebx + TCP_SOCKET.RemotePort]
cmp [edx + TCP_header.SourcePort], ax
je .found_socket
test ax, ax
jnz .socket_loop
.found_socket: ; ebx now contains the socketpointer
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: socket ptr=%x state=%u flags=%x\n", ebx, [ebx + TCP_SOCKET.t_state], [edx + TCP_header.Flags]:2
 
;----------------------------
; Check if socket isnt closed
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
je .drop_no_socket
 
;----------------
; Lock the socket
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_lock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: socket locked\n"
 
;---------------------------
; disable all temporary bits
 
mov [temp_bits], 0
 
;---------------------------------------
; unscale the window into a 32 bit value
 
movzx eax, [edx + TCP_header.Window]
push ecx
mov cl, [ebx + TCP_SOCKET.SND_SCALE]
shl eax, cl
mov dword[edx + TCP_header.Window], eax ; word after window is checksum, we dont need checksum anymore
pop ecx
 
;-----------------------------------------------------------------------------------
;
; Accept incoming connections
;
;-----------------------------------------------------------------------------------
 
test [ebx + SOCKET.options], SO_ACCEPTCON
jz .no_accept
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Accepting new connection\n"
 
; Unlock current socket
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
 
; Fork it
 
push ecx edx esi edi
call socket_fork
pop edi esi edx ecx
 
test eax, eax
jz .drop_no_socket
 
; Success! Use the new socket from now on (it is already locked)
 
mov ebx, eax
 
mov [temp_bits], TCP_BIT_DROPSOCKET
 
push [edi + IPv4_header.DestinationAddress]
pop [ebx + IP_SOCKET.LocalIP]
 
push [edx + TCP_header.DestinationPort]
pop [ebx + TCP_SOCKET.LocalPort]
 
mov [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
.no_accept:
 
 
;-------------------------------------
; Reset idle timer and keepalive timer
 
mov [ebx + TCP_SOCKET.t_idle], 0
mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_idle
or [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive
 
;-----------------------------------------------------------------------------------
;
; Process TCP options
;
;-----------------------------------------------------------------------------------
 
;;; FIXME: for LISTEN, options should be called after we determined route, we need it for MSS
;;; cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN ; no options when in listen state
;;; jz .not_uni_xfer ; also no header prediction
 
push ecx
 
mov ecx, [dataoffset]
cmp ecx, sizeof.TCP_header ; Does header contain any options?
je .no_options
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Segment has options\n"
 
add ecx, edx
lea esi, [edx + sizeof.TCP_header]
 
.opt_loop:
cmp esi, ecx ; are we scanning outside of header?
jae .no_options
lodsb
cmp al, TCP_OPT_EOL ; end of option list?
je .no_options
cmp al, TCP_OPT_NOP
je .opt_loop
cmp al, TCP_OPT_MAXSEG
je .opt_maxseg
cmp al, TCP_OPT_WINDOW
je .opt_window
cmp al, TCP_OPT_SACK_PERMIT
je .opt_sack_permit
; cmp al, TCP_OPT_SACK
; je .opt_sack
cmp al, TCP_OPT_TIMESTAMP
je .opt_timestamp
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: unknown option:%u\n", al
jmp .no_options ; If we reach here, some unknown options were received, skip them all!
 
.opt_maxseg:
lodsb
cmp al, 4
jne .no_options ; error occured, ignore all options!
 
test [edx + TCP_header.Flags], TH_SYN
jz @f
 
xor eax, eax
lodsw
rol ax, 8
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Maxseg=%u\n", eax
call tcp_mss
@@:
jmp .opt_loop
 
 
.opt_window:
lodsb
cmp al, 3
jne .no_options
 
test [edx + TCP_header.Flags], TH_SYN
jz @f
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Got window scale option\n"
or [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
 
lodsb
mov [ebx + TCP_SOCKET.SND_SCALE], al
;;;;; TODO
 
@@:
jmp .opt_loop
 
 
.opt_sack_permit:
lodsb
cmp al, 2
jne .no_options
 
test [edx + TCP_header.Flags], TH_SYN
jz @f
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Selective Acknowledgement permitted\n"
or [ebx + TCP_SOCKET.t_flags], TF_SACK_PERMIT
 
@@:
jmp .opt_loop
 
 
.opt_timestamp:
lodsb
cmp al, 10 ; length must be 10
jne .no_options
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Got timestamp option\n"
 
test [edx + TCP_header.Flags], TH_SYN
jz @f
or [ebx + TCP_SOCKET.t_flags], TF_RCVD_TSTMP
@@:
 
lodsd
bswap eax
mov [ebx + TCP_SOCKET.ts_val], eax
lodsd ; timestamp echo reply
mov [ebx + TCP_SOCKET.ts_ecr], eax
or [temp_bits], TCP_BIT_TIMESTAMP
 
; Since we have a timestamp, lets do the paws test right away!
 
test [edx + TCP_header.Flags], TH_RST
jnz .no_paws
 
mov eax, [ebx + TCP_SOCKET.ts_recent]
test eax, eax
jz .no_paws
cmp eax, [ebx + TCP_SOCKET.ts_val]
jbe .no_paws
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: PAWS: detected an old segment\n"
 
mov eax, [timestamp]
sub eax, [ebx + TCP_SOCKET.ts_recent_age]
 
pop ecx
cmp eax, TCP_PAWS_IDLE
jle .paws_drop
push ecx
mov [ebx + TCP_SOCKET.ts_recent], 0 ; timestamp was invalid, fix it.
.no_paws:
jmp .opt_loop
 
.paws_drop:
inc [TCPS_rcvduppack]
add [TCPS_rcvdupbyte], ecx
inc [TCPS_pawsdrop]
jmp .drop_after_ack
 
.no_options:
 
pop ecx
 
;-----------------------------------------------------------------------------------
;
; Header prediction
;
;-----------------------------------------------------------------------------------
 
; According to Van Jacobson, there are two common cases for an uni-directional data transfer.
;
; General rule: the packets has no control flags, is in-sequence,
; window width didnt change and we're not retransmitting.
;
; Second rules:
; - If the length is 0 and the ACK moved forward, we're the sender side of the transfer.
; In this case we'll free the ACK'ed data and notify higher levels that we have free space in buffer
;
; - If the length is not 0 and the ACK didn't move, we're the receiver side of the transfer.
; If the packets are in order (data queue is empty), add the data to the socket buffer and request a delayed ACK
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
jnz .not_uni_xfer
 
test [edx + TCP_header.Flags], TH_SYN + TH_FIN + TH_RST + TH_URG
jnz .not_uni_xfer
 
test [edx + TCP_header.Flags], TH_ACK
jz .not_uni_xfer
 
mov eax, [edx + TCP_header.SequenceNumber]
cmp eax, [ebx + TCP_SOCKET.RCV_NXT]
jne .not_uni_xfer
 
mov eax, dword[edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jne .not_uni_xfer
 
mov eax, [ebx + TCP_SOCKET.SND_NXT]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
jne .not_uni_xfer
 
;---------------------------------------
; check if we are sender in the uni-xfer
 
; If the following 4 conditions are all true, this segment is a pure ACK.
;
; - The segment contains no data.
 
test ecx, ecx
jnz .not_sender
 
; - The congestion window is greater than or equal to the current send window.
; This test is true only if the window is fully open, that is, the connection is not in the middle of slow start or congestion avoidance.
 
mov eax, [ebx + TCP_SOCKET.SND_CWND]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jb .not_uni_xfer
 
; - The acknowledgment field in the segment is less than or equal to the maximum sequence number sent.
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .not_uni_xfer
 
; - The acknowledgment field in the segment is greater than the largest unacknowledged sequence number.
 
sub eax, [ebx + TCP_SOCKET.SND_UNA]
jbe .not_uni_xfer
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction: we are sender\n"
 
;---------------------------------
; Packet is a pure ACK, process it
 
inc [TCPS_predack]
 
inc [TCPS_rcvackpack]
add [TCPS_rcvackbyte], eax
 
; Delete acknowledged bytes from send buffer
 
pusha
mov ecx, eax
lea eax, [ebx + STREAM_SOCKET.snd]
call socket_ring_free
popa
 
; Update RTT estimators
 
test [temp_bits], TCP_BIT_TIMESTAMP
jz .no_timestamp_rtt
mov eax, [timestamp]
sub eax, [ebx + TCP_SOCKET.ts_ecr]
inc eax
call tcp_xmit_timer
jmp .rtt_done
.no_timestamp_rtt:
 
cmp [ebx + TCP_SOCKET.t_rtt], 0
je .rtt_done
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.t_rtseq]
jbe .rtt_done
mov eax, [ebx + TCP_SOCKET.t_rtt]
call tcp_xmit_timer
.rtt_done:
 
; update window pointers
 
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
 
; Stop retransmit timer
 
and [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission
 
; Unlock the socket
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
 
; Awaken waiting processes
 
mov eax, ebx
call socket_notify
 
; Generate more output
 
call tcp_output
 
jmp .drop_no_socket
 
;-------------------------------------------------
; maybe we are the receiver in the uni-xfer then..
 
.not_sender:
 
; - The amount of data in the segment is greater than 0 (data count is in ecx)
; - The acknowledgment field equals the largest unacknowledged sequence number. This means no data is acknowledged by this segment.
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
jne .not_uni_xfer
 
; - The reassembly list of out-of-order segments for the connection is empty.
 
cmp [ebx + TCP_SOCKET.seg_next], 0
jne .not_uni_xfer
 
; Complete processing of received data
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction: we are receiving %u bytes\n", ecx
 
mov esi, [dataoffset]
add esi, edx
lea eax, [ebx + STREAM_SOCKET.rcv]
call socket_ring_write ; Add the data to the socket buffer
add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied
 
mov eax, ebx
call socket_notify
 
or [ebx + TCP_SOCKET.t_flags], TF_DELACK ; Set delayed ack flag
 
jmp .drop
 
 
;-----------------------------------------------------------------------------------
;
; TCP segment processing, the slow way
;
;-----------------------------------------------------------------------------------
 
.not_uni_xfer:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Header prediction failed\n"
 
; Calculate receive window size
 
push edx
mov eax, SOCKET_BUFFER_SIZE
sub eax, [ebx + STREAM_SOCKET.rcv.size]
DEBUGF DEBUG_NETWORK_VERBOSE, "Space in receive buffer=%d\n", eax
mov edx, [ebx + TCP_SOCKET.RCV_ADV]
sub edx, [ebx + TCP_SOCKET.RCV_NXT]
DEBUGF DEBUG_NETWORK_VERBOSE, "Current advertised window=%d\n", edx
cmp eax, edx
jg @f
mov eax, edx
@@:
DEBUGF DEBUG_NETWORK_VERBOSE, "Receive window size=%d\n", eax
mov [ebx + TCP_SOCKET.RCV_WND], eax
pop edx
 
; If we are in listen or syn_sent state, go to that specific code right away
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_LISTEN
je .state_listen
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_SENT
je .state_syn_sent
 
;-----------------------------------------------------------------------------------
;
; Trim any data not in window
;
;-----------------------------------------------------------------------------------
 
;-------------------------------------------------
; Check for duplicate data at beginning of segment
 
; Calculate number of bytes we need to drop
 
mov eax, [ebx + TCP_SOCKET.RCV_NXT]
sub eax, [edx + TCP_header.SequenceNumber]
jle .no_duplicate
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: %u bytes duplicate data!\n", eax
 
; Check for duplicate SYN
 
test [edx + TCP_header.Flags], TH_SYN
jz .no_dup_syn
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: got duplicate syn\n"
 
and [edx + TCP_header.Flags], not (TH_SYN)
inc [edx + TCP_header.SequenceNumber]
 
cmp [edx + TCP_header.UrgentPointer], 1
jbe @f
dec [edx + TCP_header.UrgentPointer]
jmp .dup_syn
@@:
and [edx + TCP_header.Flags], not (TH_URG)
.dup_syn:
dec eax
.no_dup_syn:
 
;-----------------------------------
; Check for entire duplicate segment
 
cmp eax, ecx ; eax holds number of bytes to drop, ecx is data size
jb .no_complete_dup
jnz @f
test [edx + TCP_header.Flags], TH_FIN
jnz .no_complete_dup
@@:
 
; Any valid FIN must be to the left of the window.
; At this point the FIN must be out of sequence or a duplicate, drop it
 
and [edx + TCP_header.Flags], not TH_FIN
 
; send an ACK to resynchronize and drop any data.
; But keep on processing for RST or ACK
 
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
mov eax, ecx
 
inc [TCPS_rcvduppack]
add [TCPS_rcvdupbyte], eax
jmp .dup_processed
.no_complete_dup:
inc [TCPS_rcvpartduppack]
add [TCPS_rcvpartdupbyte], eax
.dup_processed:
 
;-----------------------------------------------
; Remove duplicate data and update urgent offset
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: trimming duplicate data\n"
 
; Trim data from left side of window
 
add [dataoffset], eax
add [edx + TCP_header.SequenceNumber], eax
sub ecx, eax
 
sub [edx + TCP_header.UrgentPointer], ax
jg @f
and [edx + TCP_header.Flags], not (TH_URG)
mov [edx + TCP_header.UrgentPointer], 0
@@:
.no_duplicate:
 
;--------------------------------------------------
; Handle data that arrives after process terminates
 
cmp [ebx + SOCKET.PID], 0 ;;; TODO: use socket flags instead??
jne .not_terminated
cmp [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jbe .not_terminated
test ecx, ecx
jz .not_terminated
 
mov eax, ebx
call tcp_close
inc [TCPS_rcvafterclose]
jmp .respond_seg_reset
.not_terminated:
 
;----------------------------------------
; Remove data beyond right edge of window
 
mov eax, [edx + TCP_header.SequenceNumber]
add eax, ecx
sub eax, [ebx + TCP_SOCKET.RCV_NXT]
sub eax, [ebx + TCP_SOCKET.RCV_WND] ; eax now holds the number of bytes to drop
jle .no_excess_data
 
DEBUGF DEBUG_NETWORK_VERBOSE, "%d bytes beyond right edge of window\n", eax
 
inc [TCPS_rcvpackafterwin]
 
cmp eax, ecx
jl .dont_drop_all
 
add [TCPS_rcvbyteafterwin], ecx
 
;----------------------------------------------------------------------------------------------------
; If a new connection request is received while in TIME_WAIT, drop the old connection and start over,
; if the sequence numbers are above the previous ones
 
test [edx + TCP_header.Flags], TH_SYN
jz .no_new_request
cmp [ebx + TCP_SOCKET.t_state], TCPS_TIME_WAIT
jne .no_new_request
; mov edx, [ebx + TCP_SOCKET.RCV_NXT]
; cmp edx, [edx + TCP_header.SequenceNumber]
; add edx, 64000 ; TCP_ISSINCR FIXME
mov eax, ebx
call tcp_close
jmp .findpcb ; FIXME: skip code for unscaling window, ...
.no_new_request:
 
; If window is closed, we can only take segments at window edge, and have to drop data and PUSH from
; incoming segments. Continue processing, but remember to ACK. Otherwise drop segment and ACK
 
cmp [ebx + TCP_SOCKET.RCV_WND], 0
jne .drop_after_ack
mov esi, [edx + TCP_header.SequenceNumber]
cmp esi, [ebx + TCP_SOCKET.RCV_NXT]
jne .drop_after_ack
 
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
inc [TCPS_rcvwinprobe]
.dont_drop_all:
add [TCPS_rcvbyteafterwin], eax
DEBUGF DEBUG_NETWORK_VERBOSE, "Trimming %u bytes from the right of the window\n"
 
; remove data from the right side of window (decrease data length)
 
sub ecx, eax
and [edx + TCP_header.Flags], not (TH_PUSH or TH_FIN)
.no_excess_data:
 
;-----------------------------------------------------------------------------------
;
; Record timestamp
;
;-----------------------------------------------------------------------------------
 
; If last ACK falls within this segments sequence numbers, record its timestamp
 
test [temp_bits], TCP_BIT_TIMESTAMP
jz .no_timestamp
mov eax, [ebx + TCP_SOCKET.last_ack_sent]
sub eax, [edx + TCP_header.SequenceNumber]
jb .no_timestamp
test [edx + TCP_header.Flags], TH_SYN or TH_FIN ; SYN and FIN occupy one byte
jz @f
dec eax
@@:
sub eax, ecx
jae .no_timestamp
 
DEBUGF DEBUG_NETWORK_VERBOSE, "Recording timestamp\n"
 
mov eax, [timestamp]
mov [ebx + TCP_SOCKET.ts_recent_age], eax
mov eax, [ebx + TCP_SOCKET.ts_val]
mov [ebx + TCP_SOCKET.ts_recent], eax
.no_timestamp:
 
;-----------------------------------------------------------------------------------
;
; Process RST flag
;
;-----------------------------------------------------------------------------------
 
test [edx + TCP_header.Flags], TH_RST
jz .no_rst
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Got an RST flag\n"
 
mov eax, [ebx + TCP_SOCKET.t_state]
shl eax, 2
jmp dword [eax + .rst_sw_list]
 
;-----------------------------------------------------------------------------------
.rst_sw_list:
dd .no_rst ; TCPS_CLOSED
dd .no_rst ; TCPS_LISTEN
dd .no_rst ; TCPS_SYN_SENT
dd .econnrefused ; TCPS_SYN_RECEIVED
dd .econnreset ; TCPS_ESTABLISHED
dd .econnreset ; TCPS_CLOSE_WAIT
dd .econnreset ; TCPS_FIN_WAIT_1
dd .rst_close ; TCPS_CLOSING
dd .rst_close ; TCPS_LAST_ACK
dd .econnreset ; TCPS_FIN_WAIT_2
dd .rst_close ; TCPS_TIME_WAIT
 
;-----------------------------------------------------------------------------------
.econnrefused:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Connection refused\n"
mov [ebx + SOCKET.errorcode], ECONNREFUSED
jmp .close
 
;-----------------------------------------------------------------------------------
.econnreset:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Connection reset\n"
mov [ebx + SOCKET.errorcode], ECONNRESET
.close:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Closing connection\n"
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSED
inc [TCPS_drops]
 
 
jmp .drop
 
;-----------------------------------------------------------------------------------
.rst_close:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Closing with reset\n"
jmp .unlock_and_close
 
;-----------------------------------------------------------------------------------
.no_rst:
 
;-----------------------------------------------------------------------------------
;
; Handle SYN-full and ACK-less segments
;
;-----------------------------------------------------------------------------------
 
; If a SYN is in the window, then this is an error so we send an RST and drop the connection
 
test [edx + TCP_header.Flags], TH_SYN
jz .not_syn_full
 
mov eax, ebx
mov ebx, ECONNRESET
call tcp_drop
jmp .drop_with_reset
.not_syn_full:
 
; If ACK bit is off, we drop the segment and return
 
test [edx + TCP_header.Flags], TH_ACK
jz .drop
 
;----------------------------------------------------------------------------------
;
; ACK processing for SYN_RECEIVED state
;
;----------------------------------------------------------------------------------
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
jb .ack_processed ; states: closed, listen, syn_sent
ja .no_syn_rcv ; established, fin_wait_1, fin_wait_2, close_wait, closing, last_ack, time_wait
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: state=syn_received\n"
 
mov eax, [edx + TCP_header.AckNumber]
cmp [ebx + TCP_SOCKET.SND_UNA], eax
ja .drop_with_reset
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .drop_with_reset
 
inc [TCPS_connects]
 
mov eax, ebx
call socket_is_connected
mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
 
; Do window scaling?
 
test [ebx + TCP_SOCKET.t_flags], TF_RCVD_SCALE
jz @f
test [ebx + TCP_SOCKET.t_flags], TF_REQ_SCALE
jz @f
 
push word[ebx + TCP_SOCKET.requested_s_scale] ; Set send and receive scale factors to the received values
pop word[ebx + TCP_SOCKET.SND_SCALE]
@@:
 
call tcp_reassemble
 
mov eax, [edx + TCP_header.SequenceNumber]
dec eax
mov [ebx + TCP_SOCKET.SND_WL1], eax
.no_syn_rcv:
 
;-----------------------------------------------------------------------------------
;
; ACK processing for SYN_RECEIVED state and higher
;
;-----------------------------------------------------------------------------------
 
;-------------------------
; Check for duplicate ACKs
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
ja .dup_ack_complete
 
test ecx, ecx
jnz .reset_dupacks
 
mov eax, dword[edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jne .reset_dupacks
 
inc [TCPS_rcvdupack]
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Processing duplicate ACK\n"
 
; If we have outstanding data, other than a window probe, this is a completely duplicate ACK
; (window info didnt change) The ACK is the biggest we've seen and we've seen exactly our rexmt threshold of them,
; assume a packet has been dropped and retransmit it. Kludge snd_nxt & the congestion window so we send only this one packet.
 
test [ebx + TCP_SOCKET.timer_flags], timer_flag_retransmission
jz .reset_dupacks
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_UNA]
jne .reset_dupacks
 
; Increment dupplicat ACK counter
; If it reaches the threshold, re-transmit the missing segment
 
inc [ebx + TCP_SOCKET.t_dupacks]
cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh
jb .dup_ack_complete
ja .another_lost
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Re-transmitting lost segment\n"
 
push [ebx + TCP_SOCKET.SND_NXT] ; >>>>
 
mov eax, [ebx + TCP_SOCKET.SND_WND]
cmp eax, [ebx + TCP_SOCKET.SND_CWND]
jbe @f
mov eax, [ebx + TCP_SOCKET.SND_CWND]
@@:
shr eax, 1
push edx
xor edx, edx
div [ebx + TCP_SOCKET.t_maxseg]
cmp eax, 2
ja @f
xor eax, eax
mov al, 2
@@:
mul [ebx + TCP_SOCKET.t_maxseg]
pop edx
mov [ebx + TCP_SOCKET.SND_SSTHRESH], eax
 
and [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission ; turn off retransmission timer
mov [ebx + TCP_SOCKET.t_rtt], 0
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_NXT], eax
mov eax, [ebx + TCP_SOCKET.t_maxseg]
mov [ebx + TCP_SOCKET.SND_CWND], eax
 
; Unlock the socket
 
push ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
 
; retransmit missing segment
 
mov eax, [esp]
call tcp_output
 
; Lock the socket again
 
mov ecx, [esp]
add ecx, SOCKET.mutex
call mutex_lock
pop ebx
 
; Continue processing
 
xor edx, edx
mov eax, [ebx + TCP_SOCKET.t_maxseg]
mul [ebx + TCP_SOCKET.t_dupacks]
add eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
mov [ebx + TCP_SOCKET.SND_CWND], eax
 
pop eax ; <<<<
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jb @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
@@:
jmp .drop
 
.another_lost:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Increasing congestion window\n"
 
mov eax, [ebx + TCP_SOCKET.t_maxseg]
add [ebx + TCP_SOCKET.SND_CWND], eax
 
; Unlock the socket
 
push ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
 
; retransmit missing segment, again
 
mov eax, [esp]
call tcp_output
 
; Lock the socket again
 
mov ecx, [esp]
add ecx, SOCKET.mutex
call mutex_lock
pop ebx
 
; And drop the incoming segment
 
jmp .drop
 
.reset_dupacks: ; We got a new ACK, reset duplicate ACK counter
mov [ebx + TCP_SOCKET.t_dupacks], 0
jmp .ack_processed
 
.dup_ack_complete:
 
;-------------------------------------------------
; If the congestion window was inflated to account
; for the other side's cached packets, retract it
 
mov eax, [ebx + TCP_SOCKET.SND_SSTHRESH]
cmp eax, [ebx + TCP_SOCKET.SND_CWND]
ja @f
cmp [ebx + TCP_SOCKET.t_dupacks], TCP_re_xmit_thresh
jbe @f
mov [ebx + TCP_SOCKET.SND_CWND], eax
@@:
 
mov [ebx + TCP_SOCKET.t_dupacks], 0
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
jbe @f
inc [TCPS_rcvacktoomuch]
jmp .drop_after_ack
@@:
 
mov edi, [edx + TCP_header.AckNumber]
sub edi, [ebx + TCP_SOCKET.SND_UNA] ; now we got the number of acked bytes in edi
inc [TCPS_rcvackpack]
add [TCPS_rcvackbyte], edi
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: acceptable ACK for %u bytes\n", edi
 
;-----------------------------------------------------------------------------------
;
; RTT measurements and retransmission timer
;
;-----------------------------------------------------------------------------------
 
; If we have a timestamp, update smoothed RTT
 
test [temp_bits], TCP_BIT_TIMESTAMP
jz .timestamp_not_present
mov eax, [timestamp]
sub eax, [ebx + TCP_SOCKET.ts_ecr]
inc eax
call tcp_xmit_timer
jmp .rtt_done_
 
; If no timestamp but transmit timer is running and timed sequence number was acked,
; update smoothed RTT. Since we now have an RTT measurement, cancel the timer backoff
; (Phil Karn's retransmit algo)
; Recompute the initial retransmit timer
 
.timestamp_not_present:
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.t_rtseq]
jbe .rtt_done_
mov eax, [ebx + TCP_SOCKET.t_rtt]
test eax, eax
jz .rtt_done_
call tcp_xmit_timer
.rtt_done_:
 
; If all outstanding data is acked, stop retransmit timer and remember to restart (more output or persist)
; If there is more data to be acked, restart retransmit timer, using current (possible backed-off) value.
 
mov eax, [ebx + TCP_SOCKET.SND_MAX]
cmp eax, [edx + TCP_header.AckNumber]
jne .more_data
and [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission
or [temp_bits], TCP_BIT_NEEDOUTPUT
jmp .no_restart
.more_data:
test [ebx + TCP_SOCKET.timer_flags], timer_flag_persist
jnz .no_restart
 
mov eax, [ebx + TCP_SOCKET.t_rxtcur]
mov [ebx + TCP_SOCKET.timer_retransmission], eax
or [ebx + TCP_SOCKET.timer_flags], timer_flag_retransmission
.no_restart:
 
;-----------------------------------------------------------------------------------
;
; Open congestion window in response to ACKs
;
;-----------------------------------------------------------------------------------
 
; If the window gives us less then sstresh packets in flight, open exponentially.
; Otherwise, open lineary
 
mov esi, [ebx + TCP_SOCKET.SND_CWND]
mov eax, [ebx + TCP_SOCKET.t_maxseg]
cmp esi, [ebx + TCP_SOCKET.SND_SSTHRESH]
jbe @f
push edx
push eax
mul eax ; t_maxseg*t_maxseg
div esi ; t_maxseg*t_maxseg/snd_cwnd
pop edx ; t_maxseg
shr edx, 3 ; t_maxseg/8
add eax, edx ; t_maxseg*t_maxseg/snd_cwnd + t_maxseg/8
pop edx
@@:
add esi, eax
 
push ecx
mov cl, [ebx + TCP_SOCKET.SND_SCALE]
mov eax, TCP_max_win
shl eax, cl
pop ecx
 
cmp esi, eax
jbe @f
mov esi, eax
@@:
mov [ebx + TCP_SOCKET.SND_CWND], esi
 
;-----------------------------------------------------------------------------------
;
; Remove acknowledged data from send buffer
;
;-----------------------------------------------------------------------------------
 
; If the number of bytes acknowledged exceeds the number of bytes on the send buffer,
; snd_wnd is decremented by the number of bytes in the send buffer and TCP knows
; that its FIN has been ACKed. (FIN occupies 1 byte in the sequence number space)
 
cmp edi, [ebx + STREAM_SOCKET.snd.size]
jbe .no_fin_ack
 
; Drop all data in output buffer
 
push ecx edx ebx
mov ecx, [ebx + STREAM_SOCKET.snd.size]
sub [ebx + TCP_SOCKET.SND_WND], ecx
lea eax, [ebx + STREAM_SOCKET.snd]
call socket_ring_free
pop ebx edx ecx
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: our FIN is acked\n"
or [temp_bits], TCP_BIT_FIN_IS_ACKED
jmp .ack_complete
.no_fin_ack:
 
; Drop acknowledged data
 
push ecx edx ebx
mov ecx, edi
lea eax, [ebx + STREAM_SOCKET.snd]
call socket_ring_free
pop ebx
sub [ebx + TCP_SOCKET.SND_WND], ecx
pop edx ecx
.ack_complete:
 
;-----------------------------------------------------------------------------------
;
; Wake up process waiting on send buffer
;
;-----------------------------------------------------------------------------------
 
mov eax, ebx
call socket_notify
 
; Update TCPS
 
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jb @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
@@:
 
;-----------------------------------------------------------------------------------
;
; State specific ACK handeling
;
;-----------------------------------------------------------------------------------
 
mov eax, [ebx + TCP_SOCKET.t_state]
jmp dword[.ack_sw_list+eax*4]
 
.ack_sw_list:
dd .ack_processed ; TCPS_CLOSED
dd .ack_processed ; TCPS_LISTEN
dd .ack_processed ; TCPS_SYN_SENT
dd .ack_processed ; TCPS_SYN_RECEIVED
dd .ack_processed ; TCPS_ESTABLISHED
dd .ack_processed ; TCPS_CLOSE_WAIT
dd .ack_fw1 ; TCPS_FIN_WAIT_1
dd .ack_c ; TCPS_CLOSING
dd .ack_la ; TCPS_LAST_ACK
dd .ack_processed ; TCPS_FIN_WAIT_2
dd .ack_tw ; TCPS_TIMED_WAIT
 
;-----------------------------------------------------------------------------------
.ack_fw1:
; If our FIN is now acked, enter FIN_WAIT_2
 
test [temp_bits], TCP_BIT_FIN_IS_ACKED
jz .ack_processed
 
; If we can't receive any more data, then closing user can proceed.
; Starting the timer is contrary to the specification, but if we dont get a FIN,
; we'll hang forever.
 
test [ebx + SOCKET.state], SS_CANTRCVMORE
jz @f
mov eax, ebx
call socket_is_disconnected
mov [ebx + TCP_SOCKET.timer_timed_wait], TCP_time_max_idle
or [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
@@:
mov [ebx + TCP_SOCKET.t_state], TCPS_FIN_WAIT_2
jmp .ack_processed
 
;-----------------------------------------------------------------------------------
.ack_c:
; Enter the TIME_WAIT state if our FIN is acked in CLOSED state.
 
test [temp_bits], TCP_BIT_FIN_IS_ACKED
jz .ack_processed
 
mov [ebx + TCP_SOCKET.t_state], TCPS_TIME_WAIT
mov eax, ebx
call tcp_cancel_timers
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
or [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
mov eax, ebx
call socket_is_disconnected
jmp .ack_processed
 
;-----------------------------------------------------------------------------------
.ack_la:
; In LAST_ACK state, we may still be waiting for data to drain and/or to be acked.
; If our FIN is acked however, enter CLOSED state and return.
 
test [temp_bits], TCP_BIT_FIN_IS_ACKED
jz .ack_processed
 
.unlock_and_close:
push ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
pop eax
 
call tcp_close
jmp .drop_no_socket
 
;-----------------------------------------------------------------------------------
.ack_tw:
; In TIME_WAIT state the only thing that should arrive is a retransmission of the remote FIN.
; Acknowledge it and restart the FINACK timer
 
mov [ebx + TCP_SOCKET.timer_timed_wait], 2*TCP_time_MSL
or [ebx + TCP_SOCKET.timer_flags], timer_flag_2msl
jmp .drop_after_ack
 
;-----------------------------------------------------------------------------------
;
; Initiation of Passive Open?
;
;-----------------------------------------------------------------------------------
 
.state_listen:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: state=listen\n"
 
test [edx + TCP_header.Flags], TH_RST
jnz .drop
 
test [edx + TCP_header.Flags], TH_ACK
jnz .drop_with_reset
 
test [edx + TCP_header.Flags], TH_SYN
jz .drop
 
inc [TCPS_accepts]
 
;;; TODO: check if it's a broadcast or multicast, and drop if so
 
;-------------------------------------------
; Processing of SYN received in LISTEN state
 
push [edi + IPv4_header.SourceAddress]
pop [ebx + IP_SOCKET.RemoteIP]
 
push [edx + TCP_header.SourcePort]
pop [ebx + TCP_SOCKET.RemotePort]
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
 
mov eax, [TCP_sequence_num]
add [TCP_sequence_num], TCP_ISSINCR / 2
mov [ebx + TCP_SOCKET.ISS], eax
mov [ebx + TCP_SOCKET.SND_NXT], eax
 
tcp_sendseqinit ebx
tcp_rcvseqinit ebx
 
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
mov [ebx + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval ;;;; macro
or [ebx + TCP_SOCKET.timer_flags], timer_flag_keepalive
 
lea eax, [ebx + STREAM_SOCKET.snd]
call socket_ring_create
test eax, eax
jz .drop
 
lea eax, [ebx + STREAM_SOCKET.rcv]
call socket_ring_create
test eax, eax
jz .drop
 
and [temp_bits], not TCP_BIT_DROPSOCKET
 
pusha
mov eax, ebx
call socket_notify
popa
 
jmp .trim
 
;-----------------------------------------------------------------------------------
;
; Completion of active open?
;
;-----------------------------------------------------------------------------------
 
.state_syn_sent:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: state=syn_sent\n"
 
test [edx + TCP_header.Flags], TH_ACK
jz @f
 
mov eax, [edx + TCP_header.AckNumber]
cmp eax, [ebx + TCP_SOCKET.ISS]
jbe .drop_with_reset
 
cmp eax, [ebx + TCP_SOCKET.SND_MAX]
ja .drop_with_reset
@@:
 
test [edx + TCP_header.Flags], TH_RST
jz @f
 
test [edx + TCP_header.Flags], TH_ACK
jz .drop
 
mov eax, ebx
mov ebx, ECONNREFUSED
call tcp_drop
jmp .drop
@@:
 
;-----------------------------------------------------------------------------------
;
; Process received SYN in response to an active open
;
;-----------------------------------------------------------------------------------
 
test [edx + TCP_header.Flags], TH_SYN
jz .drop
 
test [edx + TCP_header.Flags], TH_ACK
jz @f
 
mov eax, [edx + TCP_header.AckNumber]
mov [ebx + TCP_SOCKET.SND_UNA], eax
cmp eax, [ebx + TCP_SOCKET.SND_NXT]
jbe @f
mov [ebx + TCP_SOCKET.SND_NXT], eax
 
and [ebx + TCP_SOCKET.timer_flags], not timer_flag_retransmission ; disable retransmission timer
@@:
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.IRS]
 
tcp_rcvseqinit ebx
 
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
 
mov eax, [ebx + TCP_SOCKET.SND_UNA]
cmp eax, [ebx + TCP_SOCKET.ISS]
jbe .simultaneous_open
 
test [edx + TCP_header.Flags], TH_ACK
jz .simultaneous_open
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: active open\n"
 
inc [TCPS_connects]
 
; set socket state to connected
 
push eax
mov eax, ebx
call socket_is_connected
pop eax
mov [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
 
; Do window scaling on this connection ?
 
mov eax, [ebx + TCP_SOCKET.t_flags]
and eax, TF_REQ_SCALE or TF_RCVD_SCALE
cmp eax, TF_REQ_SCALE or TF_RCVD_SCALE
jne .no_scaling
 
mov ax, word[ebx + TCP_SOCKET.requested_s_scale]
mov word[ebx + TCP_SOCKET.SND_SCALE], ax
.no_scaling:
 
;;; TODO: reassemble packets queue
 
; If we didnt have time to re-transmit the SYN,
; Use its rtt as our initial srtt & rtt var.
 
mov eax, [ebx + TCP_SOCKET.t_rtt]
test eax, eax
je .trim
call tcp_xmit_timer
jmp .trim
 
;-----------------------------------------------------------------------------------
;
; Simultaneous open (We have received a SYN but no ACK)
;
;-----------------------------------------------------------------------------------
 
.simultaneous_open:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: simultaneous open\n"
mov [ebx + TCP_SOCKET.t_state], TCPS_SYN_RECEIVED
 
;-----------------------------------------------------------------------------------
;
; Common processing for receipt of SYN
;
;-----------------------------------------------------------------------------------
 
.trim:
; Advance sequence number to correspond to first data byte.
; If data, trim to stay within window, dropping FIN if necessary
 
inc [edx + TCP_header.SequenceNumber]
 
; Drop any received data that doesnt fit in the receive window.
 
cmp ecx, [ebx + TCP_SOCKET.RCV_WND]
jbe .dont_trim
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: received data does not fit in window, trimming %u bytes\n", eax
inc [TCPS_rcvpackafterwin]
sub ecx, [ebx + TCP_SOCKET.RCV_WND]
add [TCPS_rcvbyteafterwin], ecx
 
and [edx + TCP_header.Flags], not (TH_FIN)
mov ecx, [ebx + TCP_SOCKET.RCV_WND]
 
.dont_trim:
mov eax, [edx + TCP_header.SequenceNumber]
mov [ebx + TCP_SOCKET.RCV_UP], eax
dec eax
mov [ebx + TCP_SOCKET.SND_WL1], eax
 
;-----------------------------------------------------------------------------------
;
; Update window information (step 6 in RFC793)
;
;-----------------------------------------------------------------------------------
 
.ack_processed:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: ACK processed\n"
 
; dont look at window if no ACK
 
test [edx + TCP_header.Flags], TH_ACK
jz .no_window_update
 
; Does the segment contain new data?
 
mov eax, [ebx + TCP_SOCKET.SND_WL1]
cmp eax, [edx + TCP_header.SequenceNumber]
jb .update_window
ja @f
 
; No new data but a new ACK ?
 
mov eax, [ebx + TCP_SOCKET.SND_WL2]
cmp eax, [edx + TCP_header.AckNumber]
jb .update_window
@@:
 
; No new data or ACK but advertised window is larger then current window?
 
mov eax, [ebx + TCP_SOCKET.SND_WL2]
cmp eax, [edx + TCP_header.AckNumber]
jne .no_window_update
 
mov eax, dword[edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jbe .no_window_update
 
 
; Keep track of pure window updates
.update_window:
test ecx, ecx
jnz @f
mov eax, [ebx + TCP_SOCKET.SND_WL2]
cmp eax, [edx + TCP_header.AckNumber]
jne @f
mov eax, dword[edx + TCP_header.Window]
cmp eax, [ebx + TCP_SOCKET.SND_WND]
jbe @f
inc [TCPS_rcvwinupd]
@@:
 
mov eax, dword[edx + TCP_header.Window]
mov [ebx + TCP_SOCKET.SND_WND], eax
cmp eax, [ebx + TCP_SOCKET.max_sndwnd]
jbe @f
mov [ebx + TCP_SOCKET.max_sndwnd], eax
@@:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Updating window to %u\n", eax
 
push [edx + TCP_header.SequenceNumber]
pop [ebx + TCP_SOCKET.SND_WL1]
 
push [edx + TCP_header.AckNumber]
pop [ebx + TCP_SOCKET.SND_WL2]
 
or [temp_bits], TCP_BIT_NEEDOUTPUT
.no_window_update:
 
;-----------------------------------------------------------------------------------
;
; Process URG flag
;
;-----------------------------------------------------------------------------------
 
test [edx + TCP_header.Flags], TH_URG
jz .not_urgent
 
cmp [edx + TCP_header.UrgentPointer], 0
jz .not_urgent
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_TIME_WAIT
je .not_urgent
 
; Ignore bogus urgent offsets
 
movzx eax, [edx + TCP_header.UrgentPointer]
add eax, [ebx + STREAM_SOCKET.rcv.size]
cmp eax, SOCKET_BUFFER_SIZE
jbe .not_urgent
 
mov [edx + TCP_header.UrgentPointer], 0
and [edx + TCP_header.Flags], not (TH_URG)
jmp .do_data
 
.not_urgent:
 
; processing of received urgent pointer
 
;;; TODO (1051-1093)
 
;-----------------------------------------------------------------------------------
;
; Process the data
;
;-----------------------------------------------------------------------------------
 
.do_data:
cmp [ebx + TCP_SOCKET.t_state], TCPS_TIME_WAIT
jae .final_processing
 
test [edx + TCP_header.Flags], TH_FIN
jnz @f
 
test ecx, ecx
jz .final_processing
@@:
 
; The segment is in order?
 
mov eax, [edx + TCP_header.SequenceNumber]
cmp eax, [ebx + TCP_SOCKET.RCV_NXT]
jne .out_of_order
 
; The reassembly queue is empty?
 
cmp [ebx + TCP_SOCKET.seg_next], 0
jne .out_of_order
 
; The connection is established?
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_ESTABLISHED
jne .out_of_order
 
; Ok, lets do this.. Set delayed ACK flag and copy data into socket buffer
 
or [ebx + TCP_SOCKET.t_flags], TF_DELACK
 
pusha
mov esi, [dataoffset]
add esi, edx
lea eax, [ebx + STREAM_SOCKET.rcv]
call socket_ring_write ; Add the data to the socket buffer
add [ebx + TCP_SOCKET.RCV_NXT], ecx ; Update sequence number with number of bytes we have copied
popa
 
; Wake up the sleeping process
 
mov eax, ebx
call socket_notify
 
jmp .data_done
 
.out_of_order:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP data is out of order!\nSequencenumber is %u, we expected %u.\n", \
[edx + TCP_header.SequenceNumber], [ebx + TCP_SOCKET.RCV_NXT]
 
; Uh-oh, some data is out of order, lets call TCP reassemble for help
 
call tcp_reassemble ;;; TODO!
 
; Generate ACK immediately, to let the other end know that a segment was received out of order,
; and to tell it what sequence number is expected. This aids the fast-retransmit algorithm.
 
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
 
jmp .final_processing ;;; HACK because of unimplemented reassembly queue!
.data_done:
 
;-----------------------------------------------------------------------------------
;
; Process FIN
;
;-----------------------------------------------------------------------------------
 
test [edx + TCP_header.Flags], TH_FIN
jz .final_processing
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Processing FIN\n"
 
cmp [ebx + TCP_SOCKET.t_state], TCPS_TIME_WAIT
jae .not_first_fin
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: First FIN for this connection\n"
 
mov eax, ebx
call socket_cant_recv_more
 
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
inc [ebx + TCP_SOCKET.RCV_NXT]
 
.not_first_fin:
mov eax, [ebx + TCP_SOCKET.t_state]
jmp dword[.fin_sw_list+eax*4]
 
.fin_sw_list:
dd .final_processing ; TCPS_CLOSED
dd .final_processing ; TCPS_LISTEN
dd .final_processing ; TCPS_SYN_SENT
dd .fin_syn_est ; TCPS_SYN_RECEIVED
dd .fin_syn_est ; TCPS_ESTABLISHED
dd .final_processing ; TCPS_CLOSE_WAIT
dd .fin_wait1 ; TCPS_FIN_WAIT_1
dd .final_processing ; TCPS_CLOSING
dd .final_processing ; TCPS_LAST_ACK
dd .fin_wait2 ; TCPS_FIN_WAIT_2
dd .fin_timed ; TCPS_TIMED_WAIT
 
;-----------------------------------------------------------------------------------
.fin_syn_est:
; In SYN_RECEIVED and ESTABLISHED state, enter the CLOSE_WAIT state
 
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSE_WAIT
jmp .final_processing
 
;-----------------------------------------------------------------------------------
.fin_wait1:
; From FIN_WAIT_1 state, enter CLOSING state (our FIN has not been ACKed)
 
mov [ebx + TCP_SOCKET.t_state], TCPS_CLOSING
jmp .final_processing
 
;-----------------------------------------------------------------------------------
.fin_wait2:
; From FIN_WAIT_2 state, enter TIME_WAIT state and start the timer
 
mov [ebx + TCP_SOCKET.t_state], TCPS_TIME_WAIT
mov eax, ebx
call tcp_cancel_timers
call socket_is_disconnected
 
;-----------------------------------------------------------------------------------
.fin_timed:
; (re)start the 2 MSL timer
mov [ebx + TCP_SOCKET.timer_timed_wait], 2 * TCP_time_MSL
or [ebx + TCP_SOCKET.timer_flags], timer_flag_wait
 
;-----------------------------------------------------------------------------------
;
; Finally, drop the segment
;
;-----------------------------------------------------------------------------------
 
.final_processing:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Final processing\n"
 
push ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
pop eax
 
test [temp_bits], TCP_BIT_NEEDOUTPUT
jnz .need_output
 
test [eax + TCP_SOCKET.t_flags], TF_ACKNOW
jz .done
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: ACK now!\n"
 
.need_output:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: need output\n"
call tcp_output
 
.done:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: dumping\n"
 
call net_buff_free
jmp .loop
 
;-----------------------------------------------------------------------------------
;
; Drop segment, reply with an RST segment when needed
;
;-----------------------------------------------------------------------------------
 
;-----------------------------------------------------------------------------------
.drop_after_ack:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Drop after ACK\n"
 
push edx ebx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
pop eax edx
 
test [edx + TCP_header.Flags], TH_RST
jnz .done
 
or [eax + TCP_SOCKET.t_flags], TF_ACKNOW
jmp .need_output
 
;-----------------------------------------------------------------------------------
.drop_with_reset:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Drop with reset\n"
 
push ebx edx
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
pop edx ebx
 
test [edx + TCP_header.Flags], TH_RST
jnz .done
 
; TODO: if its a multicast/broadcast, also drop
 
test [edx + TCP_header.Flags], TH_ACK
jnz .respond_ack
 
test [edx + TCP_header.Flags], TH_SYN
jnz .respond_syn
jmp .done
 
.respond_ack:
push ebx
mov cl, TH_RST
call tcp_respond
pop ebx
jmp .destroy_new_socket
 
.respond_syn:
push ebx
mov cl, TH_RST + TH_ACK
call tcp_respond
pop ebx
jmp .destroy_new_socket
 
;-----------------------------------------
; The connection has no associated socket
 
.no_socket:
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
.respond_seg_reset:
test [edx + TCP_header.Flags], TH_RST
jnz .drop_no_socket
 
; TODO: if its a multicast/broadcast, also drop
 
test [edx + TCP_header.Flags], TH_ACK
jnz .respond_seg_ack
 
test [edx + TCP_header.Flags], TH_SYN
jnz .respond_seg_syn
 
jmp .drop_no_socket
 
.respond_seg_ack:
mov cl, TH_RST
mov ebx, [device]
call tcp_respond_segment
jmp .drop_no_socket
 
.respond_seg_syn:
mov cl, TH_RST + TH_ACK
mov ebx, [device]
call tcp_respond_segment
jmp .drop_no_socket
 
;------------------------------------------------
; Unlock socket mutex and prepare to drop segment
 
.drop:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Dropping segment\n"
 
pusha
lea ecx, [ebx + SOCKET.mutex]
call mutex_unlock
popa
 
;--------------------------------------------
; Destroy the newly created socket if needed
 
.destroy_new_socket:
test [temp_bits], TCP_BIT_DROPSOCKET
jz .drop_no_socket
 
mov eax, ebx
call socket_free
 
;------------------
; Drop the segment
 
.drop_no_socket:
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_input: Drop (no socket)\n"
 
call net_buff_free
jmp .loop
 
endp
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/ARP.inc
0,0 → 1,676
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; ARP.INC ;;
;; ;;
;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;;
;; Based on the work of [Johnny_B] and [smb] ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June- 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
ARP_NO_ENTRY = 0
ARP_VALID_MAPPING = 1
ARP_AWAITING_RESPONSE = 2
ARP_RESPONSE_TIMEOUT = 3
 
ARP_REQUEST_TTL = 31 ; 20 s
ARP_ENTRY_TTL = 937 ; 600 s
ARP_STATIC_ENTRY = -1
 
ARP_REQ_OPCODE = 0x0100 ; request
ARP_REP_OPCODE = 0x0200 ; reply
 
ARP_TABLE_SIZE = 20 ; Size of table
 
struct ARP_entry
 
IP dd ?
MAC dp ?
Status dw ?
TTL dw ?
 
ends
 
struct ARP_header
 
HardwareType dw ?
ProtocolType dw ?
HardwareSize db ?
ProtocolSize db ?
Opcode dw ?
SenderMAC dp ?
SenderIP dd ?
TargetMAC dp ?
TargetIP dd ?
 
ends
 
uglobal
align 4
 
ARP_table rb NET_DEVICES_MAX*(ARP_TABLE_SIZE * sizeof.ARP_entry)
 
ARP_entries rd NET_DEVICES_MAX
ARP_packets_tx rd NET_DEVICES_MAX
ARP_packets_rx rd NET_DEVICES_MAX
ARP_conflicts rd NET_DEVICES_MAX
 
 
endg
 
 
 
;-----------------------------------------------------------------;
; ;
; arp_init: Resets all ARP variables. ;
; ;
;-----------------------------------------------------------------;
macro arp_init {
 
xor eax, eax
mov edi, ARP_entries
mov ecx, 4*NET_DEVICES_MAX
rep stosd
 
}
 
;-----------------------------------------------------------------;
; ;
; arp_decrease_entry_ttls ;
; ;
;-----------------------------------------------------------------;
macro arp_decrease_entry_ttls {
 
local .loop
local .exit
 
; The TTL field is decremented every second, and is deleted when it reaches 0.
; It is refreshed every time a packet is received.
; If the TTL field is 0xFFFF it is a static entry and is never deleted.
; The status field can be the following values:
; 0x0000 entry not used
; 0x0001 entry holds a valid mapping
; 0x0002 entry contains an IP address, awaiting ARP response
; 0x0003 No response received to ARP request.
; The last status value is provided to allow the network layer to delete
; a packet that is queued awaiting an ARP response
 
xor edi, edi
.loop_outer:
mov ecx, [ARP_entries + 4*edi]
test ecx, ecx
jz .exit
 
mov esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)
imul esi, edi
add esi, ARP_table
.loop:
cmp [esi + ARP_entry.TTL], ARP_STATIC_ENTRY
je .next
 
dec [esi + ARP_entry.TTL]
jz .time_out
 
.next:
add esi, sizeof.ARP_entry
dec ecx
jnz .loop
jmp .exit
 
.time_out:
cmp [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE
je .response_timeout
 
push esi edi ecx
call arp_del_entry
pop ecx edi esi
 
jmp .next
 
.response_timeout:
mov [esi + ARP_entry.Status], ARP_RESPONSE_TIMEOUT
mov [esi + ARP_entry.TTL], 10
 
jmp .next
 
.exit:
inc edi
cmp edi, NET_DEVICES_MAX
jb .loop_outer
 
}
 
 
;-----------------------------------------------------------------;
; ;
; arp_input ;
; ;
; IN: [esp] = Pointer to buffer ;
; [esp+4] = size of buffer ;
; ecx = packet size (without ethernet header) ;
; edx = packet ptr ;
; ebx = device ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
arp_input:
 
;-----------------------------------------
; Check validity and print some debug info
 
cmp ecx, sizeof.ARP_header
jb .exit
 
call net_ptr_to_num4
cmp edi, -1
jz .exit
 
inc [ARP_packets_rx + edi] ; update stats
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: got packet from %u.%u.%u.%u (device*4=%u)\n",\
[edx + ARP_header.SenderIP]:1, [edx + ARP_header.SenderIP + 1]:1,\
[edx + ARP_header.SenderIP + 2]:1, [edx + ARP_header.SenderIP + 3]:1, edi
 
;------------------------------
; First, check for IP collision
 
mov eax, [edx + ARP_header.SenderIP]
cmp eax, [IPv4_address + edi]
je .collision
 
;---------------------
; Handle reply packets
 
cmp [edx + ARP_header.Opcode], ARP_REP_OPCODE
jne .maybe_request
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: It's a reply\n"
 
mov ecx, [ARP_entries + edi]
test ecx, ecx
jz .exit
 
mov esi, edi
imul esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)/4
add esi, ARP_table
.loop:
cmp [esi + ARP_entry.IP], eax
je .gotit
add esi, sizeof.ARP_entry
dec ecx
jnz .loop
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: no matching entry found\n"
jmp .exit
 
.gotit:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: found matching entry\n"
 
cmp [esi + ARP_entry.TTL], ARP_STATIC_ENTRY ; if it is a static entry, dont touch it
je .exit
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: updating entry\n"
 
mov [esi + ARP_entry.Status], ARP_VALID_MAPPING
mov [esi + ARP_entry.TTL], ARP_ENTRY_TTL
 
mov eax, dword [edx + ARP_header.SenderMAC]
mov dword [esi + ARP_entry.MAC], eax
mov cx, word [edx + ARP_header.SenderMAC + 4]
mov word [esi + ARP_entry.MAC + 4], cx
 
jmp .exit
 
;-----------------------
; Handle request packets
 
.maybe_request:
cmp [edx + ARP_header.Opcode], ARP_REQ_OPCODE
jne .exit
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: its a request\n"
 
mov eax, [IPv4_address + edi]
cmp eax, [edx + ARP_header.TargetIP] ; Is it looking for my IP address?
jne .exit
 
push eax
push edi
 
; OK, it is a request for one of our MAC addresses.
; Build the frame and send it. We can reuse the buffer. (faster then using ARP_create_packet)
 
lea esi, [edx + ARP_header.SenderMAC]
lea edi, [edx + ARP_header.TargetMAC]
movsd ; Move Sender Mac to Dest MAC
movsw ;
movsd ; Move sender IP to Dest IP
 
pop esi
mov esi, [net_device_list + esi]
lea esi, [esi + ETH_DEVICE.mac]
lea edi, [edx + ARP_header.SenderMAC]
movsd ; Copy MAC address from in MAC_LIST
movsw ;
pop eax
stosd ; Write our IP
 
mov [edx + ARP_header.Opcode], ARP_REP_OPCODE
 
; Now, Fill in ETHERNET header
 
mov edi, [esp]
add edi, [edi + NET_BUFF.offset]
lea esi, [edx + ARP_header.TargetMAC]
movsd
movsw
lea esi, [edx + ARP_header.SenderMAC]
movsd
movsw
; mov ax , ETHER_ARP ; It's already there, I'm sure of it!
; stosw
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: Sending reply\n"
 
call [ebx + NET_DEVICE.transmit]
ret
 
.collision:
inc [ARP_conflicts + edi]
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: IP address conflict detected!\n"
 
.exit:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_input: exiting\n"
call net_buff_free
ret
 
;-----------------------------------------------------------------;
; ;
; arp_output_request ;
; ;
; IN: ebx = device ptr ;
; eax = IP ;
; ;
; OUT: scratched: probably everything ;
; ;
;-----------------------------------------------------------------;
align 4
arp_output_request:
 
push eax
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u device=0x%x\n",\
[esp]:1, [esp + 1]:1, [esp + 2]:1, [esp + 3]:1, ebx
 
mov ax, ETHER_PROTO_ARP
mov ecx, sizeof.ARP_header
mov edx, ETH_BROADCAST ; broadcast mac
call eth_output
jz .exit
 
mov [edi + ARP_header.HardwareType], 0x0100 ; Ethernet
mov [edi + ARP_header.ProtocolType], 0x0008 ; IP
mov [edi + ARP_header.HardwareSize], 6 ; MAC-addr length
mov [edi + ARP_header.ProtocolSize], 4 ; IP-addr length
mov [edi + ARP_header.Opcode], ARP_REQ_OPCODE ; Request
 
add edi, ARP_header.SenderMAC
lea esi, [ebx + ETH_DEVICE.mac] ; SenderMac
movsw ;
movsd ;
 
push edi
call net_ptr_to_num4
inc [ARP_packets_tx + edi] ; assume we will succeed
lea esi, [IPv4_address + edi] ; SenderIP
pop edi
movsd
 
mov esi, ETH_BROADCAST ; DestMac
movsw ;
movsd ;
popd [edi] ; DestIP
 
push eax
call [ebx + NET_DEVICE.transmit]
ret
 
.exit:
add esp, 4
DEBUGF DEBUG_NETWORK_ERROR, "ARP_output_request: send failed\n"
ret
 
 
;-----------------------------------------------------------------;
; ;
; arp_add_entry: Add or update an entry in the ARP table. ;
; ;
; IN: esi = ptr to entry (can easily be made on the stack) ;
; edi = device num*4 ;
; ;
; OUT: eax = entry number on success ;
; eax = -1 on error ;
; esi = ptr to newly created entry ;
; ;
;-----------------------------------------------------------------;
align 4
arp_add_entry:
 
; TODO: use a mutex to lock ARP table
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_add_entry: device=%u\n", edi
 
mov ecx, [ARP_entries + edi]
cmp ecx, ARP_TABLE_SIZE ; list full ?
jae .full
 
; From this point on, we can only fail if IP has a static entry, or if table is corrupt.
 
inc [ARP_entries + edi] ; assume we will succeed
 
push edi
xor ecx, ecx
imul edi, ARP_TABLE_SIZE*sizeof.ARP_entry/4
add edi, ARP_table
mov eax, [esi + ARP_entry.IP]
.loop:
cmp [edi + ARP_entry.Status], ARP_NO_ENTRY ; is this slot empty?
je .add
 
cmp [edi + ARP_entry.IP], eax ; if not, check if it doesnt collide
jne .maybe_next
 
cmp [edi + ARP_entry.TTL], ARP_STATIC_ENTRY ; ok, its the same IP, update it if not static
jne .add
 
DEBUGF DEBUG_NETWORK_ERROR, "ARP_add_entry: failed, IP already has a static entry\n"
jmp .error
 
.maybe_next: ; try the next slot
add edi, sizeof.ARP_entry
inc ecx
cmp ecx, ARP_TABLE_SIZE
jb .loop
 
.add:
push ecx
mov ecx, sizeof.ARP_entry/2
rep movsw
pop ecx
lea esi, [edi - sizeof.ARP_entry]
pop edi
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_add_entry: entry=%u\n", ecx
 
ret
 
.error:
pop edi
dec [ARP_entries + edi]
DEBUGF DEBUG_NETWORK_ERROR, "ARP_add_entry_failed\n"
.full:
mov eax, -1
ret
 
 
;-----------------------------------------------------------------;
; ;
; arp_del_entry: Remove an entry from the ARP table. ;
; ;
; IN: esi = ptr to arp entry ;
; edi = device number ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
arp_del_entry:
 
; TODO: use a mutex to lock ARP table
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_del_entry: entry=0x%x entrys=%u\n", esi, [ARP_entries + 4*edi]
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_del_entry: IP=%u.%u.%u.%u\n", \
[esi + ARP_entry.IP]:1, [esi + ARP_entry.IP + 1]:1, [esi + ARP_entry.IP + 2]:1, [esi + ARP_entry.IP + 3]:1
 
push edi
imul edi, (ARP_TABLE_SIZE) * sizeof.ARP_entry
lea ecx, [ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry + edi]
sub ecx, esi
shr ecx, 1
 
; move all trailing entries, sizeof.ARP_entry bytes to left.
mov edi, esi
add esi, sizeof.ARP_entry
rep movsw
 
; now add an empty entry to the end (erasing previous one)
xor eax, eax
mov ecx, sizeof.ARP_entry/2
rep stosw
 
pop edi
dec [ARP_entries + 4*edi]
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_del_entry: success\n"
 
ret
 
 
 
 
 
;-----------------------------------------------------------------;
; ;
; arp_ip_to_mac: Translate an IP address to a MAC address. ;
; ;
; IN: eax = IPv4 address ;
; edi = device number * 4 ;
; ;
; OUT: eax = -1 on error ;
; eax = -2 when request send ;
; eax = first two bytes of mac on success ;
; ebx = last four bytes of mac on success ;
; edi = unchanged ;
; ;
;-----------------------------------------------------------------;
align 4
arp_ip_to_mac:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: %u.%u", al, ah
rol eax, 16
DEBUGF DEBUG_NETWORK_VERBOSE, ".%u.%u device*4: %u\n", al, ah, edi
rol eax, 16
 
cmp eax, 0xffffffff
je .broadcast
 
;--------------------------------
; Try to find the IP in ARP_table
 
mov ecx, [ARP_entries + edi]
test ecx, ecx
jz .not_in_list
mov esi, edi
imul esi, (sizeof.ARP_entry * ARP_TABLE_SIZE)/4
add esi, ARP_table + ARP_entry.IP
.scan_loop:
cmp [esi], eax
je .found_it
add esi, sizeof.ARP_entry
dec ecx
jnz .scan_loop
 
.not_in_list:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: preparing for ARP request\n"
 
push eax edi ; save IP for ARP_output_request
; Now craft the ARP entry on the stack
pushw ARP_REQUEST_TTL ; TTL
pushw ARP_AWAITING_RESPONSE ; status
pushd 0 ; mac
pushw 0
pushd eax ; IP
mov esi, esp
 
; Add it to the list
call arp_add_entry
 
; Delete the temporary entry
add esp, sizeof.ARP_entry ; clear the entry from stack
 
; If we could not add it to the list, give up
cmp eax, -1 ; did ARP_add_entry fail?
je .full
 
;-----------------------------------------------
; At this point, we got an ARP entry in the list
 
; Now send a request packet on the network
pop edi eax ; IP in eax, device number in ebx, for ARP_output_request
 
push esi edi
mov ebx, [net_device_list + edi]
call arp_output_request
pop edi esi
.found_it:
cmp [esi + ARP_entry.Status], ARP_VALID_MAPPING ; Does it have a MAC assigned?
je .valid
 
if ARP_BLOCK
 
cmp [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE ; Are we waiting for reply from remote end?
jne .give_up
push esi
mov esi, 10 ; wait 10 ms
call delay_ms
pop esi
jmp .found_it ; now check again
 
else
 
jmp .give_up
 
end if
 
.valid:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: found MAC\n"
movzx eax, word[esi + ARP_entry.MAC]
mov ebx, dword[esi + ARP_entry.MAC + 2]
ret
 
.full:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: table is full!\n"
add esp, 8
.give_up:
DEBUGF DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: entry has no valid mapping!\n"
mov eax, -1
ret
 
.broadcast:
mov eax, 0x0000ffff
mov ebx, 0xffffffff
ret
 
 
;-----------------------------------------------------------------;
; ;
; arp_api: Part of system function 76. ;
; ;
; IN: bl = subfunction number ;
; bh = device number ;
; ecx, edx, .. depends on subfunction ;
; ;
; OUT: depends on subfunction ;
; ;
;-----------------------------------------------------------------;
align 4
arp_api:
 
movzx eax, bh
shl eax, 2
 
and ebx, 0xff
cmp ebx, .number
ja .error
jmp dword [.table + 4*ebx]
 
.table:
dd .packets_tx ; 0
dd .packets_rx ; 1
dd .entries ; 2
dd .read ; 3
dd .write ; 4
dd .remove ; 5
dd .send_announce ; 6
dd .conflicts ; 7
.number = ($ - .table) / 4 - 1
 
.error:
mov eax, -1
ret
 
.packets_tx:
mov eax, [ARP_packets_tx + eax]
ret
 
.packets_rx:
mov eax, [ARP_packets_rx + eax]
ret
 
.conflicts:
mov eax, [ARP_conflicts + eax]
ret
 
.entries:
mov eax, [ARP_entries + eax]
ret
 
.read:
cmp ecx, [ARP_entries + eax]
jae .error
shr eax, 2
imul eax, sizeof.ARP_entry*ARP_TABLE_SIZE
add eax, ARP_table
; edi = pointer to buffer
; ecx = # entry
imul ecx, sizeof.ARP_entry
lea esi, [eax + ecx]
mov ecx, sizeof.ARP_entry/2
rep movsw
 
xor eax, eax
ret
 
.write:
; esi = pointer to buffer
mov edi, eax
call arp_add_entry ; out: eax = entry number, -1 on error
ret
 
.remove:
; ecx = # entry
cmp ecx, [ARP_entries + eax]
jae .error
imul ecx, sizeof.ARP_entry
lea esi, [ARP_table + ecx]
mov edi, eax
shr edi, 2
call arp_del_entry
ret
 
.send_announce:
mov ebx, [net_device_list + eax]
mov eax, [IPv4_address + eax]
call arp_output_request ; now send a gratuitous ARP
ret
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/udp.inc
0,0 → 1,434
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; UDP.INC ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
struct UDP_header
 
SourcePort dw ?
DestinationPort dw ?
Length dw ? ; Length of (UDP Header + Data)
Checksum dw ?
 
ends
 
 
uglobal
align 4
 
UDP_packets_tx rd NET_DEVICES_MAX
UDP_packets_rx rd NET_DEVICES_MAX
 
endg
 
 
;-----------------------------------------------------------------;
; ;
; udp_init: This function resets all UDP variables ;
; ;
;-----------------------------------------------------------------;
macro udp_init {
 
xor eax, eax
mov edi, UDP_packets_tx
mov ecx, 2*NET_DEVICES_MAX
rep stosd
}
 
 
macro udp_checksum IP1, IP2 { ; esi = ptr to udp packet, ecx = packet size, destroys: ecx, edx
 
; Pseudoheader
mov edx, IP_PROTO_UDP
 
add dl, byte[IP1+1]
adc dh, byte[IP1+0]
adc dl, byte[IP1+3]
adc dh, byte[IP1+2]
 
adc dl, byte[IP2+1]
adc dh, byte[IP2+0]
adc dl, byte[IP2+3]
adc dh, byte[IP2+2]
 
adc dl, cl ; byte[esi+UDP_header.Length+1]
adc dh, ch ; byte[esi+UDP_header.Length+0]
 
; Done with pseudoheader, now do real header
adc dl, byte[esi+UDP_header.SourcePort+1]
adc dh, byte[esi+UDP_header.SourcePort+0]
 
adc dl, byte[esi+UDP_header.DestinationPort+1]
adc dh, byte[esi+UDP_header.DestinationPort+0]
 
adc dl, byte[esi+UDP_header.Length+1]
adc dh, byte[esi+UDP_header.Length+0]
 
adc edx, 0
 
; Done with header, now do data
push esi
movzx ecx, [esi+UDP_header.Length]
rol cx , 8
sub cx , sizeof.UDP_header
add esi, sizeof.UDP_header
 
call checksum_1
call checksum_2
pop esi
 
add [esi+UDP_header.Checksum], dx ; this final instruction will set or clear ZF :)
 
}
 
 
;-----------------------------------------------------------------;
; ;
; udp_input: Inject the UDP data in the application sockets. ;
; ;
; IN: [esp] = ptr to buffer ;
; ebx = ptr to device struct ;
; ecx = UDP packet size ;
; edx = ptr to IPv4 header ;
; esi = ptr to UDP packet data ;
; edi = interface number*4 ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
udp_input:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: size=%u\n", ecx
 
; First validate, checksum
 
neg [esi + UDP_header.Checksum] ; substract checksum from 0
jz .no_checksum ; if checksum is zero, it is considered valid
 
; otherwise, we will re-calculate the checksum and add it to this value, thus creating 0 when it is correct
 
mov eax, edx
udp_checksum (eax+IPv4_header.SourceAddress), (eax+IPv4_header.DestinationAddress)
jnz .checksum_mismatch
 
.no_checksum:
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: checksum ok\n"
 
; Convert length to little endian
 
rol [esi + UDP_header.Length], 8
 
; Look for a socket where
; IP Packet UDP Destination Port = local Port
; IP Packet SA = Remote IP
 
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
mov cx, [esi + UDP_header.SourcePort]
mov dx, [esi + UDP_header.DestinationPort]
mov eax, net_sockets
.next_socket:
mov eax, [eax + SOCKET.NextPtr]
or eax, eax
jz .unlock_dump
 
cmp [eax + SOCKET.Domain], AF_INET4
jne .next_socket
 
cmp [eax + SOCKET.Protocol], IP_PROTO_UDP
jne .next_socket
 
cmp [eax + UDP_SOCKET.LocalPort], dx
jne .next_socket
 
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: socket=%x\n", eax
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
;;; TODO: when packet is processed, check more sockets?!
 
; FIXME: check remote IP if possible
;
; cmp [eax + IP_SOCKET.RemoteIP], 0xffffffff
; je @f
; cmp [eax + IP_SOCKET.RemoteIP],
; jne .next_socket
; @@:
 
cmp [eax + UDP_SOCKET.RemotePort], 0
je .updateport
 
cmp [eax + UDP_SOCKET.RemotePort], cx
jne .dump
 
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
popa
 
.updatesock:
inc [UDP_packets_rx + edi]
 
movzx ecx, [esi + UDP_header.Length]
sub ecx, sizeof.UDP_header
add esi, sizeof.UDP_header
 
jmp socket_input
 
.updateport:
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: new remote port=%x\n", cx ; FIXME: find a way to print big endian values with debugf
mov [eax + UDP_SOCKET.RemotePort], cx
jmp .updatesock
 
.unlock_dump:
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: no socket found\n"
jmp .dump
 
.checksum_mismatch:
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: checksum mismatch\n"
 
.dump:
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_input: dumping\n"
call net_buff_free
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; udp_output: Create an UDP packet. ;
; ;
; IN: eax = socket pointer ;
; ecx = number of bytes to send ;
; esi = pointer to data ;
; ;
; OUT: eax = -1 on error ;
; ;
;-----------------------------------------------------------------;
 
align 4
udp_output:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_output: socket=%x bytes=%u data_ptr=%x\n", eax, ecx, esi
 
mov dx, [eax + UDP_SOCKET.RemotePort]
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_output: remote port=%x, ", dx ; FIXME: find a way to print big endian values with debugf
rol edx, 16
mov dx, [eax + UDP_SOCKET.LocalPort]
DEBUGF DEBUG_NETWORK_VERBOSE, "local port=%x\n", dx
 
sub esp, 4 ; Data ptr will be placed here
push edx esi
mov ebx, [eax + IP_SOCKET.device]
mov edx, [eax + IP_SOCKET.LocalIP]
mov edi, [eax + IP_SOCKET.RemoteIP]
mov al, [eax + IP_SOCKET.ttl]
mov ah, IP_PROTO_UDP
add ecx, sizeof.UDP_header
call ipv4_output
jz .fail
mov [esp + 8], eax ; pointer to buffer start
 
mov [edi + UDP_header.Length], cx
rol [edi + UDP_header.Length], 8
 
pop esi
push edi ecx
sub ecx, sizeof.UDP_header
add edi, sizeof.UDP_header
shr ecx, 2
rep movsd
mov ecx, [esp]
and ecx, 3
rep movsb
pop ecx edi
 
pop dword [edi + UDP_header.SourcePort]
 
; Checksum
mov esi, edi
mov [edi + UDP_header.Checksum], 0
udp_checksum (edi-4), (edi-8) ; FIXME: IPv4 packet could have options..
 
DEBUGF DEBUG_NETWORK_VERBOSE, "UDP_output: sending with device %x\n", ebx
call [ebx + NET_DEVICE.transmit]
test eax, eax
jnz @f
call net_ptr_to_num4
inc [UDP_packets_tx + edi]
@@:
 
ret
 
.fail:
DEBUGF DEBUG_NETWORK_ERROR, "UDP_output: failed\n"
add esp, 4+4+8
or eax, -1
ret
 
 
 
 
;-----------------------------------------------------------------;
; ;
; udp_connect ;
; ;
; IN: eax = socket pointer ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = error code on error ;
; ;
;-----------------------------------------------------------------;
align 4
udp_connect:
 
test [eax + SOCKET.state], SS_ISCONNECTED
jz @f
call udp_disconnect
@@:
 
push eax edx
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
pop edx eax
 
; Fill in remote port and IP
pushw [edx + 2]
pop [eax + UDP_SOCKET.RemotePort]
 
pushd [edx + 4]
pop [eax + UDP_SOCKET.RemoteIP]
 
; Find route to host
pusha
push eax
mov ebx, [eax + UDP_SOCKET.device]
mov edx, [eax + UDP_SOCKET.LocalIP]
mov eax, [eax + UDP_SOCKET.RemoteIP]
call ipv4_route
test eax, eax
jz .enoroute
pop eax
mov ebx, [net_device_list + edi]
mov [eax + UDP_SOCKET.device], ebx
mov [eax + UDP_SOCKET.LocalIP], edx
popa
 
; Find a local port, if user didnt define one
cmp [eax + UDP_SOCKET.LocalPort], 0
jne @f
call socket_find_port
@@:
 
push eax
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
pop eax
 
call socket_is_connected
 
xor eax, eax
ret
 
.enoroute:
pop eax
 
push eax
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
pop eax
 
popa
xor eax, eax
dec eax
mov ebx, EADDRNOTAVAIL
ret
 
 
;-----------------------------------------------------------------;
; ;
; UDP_disconnect ;
; ;
; IN: eax = socket pointer ;
; ;
; OUT: eax = socket pointer ;
; ;
;-----------------------------------------------------------------;
align 4
udp_disconnect:
 
; TODO: remove the pending received data
 
call socket_is_disconnected
 
ret
 
 
 
 
 
;-----------------------------------------------------------------;
; ;
; UDP_api: Part of system function 76 ;
; ;
; IN: bl = subfunction number in bl ;
; bh = device number in bh ;
; ecx, edx, .. depends on subfunction ;
; ;
; OUT: depends on subfunction ;
; ;
;-----------------------------------------------------------------;
align 4
udp_api:
 
movzx eax, bh
shl eax, 2
 
test bl, bl
jz .packets_tx ; 0
dec bl
jz .packets_rx ; 1
 
.error:
mov eax, -1
ret
 
.packets_tx:
mov eax, [UDP_packets_tx + eax]
ret
 
.packets_rx:
mov eax, [UDP_packets_rx + eax]
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/IPv4.inc
0,0 → 1,1161
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; IPv4.INC ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Based on the work of [Johnny_B] and [smb] ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
IPv4_MAX_FRAGMENTS = 64
IPv4_MAX_ROUTES = 64
 
IPv4_ROUTE_FLAG_UP = 1 shl 0
IPv4_ROUTE_FLAG_GATEWAY = 1 shl 1
IPv4_ROUTE_FLAG_HOST = 1 shl 2
IPv4_ROUTE_FLAG_D = 1 shl 3 ; Route was created by a redirect
IPv4_ROUTE_FLAG_M = 1 shl 4 ; Route was modified by a redirect
 
struct IPv4_header
 
VersionAndIHL db ? ; Version[0-3 bits] and IHL(header length)[4-7 bits]
TypeOfService db ? ; precedence [7-5] minimize delay [4], maximize throughput [3], maximize riliability [2] minimize momentary cost [1] and zero [0]
TotalLength dw ?
Identification dw ?
FlagsAndFragmentOffset dw ? ; Flags[0-2] and FragmentOffset[3-15]
TimeToLive db ? ;
Protocol db ?
HeaderChecksum dw ?
SourceAddress dd ?
DestinationAddress dd ?
 
ends
 
struct IPv4_FRAGMENT_slot
 
ttl dw ? ; Time to live for this entry, 0 for empty slot's
id dw ? ; Identification field from IP header
SrcIP dd ? ; .. from IP header
DstIP dd ? ; .. from IP header
ptr dd ? ; Pointer to first packet
 
ends
 
struct IPv4_FRAGMENT_entry ; This structure will replace the ethernet header in fragmented ip packets
 
PrevPtr dd ? ; Pointer to previous fragment entry (-1 for first packet)
NextPtr dd ? ; Pointer to next fragment entry (-1 for last packet)
Owner dd ? ; Pointer to structure of driver
rb 2 ; to match ethernet header size ;;; FIXME
; Ip header begins here (we will need the IP header to re-construct the complete packet)
ends
 
;struct IPv4_ROUTE
;
; Destination dd ?
; Gateway dd ?
; Flags dd ?
; Use dd ?
; Interface dd ?
;
;ends
 
uglobal
align 4
 
IPv4_address rd NET_DEVICES_MAX
IPv4_subnet rd NET_DEVICES_MAX
IPv4_nameserver rd NET_DEVICES_MAX
IPv4_gateway rd NET_DEVICES_MAX
IPv4_broadcast rd NET_DEVICES_MAX
 
IPv4_packets_tx rd NET_DEVICES_MAX
IPv4_packets_rx rd NET_DEVICES_MAX
IPv4_packets_dumped rd NET_DEVICES_MAX
 
IPv4_fragments rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot
 
; IPv4_routes rd IPv4_MAX_ROUTES * sizeof.IPv4_ROUTE
 
endg
 
 
;-----------------------------------------------------------------;
; ;
; ipv4_init: Resets all IPv4 variables ;
; ;
;-----------------------------------------------------------------;
macro ipv4_init {
 
xor eax, eax
mov edi, IPv4_address
mov ecx, 7*NET_DEVICES_MAX + (sizeof.IPv4_FRAGMENT_slot*IPv4_MAX_FRAGMENTS)/4
rep stosd
 
}
 
 
;-----------------------------------------------------------------;
; ;
; Decrease TimeToLive of all fragment slots ;
; ;
;-----------------------------------------------------------------;
macro ipv4_decrease_fragment_ttls {
 
local .loop, .next
 
mov esi, IPv4_fragments
mov ecx, IPv4_MAX_FRAGMENTS
.loop:
cmp [esi + IPv4_FRAGMENT_slot.ttl], 0
je .next
dec [esi + IPv4_FRAGMENT_slot.ttl]
jz .died
.next:
add esi, sizeof.IPv4_FRAGMENT_slot
dec ecx
jnz .loop
jmp .done
 
.died:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4 Fragment slot timed-out!\n"
;;; TODO: clear all entry's of timed-out slot
jmp .next
 
.done:
}
 
 
 
macro ipv4_checksum ptr {
 
; This is the fast procedure to create or check an IP header without options
; To create a new checksum, the checksum field must be set to 0 before computation
; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct
 
push ebx
xor ebx, ebx
add bl, [ptr+1]
adc bh, [ptr+0]
 
adc bl, [ptr+3]
adc bh, [ptr+2]
 
adc bl, [ptr+5]
adc bh, [ptr+4]
 
adc bl, [ptr+7]
adc bh, [ptr+6]
 
adc bl, [ptr+9]
adc bh, [ptr+8]
 
; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation
 
adc bl, [ptr+13]
adc bh, [ptr+12]
 
adc bl, [ptr+15]
adc bh, [ptr+14]
 
adc bl, [ptr+17]
adc bh, [ptr+16]
 
adc bl, [ptr+19]
adc bh, [ptr+18]
 
adc ebx, 0
 
push ecx
mov ecx, ebx
shr ecx, 16
and ebx, 0xffff
add ebx, ecx
 
mov ecx, ebx
shr ecx, 16
add ebx, ecx
 
not bx
jnz .not_zero
dec bx
.not_zero:
xchg bl, bh
pop ecx
 
neg word [ptr+10] ; zero will stay zero so we just get the checksum
add word [ptr+10], bx ; , else we will get (new checksum - old checksum) in the end, wich should be 0 :)
pop ebx
 
}
 
 
 
;-----------------------------------------------------------------;
; ;
; ipv4_input: Check if IPv4 Packet isnt damaged and call ;
; appropriate handler. (TCP/UDP/ICMP/..) ;
; We will also re-construct fragmented packets. ;
; ;
; IN: Pointer to buffer in [esp] ;
; pointer to device struct in ebx ;
; pointer to IPv4 header in edx ;
; size of IPv4 packet in ecx ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
ipv4_input:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: packet from %u.%u.%u.%u ",\
[edx + IPv4_header.SourceAddress + 0]:1,[edx + IPv4_header.SourceAddress + 1]:1,\
[edx + IPv4_header.SourceAddress + 2]:1,[edx + IPv4_header.SourceAddress + 3]:1
DEBUGF DEBUG_NETWORK_VERBOSE, "to %u.%u.%u.%u\n",\
[edx + IPv4_header.DestinationAddress + 0]:1,[edx + IPv4_header.DestinationAddress + 1]:1,\
[edx + IPv4_header.DestinationAddress + 2]:1,[edx + IPv4_header.DestinationAddress + 3]:1
 
call net_ptr_to_num4
cmp edi, -1
je .invalid_device
 
;-------------------------------
; re-calculate the checksum
 
ipv4_checksum edx
jnz .dump ; if checksum isn't valid then dump packet
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Checksum ok\n"
 
;--------------------------------
; Check if destination IP matches
 
; local ip (Using RFC1122 strong end system model)
mov eax, [edx + IPv4_header.DestinationAddress]
cmp eax, [IPv4_address + edi]
je .ip_ok
 
; network layer broadcast
cmp eax, [IPv4_broadcast + edi]
je .ip_ok
 
; physical layer broadcast (255.255.255.255)
cmp eax, 0xffffffff
je .ip_ok
 
; multicast (224.0.0.0/4 = 224.0.0.0 to 239.255.255.255)
and eax, 0x0fffffff
cmp eax, 224
je .ip_ok
 
; maybe we just dont have an IP yet and should accept everything on the IP level
cmp [IPv4_address + edi], 0
je .ip_ok
 
; or it's just not meant for us.. :(
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Destination address does not match!\n"
jmp .dump
 
;------------------------
; Now we can update stats
 
.ip_ok:
inc [IPv4_packets_rx + edi]
 
;----------------------------------
; Check if the packet is fragmented
 
test [edx + IPv4_header.FlagsAndFragmentOffset], 1 shl 5 ; Is 'more fragments' flag set ?
jnz .has_fragments ; If so, we definately have a fragmented packet
 
test [edx + IPv4_header.FlagsAndFragmentOffset], 0xff1f ; If flag is not set, but there is a fragment offset, the packet is last in series of fragmented packets
jnz .is_last_fragment
 
;-------------------------------------------------------------------
; No, it's just a regular IP packet, pass it to the higher protocols
 
.handle_it: ; We reach here if packet hasnt been fragmented, or when it already has been re-constructed
 
movzx esi, [edx + IPv4_header.VersionAndIHL] ; Calculate Header length by using IHL field
and esi, 0x0000000f ;
shl esi, 2 ;
 
movzx ecx, [edx + IPv4_header.TotalLength] ; Calculate length of encapsulated Packet
xchg cl, ch ;
sub ecx, esi ;
 
mov al, [edx + IPv4_header.Protocol]
add esi, edx ; make esi ptr to data
 
cmp al, IP_PROTO_TCP
je tcp_input
 
cmp al, IP_PROTO_UDP
je udp_input
 
cmp al, IP_PROTO_ICMP
je icmp_input
 
;-------------------------------
; Look for a matching RAW socket
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
add ecx, esi
sub ecx, edx
mov esi, edx
movzx edx, al
mov eax, net_sockets
.next_socket:
mov eax, [eax + SOCKET.NextPtr]
or eax, eax
jz .dump_unlock
 
cmp [eax + SOCKET.Domain], AF_INET4
jne .next_socket
 
cmp [eax + SOCKET.Protocol], edx
jne .next_socket
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: found matching RAW socket: 0x%x\n", eax
 
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
popa
 
jmp socket_input
 
.dump_unlock:
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: unknown protocol %u\n", al
 
.dump:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: dumping\n"
inc [IPv4_packets_dumped + edi]
call net_buff_free
ret
 
.invalid_device:
DEBUGF DEBUG_NETWORK_ERROR, "IPv4_input: packet originated from invalid device\n"
call net_buff_free
ret
 
 
;---------------------------
; Fragmented packet handler
 
 
.has_fragments:
movzx eax, [edx + IPv4_header.FlagsAndFragmentOffset]
xchg al, ah
shl ax, 3
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: fragmented packet offset=%u id=%x ptr=0x%x\n", ax, [edx + IPv4_header.Identification]:4, edx
 
test ax, ax ; Is this the first packet of the fragment?
jz .is_first_fragment
 
 
;-------------------------------------------------------
; We have a fragmented IP packet, but it's not the first
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Middle fragment packet received!\n"
 
call ipv4_find_fragment_slot
cmp esi, -1
je .dump
 
mov [esi + IPv4_FRAGMENT_slot.ttl], 15 ; Reset the ttl
mov esi, [esi + IPv4_FRAGMENT_slot.ptr]
or edi, -1
.find_last_entry: ; The following routine will try to find the last entry
cmp edi, [esi + IPv4_FRAGMENT_entry.PrevPtr]
jne .destroy_slot ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
mov edi, esi
mov esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
cmp esi, -1
jne .find_last_entry
; We found the last entry (pointer is now in edi)
; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
 
pop eax ; pointer to packet
mov [edi + IPv4_FRAGMENT_entry.NextPtr], eax ; update pointer of previous entry to the new entry
mov [eax + IPv4_FRAGMENT_entry.NextPtr], -1
mov [eax + IPv4_FRAGMENT_entry.PrevPtr], edi
mov [eax + IPv4_FRAGMENT_entry.Owner], ebx
 
ret
 
 
;------------------------------------
; We have received the first fragment
 
.is_first_fragment:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: First fragment packet received!\n"
; try to locate a free slot..
mov ecx, IPv4_MAX_FRAGMENTS
mov esi, IPv4_fragments
.find_free_slot:
cmp word [esi + IPv4_FRAGMENT_slot.ttl], 0
je .found_free_slot
add esi, sizeof.IPv4_FRAGMENT_slot
loop .find_free_slot
jmp .dump ; If no free slot was found, dump the packet
 
.found_free_slot: ; We found a free slot, let's fill in the FRAGMENT_slot structure
mov [esi + IPv4_FRAGMENT_slot.ttl], 15 ; RFC recommends 15 secs as ttl
mov ax, [edx + IPv4_header.Identification]
mov [esi + IPv4_FRAGMENT_slot.id], ax
mov eax, [edx + IPv4_header.SourceAddress]
mov [esi + IPv4_FRAGMENT_slot.SrcIP], eax
mov eax, [edx + IPv4_header.DestinationAddress]
mov [esi + IPv4_FRAGMENT_slot.DstIP], eax
pop eax
mov [esi + IPv4_FRAGMENT_slot.ptr], eax
; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
mov [eax + IPv4_FRAGMENT_entry.NextPtr], -1
mov [eax + IPv4_FRAGMENT_entry.PrevPtr], -1
mov [eax + IPv4_FRAGMENT_entry.Owner], ebx
 
ret
 
 
;-----------------------------------
; We have received the last fragment
 
.is_last_fragment:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Last fragment packet received!\n"
 
call ipv4_find_fragment_slot
cmp esi, -1
je .dump
 
mov esi, [esi + IPv4_FRAGMENT_slot.ptr] ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer
push esi
xor eax, eax
or edi, -1
 
.count_bytes:
cmp [esi + IPv4_FRAGMENT_entry.PrevPtr], edi
jne .destroy_slot_pop ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
mov cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength] ; Add total length
xchg cl, ch
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
add ax, cx
movzx cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Sub Header length
and cx, 0x000F
shl cx, 2
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Header size=%u\n", cx
sub ax, cx
mov edi, esi
mov esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
cmp esi, -1
jne .count_bytes
 
mov esi, [esp+4]
mov [edi + IPv4_FRAGMENT_entry.NextPtr], esi ; Add this packet to the chain, this simplifies the following code
mov [esi + IPv4_FRAGMENT_entry.NextPtr], -1
mov [esi + IPv4_FRAGMENT_entry.PrevPtr], edi
mov [esi + IPv4_FRAGMENT_entry.Owner], ebx
 
mov cx, [edx + IPv4_header.TotalLength] ; Note: This time we dont substract Header length
xchg cl, ch
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
add ax, cx
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Received data size=%u\n", eax
 
push eax
mov ax, [edx + IPv4_header.FlagsAndFragmentOffset]
xchg al, ah
shl ax, 3
add cx, ax
pop eax
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Fragment size=%u\n", ecx
 
cmp ax, cx
jne .destroy_slot_pop
 
push eax
push eax
call kernel_alloc
test eax, eax
je .destroy_slot_pop ; If we dont have enough space to allocate the buffer, discard all packets in slot
mov edx, [esp+4] ; Get pointer to first fragment entry back in edx
 
.rebuild_packet_loop:
movzx ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset
xchg cl, ch ; intel byte order
shl cx, 3 ; multiply by 8 and clear first 3 bits
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Fragment offset=%u\n", cx
 
lea edi, [eax + ecx] ; Notice that edi will be equal to eax for first fragment
movzx ebx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL] ; Find header size (in ebx) of fragment
and bx, 0x000F ;
shl bx, 2 ;
 
lea esi, [edx + sizeof.IPv4_FRAGMENT_entry] ; Set esi to the correct begin of fragment
movzx ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength] ; Calculate total length of fragment
xchg cl, ch ; intel byte order
 
cmp edi, eax ; Is this packet the first fragment ?
je .first_fragment
sub cx, bx ; If not, dont copy the header
add esi, ebx ;
.first_fragment:
 
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Copying %u bytes from 0x%x to 0x%x\n", ecx, esi, edi
push cx ; First copy dword-wise, then byte-wise
shr cx, 2 ;
rep movsd ;
pop cx ;
and cx, 3 ;
rep movsb ;
 
push eax
push [edx + IPv4_FRAGMENT_entry.Owner] ; we need to remeber the owner, in case this is the last packet
push [edx + IPv4_FRAGMENT_entry.NextPtr] ; Set edx to the next pointer
push edx ; Push pointer to fragment onto stack
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Next Fragment: 0x%x\n", edx
call net_buff_free ; free the previous fragment buffer (this uses the value from stack)
pop edx ebx eax
cmp edx, -1 ; Check if it is last fragment in chain
jne .rebuild_packet_loop
 
pop ecx
xchg cl, ch
mov edx, eax
mov [edx + IPv4_header.TotalLength], cx
add esp, 12
xchg cl, ch
push ecx edx ; size and pointer
jmp .handle_it ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
 
.destroy_slot_pop:
add esp, 4
.destroy_slot:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_input: Destroy fragment slot!\n"
; TODO!
jmp .dump
 
 
 
 
 
;-----------------------------------------------------------------;
; ;
; ipv4_find_fragment_slot ;
; ;
; IN: pointer to fragmented packet in edx ;
; ;
; OUT: pointer to slot in esi, -1 on error ;
; ;
;-----------------------------------------------------------------;
align 4
ipv4_find_fragment_slot:
 
;;; TODO: the RFC says we should check protocol number too
 
push eax ebx ecx edx
mov ax, [edx + IPv4_header.Identification]
mov ecx, IPv4_MAX_FRAGMENTS
mov esi, IPv4_fragments
mov ebx, [edx + IPv4_header.SourceAddress]
mov edx, [edx + IPv4_header.DestinationAddress]
.find_slot:
cmp [esi + IPv4_FRAGMENT_slot.id], ax
jne .try_next
cmp [esi + IPv4_FRAGMENT_slot.SrcIP], ebx
jne .try_next
cmp [esi + IPv4_FRAGMENT_slot.DstIP], edx
je .found_slot
.try_next:
add esi, sizeof.IPv4_FRAGMENT_slot
loop .find_slot
 
or esi, -1
.found_slot:
pop edx ecx ebx eax
ret
 
 
;------------------------------------------------------------------;
; ;
; ipv4_output ;
; ;
; IN: al = protocol ;
; ah = TTL ;
; ebx = device ptr (or 0 to let IP layer decide) ;
; ecx = data length ;
; edx = Source IP ;
; edi = Destination IP ;
; ;
; OUT: eax = pointer to buffer start ;
; eax = 0 on error ;
; ebx = device ptr (send packet through this device) ;
; ecx = data length ;
; edx = size of complete frame ;
; edi = start of IPv4 payload ;
; ;
;------------------------------------------------------------------;
align 4
ipv4_output:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_output: size=%u ip=0x%x\n", ecx, edi
 
cmp ecx, 65500 ; Max IPv4 packet size
ja .too_large
 
push ecx ax edi
mov eax, edi
call ipv4_route ; outputs device number in edi, dest ip in eax, source IP in edx
test eax, eax
jz .no_route
push edx
test edi, edi
jz .loopback
 
call arp_ip_to_mac
test eax, 0xffff0000 ; error bits
jnz .arp_error
push ebx ; push the mac onto the stack
push ax
 
inc [IPv4_packets_tx + edi] ; update stats
 
mov ax, ETHER_PROTO_IPv4
mov ebx, [net_device_list + edi]
mov ecx, [esp + 6 + 8 + 2]
add ecx, sizeof.IPv4_header
mov edx, esp
call eth_output
jz .eth_error
add esp, 6 ; pop the mac out of the stack
 
.continue:
xchg cl, ch ; internet byte order
mov [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
mov [edi + IPv4_header.TypeOfService], 0 ; nothing special, just plain ip packet
mov [edi + IPv4_header.TotalLength], cx
mov [edi + IPv4_header.Identification], 0 ; fragment id: FIXME
mov [edi + IPv4_header.FlagsAndFragmentOffset], 0
 
mov [edi + IPv4_header.HeaderChecksum], 0
popd [edi + IPv4_header.SourceAddress]
popd [edi + IPv4_header.DestinationAddress]
 
pop word[edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol
; [edi + IPv4_header.Protocol]
 
pop ecx
 
ipv4_checksum edi
add edi, sizeof.IPv4_header
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_output: success!\n"
ret
 
.eth_error:
DEBUGF DEBUG_NETWORK_ERROR, "IPv4_output: ethernet error\n"
add esp, 3*4+2+6
xor eax, eax
ret
 
.no_route:
DEBUGF DEBUG_NETWORK_ERROR, "IPv4_output: No route to host!\n"
add esp, 2*4+2
xor eax, eax
ret
 
.arp_error:
DEBUGF DEBUG_NETWORK_ERROR, "IPv4_output: ARP error=%x\n", eax
add esp, 4
pop eax
DEBUGF DEBUG_NETWORK_ERROR, "IPv4_output: ip=0x%x\n", eax
add esp, 4+2
xor eax, eax
ret
 
.too_large:
DEBUGF DEBUG_NETWORK_ERROR, "IPv4_output: Packet too large!\n"
xor eax, eax
ret
 
.loopback:
inc [IPv4_packets_tx + edi] ; update stats
 
mov dword [esp], eax ; set source IP to dest IP
mov ecx, [esp + 10]
add ecx, sizeof.IPv4_header
mov edi, AF_INET4
call loop_output
jmp .continue
 
 
 
 
;------------------------------------------------------------------;
; ;
; ipv4_output_raw ;
; ;
; IN: eax = socket ptr ;
; ecx = data length ;
; esi = data ptr ;
; ;
; OUT: eax = -1 on error ;
; ;
;------------------------------------------------------------------;
align 4
ipv4_output_raw:
 
DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
 
sub esp, 8
push esi eax
 
call ipv4_route
call arp_ip_to_mac
 
test eax, 0xffff0000 ; error bits
jnz .arp_error
 
push ebx ; push the mac
push ax
 
inc [IPv4_packets_tx + 4*edi]
mov ax, ETHER_PROTO_IPv4
mov ebx, [net_device_list + 4*edi]
mov ecx, [esp + 6 + 4]
add ecx, sizeof.IPv4_header
mov edx, esp
call eth_output
jz .error
add esp, 6 ; pop the mac
 
mov dword[esp+4+4], edx
mov dword[esp+4+4+4], eax
 
pop eax esi
;; TODO: check socket options if we should add header, or just compute checksum
 
push edi ecx
rep movsb
pop ecx edi
 
; [edi + IPv4_header.VersionAndIHL] ; IPv4, normal length (no Optional header)
; [edi + IPv4_header.TypeOfService] ; nothing special, just plain ip packet
; [edi + IPv4_header.TotalLength]
; [edi + IPv4_header.TotalLength] ; internet byte order
; [edi + IPv4_header.FlagsAndFragmentOffset]
 
mov [edi + IPv4_header.HeaderChecksum], 0
 
; [edi + IPv4_header.TimeToLive] ; ttl shl 8 + protocol
; [edi + IPv4_header.Protocol]
; [edi + IPv4_header.Identification] ; fragment id
; [edi + IPv4_header.SourceAddress]
; [edi + IPv4_header.DestinationAddress]
 
ipv4_checksum edi ;;;; todo: checksum for IP packet with options!
add edi, sizeof.IPv4_header
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_output_raw: device=%x\n", ebx
call [ebx + NET_DEVICE.transmit]
ret
 
.error:
add esp, 6+8+4+4
mov ebx, ENOBUFS ; FIXME: NOBUFS or MSGSIZE error
or eax, -1
ret
 
.arp_error:
add esp, 8+4+4
mov ebx, ENOTCONN
or eax, -1
ret
 
 
;-----------------------------------------------------------------;
; ;
; ipv4_fragment ;
; ;
; IN: [esp] = ptr to packet buffer to fragment ;
; edi = ptrr to ip header in that buffer ;
; ebx = device ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
proc ipv4_fragment stdcall buffer
 
locals
offset dd ?
headerlength dd ?
headerptr dd ?
dataptr dd ?
remaining dd ?
segmentsize dd ?
endl
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_fragment\n"
 
; We must be able to put at least 8 bytes per segment
movzx eax, byte[edi] ; IHL
and eax, 0xf
shl eax, 2
mov [headerlength], eax
add eax, 8
mov ecx, [ebx + NET_DEVICE.mtu]
and ecx, not 11b
cmp ecx, eax
jb .fail
 
mov [edi + IPv4_header.HeaderChecksum], 0
 
mov [segmentsize], ecx
mov [headerptr], edi
movzx ecx, [edi + IPv4_header.TotalLength]
xchg cl, ch
sub ecx, [headerlength]
mov [remaining], ecx
mov [offset], 0
 
add edi, [headerlength]
mov [dataptr], edi
 
.loop:
DEBUGF DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: new fragment"
 
mov ecx, [segmentsize]
cmp ecx, [remaining]
jbe @f
mov ecx, [remaining]
@@:
 
mov ax, ETHER_PROTO_IPv4
mov edx, [esp]
add edx, [edx + NET_BUFF.offset]
; add edx, ETH_header.DstMAC ; = 0
call ETH_output
jz .fail
 
push edi
mov edx, ecx
 
; copy header
mov esi, [headerptr]
mov ecx, [headerlength]
shr ecx, 2
rep movsd
 
; copy data
mov esi, [dataptr]
add esi, [offset]
mov ecx, edx
sub ecx, [headerlength]
shr ecx, 2
rep movsd
pop edi
 
; now, correct header
; packet length
mov ax, dx
xchg al, ah
mov [edi + IPv4_header.TotalLength], ax
 
; offset
mov eax, [offset]
xchg al, ah
 
sub edx, [headerlength]
sub [remaining], edx
je @f
jb .fail
or ah, 1 shl 2 ; more fragments
add [offset], edx
@@:
mov [edi + IPv4_header.FlagsAndFragmentOffset], ax
 
; Send the fragment
IPv4_checksum edi
call [ebx + NET_DEVICE.transmit]
 
cmp [remaining], 0
jne .loop
 
call NET_BUFF_free
ret
 
.fail:
DEBUGF DEBUG_NETWORK_ERROR, "Ipv4_fragment: failed\n"
call NET_BUFF_free
ret
 
endp
 
 
 
;-----------------------------------------------------------------;
; ;
; ipv4_route ;
; ;
; IN: eax = Destination IP ;
; ebx = outgoing device / 0 ;
; edx = Source IP ;
; ;
; OUT: eax = Destination IP (may be gateway), 0 on error ;
; edx = Source IP ;
; edi = device number*4 ;
; ;
; DESTROYED: ;
; ecx ;
; ;
;-----------------------------------------------------------------;
align 4
ipv4_route:
 
test ebx, ebx
jnz .got_device
 
; Broadcast does not need gateway
cmp eax, 0xffffffff
je .broadcast
 
xor edi, edi
.loop:
mov ebx, [IPv4_address + edi]
and ebx, [IPv4_subnet + edi]
jz .next
mov ecx, eax
and ecx, [IPv4_subnet + edi]
cmp ebx, ecx
je .got_it
.next:
add edi, 4
cmp edi, 4*NET_DEVICES_MAX
jb .loop
 
mov eax, [IPv4_gateway + 4] ; TODO: let user (or a user space daemon) configure default route
.broadcast:
mov edi, 4 ; TODO: same as above
.got_it:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
test edx, edx
jnz @f
mov edx, [IPv4_address + edi]
@@:
 
ret
 
.got_device:
; Validate device ptr and convert to device number
call net_ptr_to_num4
cmp edi, -1
je .fail
 
mov edx, [IPv4_address + edi] ; Source IP
 
; Broadcast does not need gateway
cmp eax, 0xffffffff
je @f
 
; Check if we should route to gateway or not
mov ebx, [IPv4_address + edi]
and ebx, [IPv4_subnet + edi]
mov ecx, eax
and ecx, [IPv4_subnet + edi]
cmp ecx, ebx
je @f
mov eax, [IPv4_gateway + edi]
@@:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
ret
 
.fail:
DEBUGF DEBUG_NETWORK_ERROR, "IPv4_route failed\n"
xor eax, eax
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; ipv4_get_frgmnt_num ;
; ;
; IN: / ;
; ;
; OUT: ax = fragment number ;
; ;
;-----------------------------------------------------------------;
align 4
ipv4_get_frgmnt_num:
xor ax, ax ;;; TODO: replace this with real code
 
ret
 
 
;-----------------------------------------------------------------;
; ;
; ipv4_connect ;
; ;
; IN: eax = socket pointer ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = error code on error ;
; ;
;-----------------------------------------------------------------;
align 4
ipv4_connect:
 
push eax edx
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
pop edx eax
 
; Fill in local IP
cmp [eax + IP_SOCKET.LocalIP], 0
jne @f
push [IPv4_address + 4] ; FIXME: use correct local IP
pop [eax + IP_SOCKET.LocalIP]
 
; Fill in remote IP
pushd [edx + 4]
pop [eax + IP_SOCKET.RemoteIP]
 
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
 
xor eax, eax
ret
 
 
;-----------------------------------------------------------------;
; ;
; ipv4_API: Part of system function 76. ;
; ;
; IN: bl = subfunction number ;
; bh = device number ;
; ecx, edx, .. depends on subfunction ;
; ;
; OUT: depends on subfunction ;
; ;
;-----------------------------------------------------------------;
align 4
ipv4_api:
 
movzx eax, bh
shl eax, 2
 
and ebx, 0x000000ff
cmp ebx, .number
ja .error
jmp dword [.table + 4*ebx]
 
.table:
dd .packets_tx ; 0
dd .packets_rx ; 1
dd .read_ip ; 2
dd .write_ip ; 3
dd .read_dns ; 4
dd .write_dns ; 5
dd .read_subnet ; 6
dd .write_subnet ; 7
dd .read_gateway ; 8
dd .write_gateway ; 9
.number = ($ - .table) / 4 - 1
 
.error:
mov eax, -1
ret
 
.packets_tx:
mov eax, [IPv4_packets_tx + eax]
ret
 
.packets_rx:
mov eax, [IPv4_packets_rx + eax]
ret
 
.read_ip:
mov eax, [IPv4_address + eax]
ret
 
.write_ip:
mov [IPv4_address + eax], ecx
mov edi, eax ; device number, we'll need it for ARP
 
; pre-calculate the local broadcast address
mov ebx, [IPv4_subnet + eax]
not ebx
or ebx, ecx
mov [IPv4_broadcast + eax], ebx
 
mov ebx, [net_device_list + eax]
mov eax, [IPv4_address + eax]
call arp_output_request ; now send a gratuitous ARP
 
call net_send_event
xor eax, eax
ret
 
.read_dns:
mov eax, [IPv4_nameserver + eax]
ret
 
.write_dns:
mov [IPv4_nameserver + eax], ecx
call net_send_event
xor eax, eax
ret
 
.read_subnet:
mov eax, [IPv4_subnet + eax]
ret
 
.write_subnet:
mov [IPv4_subnet + eax], ecx
 
; pre-calculate the local broadcast address
mov ebx, [IPv4_address + eax]
not ecx
or ecx, ebx
mov [IPv4_broadcast + eax], ecx
 
call net_send_event
xor eax, eax
ret
 
.read_gateway:
mov eax, [IPv4_gateway + eax]
ret
 
.write_gateway:
mov [IPv4_gateway + eax], ecx
 
call net_send_event
xor eax, eax
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/PPPoE.inc
0,0 → 1,346
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2012-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; PPPoE.INC ;;
;; ;;
;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
struct PPPoE_frame
VersionAndType db ?
Code db ?
SessionID dw ?
Length dw ? ; Length of payload, does NOT include the length PPPoE header.
Payload rb 0
ends
 
uglobal
align 4
 
PPPoE_SID dw ?
PPPoE_MAC dp ?
 
endg
 
;-----------------------------------------------------------------;
; ;
; pppoe_init: Reset all pppoe variables ;
; ;
;-----------------------------------------------------------------;
macro pppoe_init {
 
call pppoe_stop_connection
 
}
 
 
;-----------------------------------------------------------------;
; ;
; pppoe_discovery_input ;
; ;
; IN: [esp] = ptr to buffer ;
; [esp+4] = size of buffer ;
; ebx = ptr to device struct ;
; ecx = size of PPP packet ;
; edx = ptr to PPP header ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
pppoe_discovery_input:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_discovery_input\n"
 
; First, find open PPPoE socket
 
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
mov eax, net_sockets
 
.next_socket:
mov eax, [eax + SOCKET.NextPtr]
or eax, eax
jz .dump
 
cmp [eax + SOCKET.Domain], AF_PPP
jne .next_socket
 
cmp [eax + SOCKET.Protocol], PPP_PROTO_ETHERNET
jne .next_socket
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
; Now, send it to the this socket
 
mov ecx, [esp + 4]
mov esi, [esp]
 
jmp socket_input
 
.dump:
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, 'PPPoE_discovery_input: dumping\n'
call net_buff_free
ret
 
 
;-----------------------------------------------------------------;
; ;
; pppoe_discovery_output ;
; ;
; IN: eax = socket pointer ;
; ecx = number of bytes to send ;
; esi = pointer to data ;
; ;
;-----------------------------------------------------------------;
align 4
pppoe_discovery_output:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_discovery_output: socket=%x buffer=%x size=%d\n", eax, esi, ecx
 
; RFC2516: An entire PADI packet (including the PPPoE header) MUST NOT
; exceed 1484 octets.
cmp ecx, 1484 + 14
ja .bad
 
; Check that device exists and is ethernet device
mov ebx, [eax + SOCKET.device]
 
cmp ebx, NET_DEVICES_MAX
ja .bad
 
mov ebx, [net_device_list + 4*ebx]
test ebx, ebx
jz .bad
 
cmp [ebx + NET_DEVICE.device_type], NET_DEVICE_ETH
jne .bad
 
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_discovery_output: device=%x\n", ebx
 
; Create packet.
push ecx esi
;;;; FIXME stdcall kernel_alloc, 1500
pop esi ecx
test eax, eax
jz .bad
 
mov edx, ecx
mov edi, eax
rep movsb
 
cmp edx, 60 ; Min ETH size
ja @f
mov edx, 60
@@:
 
push edx eax ; size and packet ptr for driver send proc
 
; Overwrite source MAC and protocol type
lea edi, [eax + ETH_header.SrcMAC]
lea esi, [ebx + ETH_DEVICE.mac]
movsd
movsw
cmp word[edi], ETHER_PROTO_PPP_SESSION ; Allow only PPP_discovery, or LCP
je @f
mov ax, ETHER_PROTO_PPP_DISCOVERY
stosw
@@:
 
; And send the packet
call [ebx + NET_DEVICE.transmit]
 
xor eax, eax
ret
 
.bad:
or eax, -1
ret
 
 
;-----------------------------------------------------------------;
; ;
; pppoe_session_input ;
; ;
; IN: [esp] = ptr to buffer ;
; [esp+4] = size of buffer ;
; ebx = ptr to device struct ;
; edx = ptr to PPP header ;
; ecx = size of PPP packet ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
pppoe_session_input:
 
cmp [edx + PPPoE_frame.VersionAndType], 0x11
jne .dump
 
cmp [edx + PPPoE_frame.Code], 0x00
jne .dump
 
movzx ecx, [edx + PPPoE_frame.Length]
xchg cl, ch
 
mov ax, [edx + PPPoE_frame.SessionID]
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_input: session ID=%x, length=%u\n", ax, cx
cmp ax, [PPPoE_SID]
jne .dump
 
mov ax, word [edx + PPPoE_frame.Payload]
add edx, PPPoE_frame.Payload + 2
 
cmp ax, PPP_PROTO_IPv4
je ipv4_input
 
; cmp ax, PPP_PROTO_IPv6
; je ipv6_input
 
jmp pppoe_discovery_input ; Send LCP,CHAP,CBCP,... packets to the PPP dialer
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_input: Unknown protocol=%x\n", ax
 
.dump:
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_input: dumping\n"
call net_buff_free
ret
 
 
 
;-----------------------------------------------------------------;
; ;
; pppoe_output ;
; ;
; IN: ax = protocol ;
; ebx = device ptr ;
; ecx = packet size ;
; ;
; OUT: eax = buffer start ;
; eax = 0 on error ;
; ebx = device ptr ;
; ecx = packet size ;
; edx = size of complete buffer ;
; edi = start of PPP payload ;
; ;
;-----------------------------------------------------------------;
align 4
pppoe_output:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_output: size=%u device=%x\n", ecx, ebx
 
pushw ax
pushw [PPPoE_SID]
 
mov ax, ETHER_PROTO_PPP_SESSION
add ecx, PPPoE_frame.Payload + 2
lea edx, [PPPoE_MAC]
call eth_output
jz .eth_error
 
sub ecx, PPPoE_frame.Payload
mov [edi + PPPoE_frame.VersionAndType], 0x11
mov [edi + PPPoE_frame.Code], 0
popw [edi + PPPoE_frame.SessionID]
xchg cl, ch
mov [edi + PPPoE_frame.Length], cx
xchg cl, ch
 
pop word [edi + PPPoE_frame.Payload]
 
sub ecx, 2
add edi, PPPoE_frame.Payload + 2
 
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_output: success!\n"
ret
 
 
.eth_error:
add esp, 4
xor eax, eax
ret
 
align 4
pppoe_start_connection:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_start_connection: %x\n", cx
 
cmp [PPPoE_SID], 0
jne .fail
 
mov [PPPoE_SID], cx
mov dword [PPPoE_MAC], edx
mov word [PPPoE_MAC + 4], si
 
xor eax, eax
ret
 
.fail:
or eax, -1
ret
 
 
align 4
pppoe_stop_connection:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "PPPoE_stop_connection\n"
 
xor eax, eax
mov [PPPoE_SID], ax
mov dword [PPPoE_MAC], eax
mov word [PPPoE_MAC + 4], ax
 
ret
 
 
;-----------------------------------------------------------------;
; ;
; pppoe_api: Part of system function 76 ;
; ;
; IN: subfunction number in bl ;
; device number in bh ;
; ecx, edx, .. depends on subfunction ;
; ;
; OUT: ;
; ;
;-----------------------------------------------------------------;
align 4
pppoe_api:
 
movzx eax, bh
shl eax, 2
 
and ebx, 0xff
cmp ebx, .number
ja .error
jmp dword [.table + 4*ebx]
 
.table:
dd pppoe_start_connection ; 0
dd pppoe_stop_connection ; 1
.number = ($ - .table) / 4 - 1
 
.error:
mov eax, -1
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/tcp_usreq.inc
0,0 → 1,237
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; Based on the code of 4.4BSD ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
;-----------------------------------------------------------------;
; ;
; tcp_usrclosed ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_usrclosed:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "TCP_usrclosed: %x\n", eax
 
push ebx
mov ebx, [eax + TCP_SOCKET.t_state]
mov ebx, dword [.switch + ebx*4]
jmp ebx
 
.switch:
dd .close ; TCPS_CLOSED
dd .close ; TCPS_LISTEN
dd .close ; TCPS_SYN_SENT
dd .wait1 ; TCPS_SYN_RECEIVED
dd .wait1 ; TCPS_ESTABLISHED
dd .last_ack ; TCPS_CLOSE_WAIT
dd .ret ; TCPS_FIN_WAIT_1
dd .ret ; TCPS_CLOSING
dd .ret ; TCPS_LAST_ACK
dd .disc ; TCPS_FIN_WAIT_2
dd .disc ; TCPS_TIMED_WAIT
 
.close:
mov [eax + TCP_SOCKET.t_state], TCPS_CLOSED
call tcp_close
pop ebx
ret
 
.wait1:
mov [eax + TCP_SOCKET.t_state], TCPS_FIN_WAIT_1
pop ebx
ret
 
.last_ack:
mov [eax + TCP_SOCKET.t_state], TCPS_LAST_ACK
pop ebx
ret
 
.disc:
call socket_is_disconnected
.ret:
pop ebx
ret
 
 
;-----------------------------------------------------------------;
; ;
; tcp_connect ;
; ;
; IN: eax = socket ptr ;
; ;
; OUT: eax = 0 on success ;
; eax = -1 on error ;
; ebx = error code on error ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_connect:
 
test [eax + SOCKET.state], SS_ISCONNECTED
jnz .eisconn
 
push eax edx
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
 
mov ebx, eax
lea eax, [ebx + STREAM_SOCKET.snd]
call socket_ring_create
test eax, eax
jz .nomem
 
lea eax, [ebx + STREAM_SOCKET.rcv]
call socket_ring_create
test eax, eax
jz .nomem
pop edx eax
 
; Fill in remote port and IP
pushw [edx + 2]
pop [eax + TCP_SOCKET.RemotePort]
 
pushd [edx + 4]
pop [eax + TCP_SOCKET.RemoteIP]
 
; Find route to host
pusha
push eax
mov ebx, [eax + TCP_SOCKET.device]
mov edx, [eax + TCP_SOCKET.LocalIP]
mov eax, [eax + TCP_SOCKET.RemoteIP]
call ipv4_route
test eax, eax
jz .enoroute
pop eax
mov ebx, [net_device_list + edi]
mov [eax + TCP_SOCKET.device], ebx
mov [eax + TCP_SOCKET.LocalIP], edx
popa
 
; Find a local port, if user didnt define one
cmp [eax + TCP_SOCKET.LocalPort], 0
jne @f
call socket_find_port
@@:
 
; Compute window scaling factor
push ecx
xor ecx, ecx
mov ebx, TCP_max_win
@@:
cmp ebx, SOCKET_BUFFER_SIZE
ja @f
shl ebx, 1
inc ecx
cmp ecx, TCP_max_winshift
jb @r
@@:
mov [eax + TCP_SOCKET.request_r_scale], cl
pop ecx
 
call socket_is_connecting
inc [TCPS_connattempt]
 
mov [eax + TCP_SOCKET.timer_persist], 0
mov [eax + TCP_SOCKET.t_state], TCPS_SYN_SENT
 
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_init
 
push [TCP_sequence_num]
add [TCP_sequence_num], TCP_ISSINCR/2
pop [eax + TCP_SOCKET.ISS]
 
tcp_sendseqinit eax
 
push eax
lea ecx, [eax + SOCKET.mutex]
call mutex_unlock
pop eax
 
; Now send the SYN packet to remote end
push eax
call tcp_output
pop eax
 
test [eax + SOCKET.options], SO_NONBLOCK
jz .waitforit
 
xor eax, eax
dec eax
mov ebx, EINPROGRESS
ret
 
.nomem:
pop edx eax
xor eax, eax
dec eax
mov ebx, ENOMEM
ret
 
.eisconn:
xor eax, eax
dec eax
mov ebx, EISCONN
ret
 
.enoroute:
pop eax
popa
xor eax, eax
dec eax
mov ebx, EADDRNOTAVAIL
ret
 
.waitforit:
push eax
stdcall timer_hs, TCP_time_connect, 0, .timeout, eax
pop ebx
mov [ebx + TCP_SOCKET.timer_connect], eax
mov eax, ebx
 
.loop:
cmp [eax + SOCKET.errorcode], 0
jne .fail
cmp [eax + TCP_SOCKET.t_state], TCPS_ESTABLISHED
je .established
 
call socket_block
jmp .loop
 
.timeout:
mov eax, [esp+4]
mov [eax + SOCKET.errorcode], ETIMEDOUT
and [eax + SOCKET.state], not SS_ISCONNECTING
call socket_notify
ret 4
 
.fail:
mov ebx, [eax + SOCKET.errorcode]
mov [eax + SOCKET.errorcode], 0 ; Clear the error, we only need to send it to the caller once
xor eax, eax
dec eax
ret
 
.established:
stdcall cancel_timer_hs, [eax + TCP_SOCKET.timer_connect]
xor eax, eax
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/icmp.inc
0,0 → 1,456
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; ICMP.INC ;;
;; ;;
;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;;
;; Based on the work of [Johnny_B] and [smb] ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; ICMP types & codes
 
ICMP_ECHOREPLY = 0 ; echo reply message
 
ICMP_UNREACH = 3
ICMP_UNREACH_NET = 0 ; bad net
ICMP_UNREACH_HOST = 1 ; bad host
ICMP_UNREACH_PROTOCOL = 2 ; bad protocol
ICMP_UNREACH_PORT = 3 ; bad port
ICMP_UNREACH_NEEDFRAG = 4 ; IP_DF caused drop
ICMP_UNREACH_SRCFAIL = 5 ; src route failed
ICMP_UNREACH_NET_UNKNOWN = 6 ; unknown net
ICMP_UNREACH_HOST_UNKNOWN = 7 ; unknown host
ICMP_UNREACH_ISOLATED = 8 ; src host isolated
ICMP_UNREACH_NET_PROHIB = 9 ; prohibited access
ICMP_UNREACH_HOST_PROHIB = 10 ; ditto
ICMP_UNREACH_TOSNET = 11 ; bad tos for net
ICMP_UNREACH_TOSHOST = 12 ; bad tos for host
ICMP_UNREACH_FILTER_PROHIB = 13 ; admin prohib
ICMP_UNREACH_HOST_PRECEDENCE = 14 ; host prec vio.
ICMP_UNREACH_PRECEDENCE_CUTOFF = 15 ; prec cutoff
 
ICMP_SOURCEQUENCH = 4 ; Packet lost, slow down
 
ICMP_REDIRECT = 5 ; shorter route, codes:
ICMP_REDIRECT_NET = 0 ; for network
ICMP_REDIRECT_HOST = 1 ; for host
ICMP_REDIRECT_TOSNET = 2 ; for tos and net
ICMP_REDIRECT_TOSHOST = 3 ; for tos and host
 
ICMP_ALTHOSTADDR = 6 ; alternate host address
ICMP_ECHO = 8 ; echo service
ICMP_ROUTERADVERT = 9 ; router advertisement
ICMP_ROUTERADVERT_NORMAL = 0 ; normal advertisement
ICMP_ROUTERADVERT_NOROUTE_COMMON= 16 ; selective routing
 
ICMP_ROUTERSOLICIT = 10 ; router solicitation
ICMP_TIMXCEED = 11 ; time exceeded, code:
ICMP_TIMXCEED_INTRANS = 0 ; ttl==0 in transit
ICMP_TIMXCEED_REASS = 1 ; ttl==0 in reass
 
ICMP_PARAMPROB = 12 ; ip header bad
ICMP_PARAMPROB_ERRATPTR = 0 ; error at param ptr
ICMP_PARAMPROB_OPTABSENT = 1 ; req. opt. absent
ICMP_PARAMPROB_LENGTH = 2 ; bad length
 
ICMP_TSTAMP = 13 ; timestamp request
ICMP_TSTAMPREPLY = 14 ; timestamp reply
ICMP_IREQ = 15 ; information request
ICMP_IREQREPLY = 16 ; information reply
ICMP_MASKREQ = 17 ; address mask request
ICMP_MASKREPLY = 18 ; address mask reply
ICMP_TRACEROUTE = 30 ; traceroute
ICMP_DATACONVERR = 31 ; data conversion error
ICMP_MOBILE_REDIRECT = 32 ; mobile host redirect
ICMP_IPV6_WHEREAREYOU = 33 ; IPv6 where-are-you
ICMP_IPV6_IAMHERE = 34 ; IPv6 i-am-here
ICMP_MOBILE_REGREQUEST = 35 ; mobile registration req
ICMP_MOBILE_REGREPLY = 36 ; mobile registreation reply
ICMP_SKIP = 39 ; SKIP
 
ICMP_PHOTURIS = 40 ; Photuris
ICMP_PHOTURIS_UNKNOWN_INDEX = 1 ; unknown sec index
ICMP_PHOTURIS_AUTH_FAILED = 2 ; auth failed
ICMP_PHOTURIS_DECRYPT_FAILED = 3 ; decrypt failed
 
 
struct ICMP_header
 
Type db ?
Code db ?
Checksum dw ?
Identifier dw ?
SequenceNumber dw ?
 
ends
 
 
uglobal
align 4
 
ICMP_packets_tx rd NET_DEVICES_MAX
ICMP_packets_rx rd NET_DEVICES_MAX
 
endg
 
 
 
;-----------------------------------------------------------------;
; ;
; ICMP_init ;
; ;
;-----------------------------------------------------------------;
 
macro icmp_init {
 
xor eax, eax
mov edi, ICMP_packets_tx
mov ecx, 2*NET_DEVICES_MAX
rep stosd
 
}
 
 
;-----------------------------------------------------------------;
; ;
; icmp_input: Send a reply's to an ICMP echo or insert packets ;
; into socket. ;
; ;
; IN: [esp] = ptr to buffer ;
; ebx = ptr to device struct ;
; ecx = ICMP Packet size ;
; edx = ptr to IPv4 header ;
; esi = ptr to ICMP Packet data ;
; edi = interface number*4 ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
icmp_input:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ICMP_input\n"
 
; Dump all multicasts and broadcasts
mov eax, [IPv4_address + edi]
cmp eax, [edx + IPv4_header.DestinationAddress]
jne .dump
 
; Check the checksum
push esi ecx edx
push [esi + ICMP_header.Checksum]
mov [esi + ICMP_header.Checksum], 0
xor edx, edx
call checksum_1
call checksum_2
pop si
cmp dx, si
pop edx ecx esi
jne .checksum_mismatch
 
DEBUGF DEBUG_NETWORK_VERBOSE, "ICMP_input: Checksum OK\n"
 
; Update stats
inc [ICMP_packets_rx + edi]
 
; Is this an echo request?
cmp [esi + ICMP_header.Type], ICMP_ECHO
je .echo_request
 
; Look for an open ICMP socket
pusha
mov ecx, socket_mutex
call mutex_lock
popa
 
add ecx, esi
sub ecx, edx
mov esi, edx
mov eax, net_sockets
.next_socket:
mov eax, [eax + SOCKET.NextPtr]
or eax, eax
jz .dump_
 
cmp [eax + SOCKET.Domain], AF_INET4
jne .next_socket
 
cmp [eax + SOCKET.Protocol], IP_PROTO_ICMP
jne .next_socket
 
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_VERBOSE, "socket=%x\n", eax
 
pusha
lea ecx, [eax + SOCKET.mutex]
call mutex_lock
popa
 
jmp socket_input
 
 
 
.echo_request:
 
; We'll reuse the packet so we can create the response as fast as possible
DEBUGF DEBUG_NETWORK_VERBOSE, "ICMP echo request\n"
 
; Change Packet type to reply
mov [esi + ICMP_header.Type], ICMP_ECHOREPLY
 
mov eax, [esp]
mov esi, [eax + NET_BUFF.offset]
add esi, eax
 
; Check frame type
cmp [eax + NET_BUFF.type], NET_BUFF_ETH
jne .not_ethernet
 
; exchange dest and source MAC in ETH header
push dword [esi + ETH_header.DstMAC]
push dword [esi + ETH_header.SrcMAC]
pop dword [esi + ETH_header.DstMAC]
pop dword [esi + ETH_header.SrcMAC]
push word [esi + ETH_header.DstMAC + 4]
push word [esi + ETH_header.SrcMAC + 4]
pop word [esi + ETH_header.DstMAC + 4]
pop word [esi + ETH_header.SrcMAC + 4]
add esi, sizeof.ETH_header
 
.not_ethernet:
; Exchange dest and source address in IP header
push [esi + IPv4_header.SourceAddress]
push [esi + IPv4_header.DestinationAddress]
pop [esi + IPv4_header.SourceAddress]
pop [esi + IPv4_header.DestinationAddress]
 
; Calculate IP header length
movzx ecx, [esi + IPv4_header.VersionAndIHL]
and ecx, 0x0f
shl cx, 2
mov edi, ecx ; put it in edi for later
 
; Calculate IP checksum
mov eax, esi
mov [eax + IPv4_header.HeaderChecksum], 0
xor edx, edx
call checksum_1
call checksum_2
mov [eax + IPv4_header.HeaderChecksum], dx
 
; Calculate ICMP packet length
movzx ecx, [eax + IPv4_header.TotalLength]
xchg ch, cl
sub ecx, edi ; IP packet length - IP header length = ICMP packet length
 
; Calculate ICMP checkSum
mov eax, esi
mov [esi + ICMP_header.Checksum], 0
xor edx, edx
call checksum_1
call checksum_2
mov [eax + ICMP_header.Checksum], dx
 
; Transmit the frame
DEBUGF DEBUG_NETWORK_VERBOSE, "ICMP transmitting reply\n"
call [ebx + NET_DEVICE.transmit]
test eax, eax
jnz @f
DEBUGF DEBUG_NETWORK_VERBOSE, "ICMP transmit failed\n"
call net_ptr_to_num4
inc [ICMP_packets_tx + edi]
inc [IPv4_packets_tx + edi]
@@:
ret
 
.dump_:
pusha
mov ecx, socket_mutex
call mutex_unlock
popa
 
DEBUGF DEBUG_NETWORK_ERROR, "ICMP_input: no socket found\n"
jmp .dump
 
.checksum_mismatch:
DEBUGF DEBUG_NETWORK_ERROR, "ICMP_input: checksum mismatch\n"
 
.dump:
DEBUGF DEBUG_NETWORK_VERBOSE, "ICMP_input: dumping\n"
call net_buff_free
ret
 
 
if 0
;-----------------------------------------------------------------;
; ;
; icmp_output ;
; ;
; IN: eax = dest ip ;
; bh = type ;
; bl = code ;
; ecx = data length ;
; edx = source ip ;
; esi = data offset ;
; edi = identifier shl 16 + sequence number ;
; ;
;-----------------------------------------------------------------;
align 4
icmp_output:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "Creating ICMP Packet\n"
 
push esi edi bx
add ecx, sizeof.ICMP_header
mov di, IP_PROTO_ICMP SHL 8 + 128 ; TTL
call IPv4_output
jz .exit
 
DEBUGF DEBUG_NETWORK_VERBOSE, "full icmp packet size: %u\n", edx
 
pop word [edi + ICMP_header.Type] ; Write both type and code bytes at once
pop dword [edi + ICMP_header.Identifier] ; identifier and sequence number
mov [edi + ICMP_header.Checksum], 0
 
push ebx ecx edx
mov esi, edi
xor edx, edx
call checksum_1
call checksum_2
mov [edi + ICMP_header.Checksum], dx
pop edx ecx ebx esi
 
sub ecx, sizeof.ICMP_header
add edi, sizeof.ICMP_header
push cx
shr cx, 2
rep movsd
pop cx
and cx, 3
rep movsb
 
sub edi, edx ;;; TODO: find a better way to remember start of packet
push edx edi
DEBUGF DEBUG_NETWORK_VERBOSE, "Sending ICMP Packet\n"
call [ebx + NET_DEVICE.transmit]
test eax, eax
jnz @f
call NET_ptr_to_num4
inc [ICMP_PACKETS_TX + edi]
@@:
ret
.exit:
DEBUGF DEBUG_NETWORK_ERROR, "Creating ICMP Packet failed\n"
add esp, 2*4 + 2
ret
end if
 
 
 
 
;-----------------------------------------------------------------;
; ;
; icmp_output_raw ;
; ;
; IN: eax = socket ptr ;
; ecx = data length ;
; edx = data pointer ;
; ;
;-----------------------------------------------------------------;
align 4
icmp_output_raw:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "Creating ICMP Packet for socket %x, data ptr=%x\n", eax, edx
 
push edx
mov ebx, [eax + IP_SOCKET.device]
mov edx, [eax + IP_SOCKET.LocalIP]
mov edi, [eax + IP_SOCKET.RemoteIP]
mov al, [eax + IP_SOCKET.ttl]
mov ah, IP_PROTO_ICMP
call ipv4_output
jz .fail
 
pop esi
push eax
 
push edi ecx
DEBUGF DEBUG_NETWORK_VERBOSE, "copying %u bytes from %x to %x\n", ecx, esi, edi
rep movsb
pop ecx edi
 
mov [edi + ICMP_header.Checksum], 0
 
mov esi, edi
xor edx, edx
call checksum_1
call checksum_2
mov [edi + ICMP_header.Checksum], dx
 
DEBUGF DEBUG_NETWORK_VERBOSE, "Sending ICMP Packet\n"
call [ebx + NET_DEVICE.transmit]
test eax, eax
jnz @f
call net_ptr_to_num4
inc [ICMP_packets_tx + edi]
@@:
ret
 
.fail:
pop edx
DEBUGF DEBUG_NETWORK_ERROR, "Creating ICMP Packet failed\n"
or eax, -1
mov ebx, EMSGSIZE ;;; FIXME
ret
 
 
 
 
;-----------------------------------------------------------------;
; ;
; icmp_api: Part of system function 76. ;
; ;
; IN: bl = subfunction number ;
; bh = device number ;
; ecx, edx, .. depends on subfunction ;
; ;
; OUT: depends on subfunction ;
; ;
;-----------------------------------------------------------------;
align 4
icmp_api:
 
movzx eax, bh
shl eax, 2
 
test bl, bl
jz .packets_tx ; 0
dec bl
jz .packets_rx ; 1
 
.error:
mov eax, -1
ret
 
.packets_tx:
mov eax, [ICMP_packets_tx + eax]
ret
 
.packets_rx:
mov eax, [ICMP_packets_rx + eax]
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/tcp_timer.inc
0,0 → 1,192
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; Based on the code of 4.4BSD ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
timer_flag_retransmission = 1 shl 0
timer_flag_keepalive = 1 shl 1
timer_flag_2msl = 1 shl 2
timer_flag_persist = 1 shl 3
timer_flag_wait = 1 shl 4
 
 
macro tcp_timer_160ms {
 
local .loop
local .exit
 
mov ebx, net_sockets
.loop:
mov ebx, [ebx + SOCKET.NextPtr]
test ebx, ebx
jz .exit
 
cmp [ebx + SOCKET.Domain], AF_INET4
jne .loop
cmp [ebx + SOCKET.Protocol], IP_PROTO_TCP
jne .loop
test [ebx + TCP_SOCKET.t_flags], TF_DELACK
jz .loop
 
and [ebx + TCP_SOCKET.t_flags], not (TF_DELACK)
or [ebx + TCP_SOCKET.t_flags], TF_ACKNOW
 
push ebx
mov eax, ebx
call tcp_output
pop ebx
 
inc [TCPS_delack] ; update stats
 
jmp .loop
 
.exit:
 
}
 
 
align 4
proc tcp_timer_640ms
 
xor esi, esi
mov ecx, MANUAL_DESTROY
call create_event
mov [TCP_timer1_event], eax
 
.wait:
mov eax, [TCP_timer1_event]
mov ebx, [eax + EVENT.id]
call wait_event
 
; Update TCP sequence number
 
add [TCP_sequence_num], 64000
 
; Scan through all the active TCP sockets, decrementing all active timers
; When a timer reaches zero, run its handler.
 
mov eax, net_sockets
.loop:
mov eax, [eax + SOCKET.NextPtr]
.check_only:
or eax, eax
jz .wait
 
cmp [eax + SOCKET.Domain], AF_INET4
jne .loop
 
cmp [eax + SOCKET.Protocol], IP_PROTO_TCP
jne .loop
 
inc [eax + TCP_SOCKET.t_idle]
 
test [eax + TCP_SOCKET.timer_flags], timer_flag_retransmission
jz .check_more2
dec [eax + TCP_SOCKET.timer_retransmission]
jnz .check_more2
 
DEBUGF DEBUG_NETWORK_VERBOSE, "socket %x: Retransmission timer expired\n", eax
 
push eax
call tcp_output
pop eax
 
.check_more2:
test [eax + TCP_SOCKET.timer_flags], timer_flag_keepalive
jz .check_more3
dec [eax + TCP_SOCKET.timer_keepalive]
jnz .check_more3
 
DEBUGF DEBUG_NETWORK_VERBOSE, "socket %x: Keepalive expired\n", eax
 
cmp [eax + TCP_SOCKET.state], TCPS_ESTABLISHED
ja .dont_kill
 
push eax
call tcp_disconnect
pop eax
jmp .loop
 
.dont_kill:
test [eax + SOCKET.options], SO_KEEPALIVE
jz .reset_keepalive
 
push eax
mov ebx, eax
xor cl, cl
call tcp_respond ; send keepalive
pop eax
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_interval
jmp .check_more3
 
.reset_keepalive:
mov [eax + TCP_SOCKET.timer_keepalive], TCP_time_keep_idle
 
.check_more3:
test [eax + TCP_SOCKET.timer_flags], timer_flag_2msl
jz .check_more5
dec [eax + TCP_SOCKET.timer_timed_wait]
jnz .check_more5
 
DEBUGF DEBUG_NETWORK_VERBOSE, "socket %x: 2MSL timer expired\n", eax
 
.check_more5:
test [eax + TCP_SOCKET.timer_flags], timer_flag_persist
jz .check_more6
dec [eax + TCP_SOCKET.timer_persist]
jnz .check_more6
 
DEBUGF DEBUG_NETWORK_VERBOSE, "socket %x: persist timer expired\n", eax
 
call tcp_set_persist
or [eax + TCP_SOCKET.t_flags], TF_FORCE
push eax
call tcp_output
pop eax
and [eax + TCP_SOCKET.t_flags], not TF_FORCE
 
.check_more6:
test [eax + TCP_SOCKET.timer_flags], timer_flag_wait
jz .loop
dec [eax + TCP_SOCKET.timer_timed_wait]
jnz .loop
 
DEBUGF DEBUG_NETWORK_VERBOSE, "socket %x: timed wait timer expired\n", eax
 
push [eax + SOCKET.NextPtr]
call tcp_close
pop eax
 
jmp .check_only
 
endp
 
 
;-----------------------------------------------------------------;
; ;
; TCP_cancel_timers ;
; ;
; IN: eax = socket ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
tcp_cancel_timers:
 
mov [eax + TCP_SOCKET.timer_flags], 0
 
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/tcp.inc
0,0 → 1,293
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Part of the TCP/IP network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; Based on the code of 4.4BSD ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; Socket states
TCPS_CLOSED = 0
TCPS_LISTEN = 1
TCPS_SYN_SENT = 2
TCPS_SYN_RECEIVED = 3
TCPS_ESTABLISHED = 4
TCPS_CLOSE_WAIT = 5
TCPS_FIN_WAIT_1 = 6
TCPS_CLOSING = 7
TCPS_LAST_ACK = 8
TCPS_FIN_WAIT_2 = 9
TCPS_TIME_WAIT = 10
 
; Socket Flags
TF_ACKNOW = 1 shl 0 ; ack peer immediately
TF_DELACK = 1 shl 1 ; ack, but try to delay it
TF_NODELAY = 1 shl 2 ; don't delay packets to coalesce
TF_NOOPT = 1 shl 3 ; don't use tcp options
TF_SENTFIN = 1 shl 4 ; have sent FIN
TF_REQ_SCALE = 1 shl 5 ; have/will request window scaling
TF_RCVD_SCALE = 1 shl 6 ; other side has requested scaling
TF_REQ_TSTMP = 1 shl 7 ; have/will request timestamps
TF_RCVD_TSTMP = 1 shl 8 ; a timestamp was received in SYN
TF_SACK_PERMIT = 1 shl 9 ; other side said I could SACK
 
TF_FORCE = 1 shl 16 ; force to send a segment
 
; Segment flags
TH_FIN = 1 shl 0
TH_SYN = 1 shl 1
TH_RST = 1 shl 2
TH_PUSH = 1 shl 3
TH_ACK = 1 shl 4
TH_URG = 1 shl 5
 
; Segment header options
TCP_OPT_EOL = 0 ; End of option list.
TCP_OPT_NOP = 1 ; No-Operation.
TCP_OPT_MAXSEG = 2 ; Maximum Segment Size.
TCP_OPT_WINDOW = 3 ; window scale
TCP_OPT_SACK_PERMIT = 4 ; Selective Acknowledgement
TCP_OPT_SACK = 5
TCP_OPT_TIMESTAMP = 8
 
; Fundamental timer values
TCP_time_MSL = 47 ; max segment lifetime (30s)
TCP_time_re_min = 2 ; min retransmission (1,28s)
TCP_time_re_max = 100 ; max retransmission (64s)
TCP_time_pers_min = 8 ; min persist (5,12s)
TCP_time_pers_max = 94 ; max persist (60,16s)
TCP_time_keep_init = 118 ; connection establishment (75,52s)
TCP_time_keep_idle = 4608 ; idle time before 1st probe (2h)
TCP_time_keep_interval = 118 ; between probes when no response (75,52s)
TCP_time_rtt_default = 5 ; default Round Trip Time (3,2s)
TCP_time_srtt_default = 0 ;
TCP_time_max_idle = 8*TCP_time_keep_interval ; FIXME
 
TCP_time_connect = 300 ; in 1/100s (default=3s)
 
; timer constants
TCP_max_rxtshift = 12 ; max retransmissions waiting for ACK
TCP_max_keepcnt = 8 ; max keepalive probes
 
;
TCP_max_winshift = 14
TCP_max_win = 65535
 
TCP_re_xmit_thresh = 3
 
TCP_mss_default = 1480 ; default max segment size
 
; smoothed round trip time and estimated variance are stored as fixed point numbers,
; shifted by the value below.
; With these scales, srtt has 3 bits to the right of the binary point, and thus an "alpha"
; of .875. rttvar has 2 bits to the right and thus "alpha" of 0.75
TCP_RTT_SHIFT = 3
TCP_RTTVAR_SHIFT = 2
 
TCP_PAWS_IDLE = 24*24*60*60*100 ; 24 days, in 1/100 seconds
 
TCP_QUEUE_SIZE = 50
 
TCP_ISSINCR = 128000
 
struct TCP_header
 
SourcePort dw ?
DestinationPort dw ?
SequenceNumber dd ?
AckNumber dd ?
DataOffset db ? ; DataOffset[0-3 bits] and Reserved[4-7]
Flags db ? ; Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN
Window dw ?
Checksum dw ?
UrgentPointer dw ?
 
ends
 
struct TCP_queue_entry
 
ip_ptr dd ?
segment_ptr dd ?
segment_size dd ?
device_ptr dd ?
timestamp dd ?
buffer_ptr dd ?
 
ends
 
uglobal
align 4
 
TCP_segments_tx rd NET_DEVICES_MAX
TCP_segments_rx rd NET_DEVICES_MAX
TCP_segments_missed rd NET_DEVICES_MAX
TCP_segments_dumped rd NET_DEVICES_MAX
; TCP_bytes_rx rq NET_DEVICES_MAX
; TCP_bytes_tx rq NET_DEVICES_MAX
TCP_sequence_num dd ?
TCP_queue rd (TCP_QUEUE_SIZE*sizeof.TCP_queue_entry + sizeof.queue)/4
TCP_input_event dd ?
TCP_timer1_event dd ?
endg
 
uglobal
align 4
 
TCPS_accepts dd ? ; #SYNs received in LISTEN state
TCPS_closed dd ? ; #connections closed (includes drops)
TCPS_connattempt dd ? ; #connections initiated (calls to connect)
TCPS_conndrops dd ? ; #embryonic connections dropped (before SYN received)
TCPS_connects dd ? ; #connections established actively or passively
TCPS_delack dd ? ; #delayed ACKs sent
TCPS_drops dd ? ; #connections dropped (after SYN received)
TCPS_keepdrops dd ? ; #connections dropped in keepalive (established or awaiting SYN)
TCPS_keepprobe dd ? ; #keepalive probes sent
TCPS_keeptimeo dd ? ; #times keepalive timer or connections-establishment timer expire
TCPS_pawsdrop dd ? ; #segments dropped due to PAWS
TCPS_pcbcachemiss dd ? ; #times PCB cache comparison fails
TCPS_persisttimeo dd ? ; #times persist timer expires
TCPS_predack dd ? ; #times header prediction correct for ACKs
TCPS_preddat dd ? ; #times header prediction correct for data packets
TCPS_rcvackbyte dd ? ; #bytes ACKed by received ACKs
TCPS_rcvackpack dd ? ; #received ACK packets
TCPS_rcvacktoomuch dd ? ; #received ACKs for unsent data
TCPS_rcvafterclose dd ? ; #packets received after connection closed
TCPS_rcvbadoff dd ? ; #packets received with invalid header length
TCPS_rcvbadsum dd ? ; #packets received with checksum errors
TCPS_rcvbyte dd ? ; #bytes received in sequence
TCPS_rcvbyteafterwin dd ? ; #bytes received beyond advertised window
TCPS_rcvdupack dd ? ; #duplicate ACKs received
TCPS_rcvdupbyte dd ? ; #bytes receivedin completely duplicate packets
TCPS_rcvduppack dd ? ; #packets received with completely duplicate bytes
TCPS_rcvoobyte dd ? ; #out-of-order bytes received
TCPS_rcvoopack dd ? ; #out-of-order packets received
TCPS_rcvpack dd ? ; #packets received in sequence
TCPS_rcvpackafterwin dd ? ; #packets with some data beyond advertised window
TCPS_rcvpartdupbyte dd ? ; #duplicate bytes in part-duplicate packets
TCPS_rcvpartduppack dd ? ; #packets with some duplicate data
TCPS_rcvshort dd ? ; #packets received too short
TCPS_rcvtotal dd ? ; #total packets received
TCPS_rcvwinprobe dd ? ; #window probe packets received
TCPS_rcvwinupd dd ? ; #received window update packets
TCPS_rexmttimeo dd ? ; #retransmission timeouts
TCPS_rttupdated dd ? ; #times RTT estimators updated
TCPS_segstimed dd ? ; #segments for which TCP tried to measure RTT
TCPS_sndacks dd ? ; #ACK-only packets sent (data length = 0)
TCPS_sndbyte dd ? ; #data bytes sent
TCPS_sndctrl dd ? ; #control (SYN, FIN, RST) packets sent (data length = 0)
TCPS_sndpack dd ? ; #data packets sent (data length > 0)
TCPS_sndprobe dd ? ; #window probes sent (1 byte of data forced by persist timer)
TCPS_sndrexmitbyte dd ? ; #data bytes retransmitted
TCPS_sndrexmitpack dd ? ; #data packets retransmitted
TCPS_sndtotal dd ? ; total #packets sent
TCPS_sndurg dd ? ; #packets sent with URG-only (data length=0)
TCPS_sndwinup dd ? ; #window update-only packets sent (data length=0)
TCPS_timeoutdrop dd ? ; #connections dropped in retransmission timeout
 
endg
 
 
;-----------------------------------------------------------------;
; ;
; TCP_init: Resets all TCP variables. ;
; ;
;-----------------------------------------------------------------;
macro tcp_init {
 
xor eax, eax
mov edi, TCP_segments_tx
mov ecx, (6*NET_DEVICES_MAX)
rep stosd
 
pseudo_random eax
mov [TCP_sequence_num], eax
 
init_queue TCP_queue
 
movi ebx, 1
mov ecx, tcp_process_input
call new_sys_threads
test eax, eax
jns @f
DEBUGF DEBUG_NETWORK_ERROR,'K : cannot create kernel thread for TCP input, error %d\n', eax
@@:
 
movi ebx, 1
mov ecx, tcp_timer_640ms
call new_sys_threads
test eax, eax
jns @f
DEBUGF DEBUG_NETWORK_ERROR,'K : cannot create kernel thread for TCP timer, error %d\n', eax
@@:
 
}
 
 
include 'tcp_timer.inc'
include 'tcp_subr.inc'
include 'tcp_usreq.inc'
include 'tcp_input.inc'
include 'tcp_output.inc'
 
 
;------------------------------------------------------------------;
; ;
; tcp_api: Part of system function 76 ;
; ;
; IN: bl = subfunction number ;
; bh = device number ;
; ecx, edx, .. depends on subfunction ;
; ;
; OUT: depends on subfunction ;
; ;
;------------------------------------------------------------------;
align 4
tcp_api:
 
movzx eax, bh
shl eax, 2
 
test bl, bl
jz .packets_tx ; 0
dec bl
jz .packets_rx ; 1
dec bl
jz .packets_missed ; 2
dec bl
jz .packets_dumped ; 3
dec bl
jz .packets_queued ; 4
 
.error:
mov eax, -1
ret
 
.packets_tx:
mov eax, [TCP_segments_tx + eax]
ret
 
.packets_rx:
mov eax, [TCP_segments_rx + eax]
ret
 
.packets_missed:
mov eax, [TCP_segments_missed + eax]
ret
 
.packets_dumped:
mov eax, [TCP_segments_dumped + eax]
ret
 
.packets_queued:
mov eax, [TCP_queue + queue.size]
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/queue.inc
0,0 → 1,120
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; queue.inc ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; The Queues implemented by these macros form a ring-buffer.
; The data to these queue's always looks like this:
;
; At top, you have the queue struct, wich has the size (number of currently queued packets, read and write pointers.
; This struct is followed by a number of slots wich you can read and write to using the macros.
; How these slots look like is up to you to chose, normally they should have at least a pointer to where the real data is.
; (you can see some examples below)
 
 
struct queue
 
size dd ? ; number of queued packets in this queue
w_ptr dd ? ; current writing pointer in queue
r_ptr dd ? ; current reading pointer
 
ends
 
; The following macros share these inputs:
 
; ptr = pointer to where the queue data is located
; size = number of slots/entrys in the queue
; entry_size = size of one slot, in bytes
; failaddr = the address where macro will jump to when there is no data in the queue
 
; additionally, add_to_queue requires you to set esi to the data wich you want to queue
; get_from_queue on the other hand will return a pointer in esi, to the entry you're interessed in
; PS: macros WILL destroy ecx and edi
 
macro add_to_queue ptr, size, entry_size, failaddr {
 
local .ok, .no_wrap
 
spin_lock_irqsave
 
cmp [ptr + queue.size], size ; Check if queue isnt full
jb .ok
 
spin_unlock_irqrestore
jmp failaddr
 
.ok:
inc [ptr + queue.size] ; if not full, queue one more
 
mov edi, [ptr + queue.w_ptr] ; Current write pointer (FIFO!)
mov ecx, entry_size/4 ; Write the queue entry
rep movsd ;
 
lea ecx, [size*entry_size+ptr+sizeof.queue]
cmp edi, ecx ; entry size
jb .no_wrap
 
sub edi, size*entry_size
.no_wrap:
mov [ptr + queue.w_ptr], edi
 
spin_unlock_irqrestore
 
}
 
 
 
macro get_from_queue ptr, size, entry_size, failaddr {
 
local .ok, .no_wrap
 
spin_lock_irqsave
 
cmp [ptr + queue.size], 0 ; any packets queued?
ja .ok
 
spin_unlock_irqrestore
jmp failaddr
 
.ok:
dec [ptr + queue.size] ; if so, dequeue one
 
mov esi, [ptr + queue.r_ptr]
push esi
 
add esi, entry_size
 
lea ecx, [size*entry_size+ptr+sizeof.queue]
cmp esi, ecx ; entry size
jb .no_wrap
 
sub esi, size*entry_size
 
.no_wrap:
mov dword [ptr + queue.r_ptr], esi
 
pop esi
 
spin_unlock_irqrestore
 
}
 
macro init_queue ptr {
 
mov [ptr + queue.size] , 0
lea edi, [ptr + sizeof.queue]
mov [ptr + queue.w_ptr], edi
mov [ptr + queue.r_ptr], edi
 
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network/IPv6.inc
0,0 → 1,290
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2012-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; IPv6.INC ;;
;; ;;
;; Part of the tcp/ip network stack for KolibriOS ;;
;; ;;
;; Written by hidnplayr@kolibrios.org ;;
;; ;;
;; GNU GENERAL PUBLIC LICENSE ;;
;; Version 2, June 1991 ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
struct IPv6_header
 
VersionTrafficFlow dd ? ; Version[0-3], Traffic class[4-11], Flow Label [12-31]
PayloadLength dw ? ; 16 bits, unsigned length of payload (extension headers are part of this)
NextHeader db ? ; Values are same as in IPv4 'Protocol' field
HopLimit db ? ; Decremented by every node, packet is discarded when it reaches 0
SourceAddress rd 4 ; 128-bit addresses
DestinationAddress rd 4 ;
Payload rb 0
 
ends
 
 
uglobal
align 4
 
IPv6:
.addresses rd 4*NET_DEVICES_MAX
.subnet rd 4*NET_DEVICES_MAX
.dns rd 4*NET_DEVICES_MAX
.gateway rd 4*NET_DEVICES_MAX
 
.packets_tx rd NET_DEVICES_MAX
.packets_rx rd NET_DEVICES_MAX
 
endg
 
 
;-----------------------------------------------------------------;
; ;
; ipv6_init: Resets all IPv6 variables ;
; ;
;-----------------------------------------------------------------;
macro ipv6_init {
 
xor eax, eax
mov edi, IPv6
mov ecx, (4*4*4+2*4)MAX_IP
rep stosd
 
}
 
 
 
;-----------------------------------------------------------------;
; ;
; ipv6_input: Check if IPv6 Packet isnt damaged and call ;
; appropriate handler. (TCP/UDP/ICMP/..) ;
; We will also re-construct fragmented packets ;
; ;
; IN: [esp] = ptr to buffer ;
; [esp+4] = size of buffer ;
; ebx = ptr to device struct ;
; edx = ptr to IPv6 header ;
; ecx = size of IPv6 packet ;
; ;
; OUT: / ;
; ;
;-----------------------------------------------------------------;
align 4
ipv6_input:
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input from: %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x\n",\
[edx + IPv6_header.SourceAddress + 0]:2,[edx + IPv6_header.SourceAddress + 1]:2,\
[edx + IPv6_header.SourceAddress + 2]:2,[edx + IPv6_header.SourceAddress + 3]:2,\
[edx + IPv6_header.SourceAddress + 4]:2,[edx + IPv6_header.SourceAddress + 5]:2,\
[edx + IPv6_header.SourceAddress + 6]:2,[edx + IPv6_header.SourceAddress + 7]:2,\
[edx + IPv6_header.SourceAddress + 8]:2,[edx + IPv6_header.SourceAddress + 9]:2,\
[edx + IPv6_header.SourceAddress + 10]:2,[edx + IPv6_header.SourceAddress + 11]:2,\
[edx + IPv6_header.SourceAddress + 12]:2,[edx + IPv6_header.SourceAddress + 13]:2,\
[edx + IPv6_header.SourceAddress + 14]:2,[edx + IPv6_header.SourceAddress + 15]:2
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input to: %x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x\n",\
[edx + IPv6_header.DestinationAddress + 0]:2,[edx + IPv6_header.DestinationAddress + 1]:2,\
[edx + IPv6_header.DestinationAddress + 2]:2,[edx + IPv6_header.DestinationAddress + 3]:2,\
[edx + IPv6_header.DestinationAddress + 4]:2,[edx + IPv6_header.DestinationAddress + 5]:2,\
[edx + IPv6_header.DestinationAddress + 6]:2,[edx + IPv6_header.DestinationAddress + 7]:2,\
[edx + IPv6_header.DestinationAddress + 8]:2,[edx + IPv6_header.DestinationAddress + 9]:2,\
[edx + IPv6_header.DestinationAddress + 10]:2,[edx + IPv6_header.DestinationAddress + 11]:2,\
[edx + IPv6_header.DestinationAddress + 12]:2,[edx + IPv6_header.DestinationAddress + 13]:2,\
[edx + IPv6_header.DestinationAddress + 14]:2,[edx + IPv6_header.DestinationAddress + 15]:2
 
sub ecx, sizeof.IPv6_header
jb .dump
 
cmp cx, [edx + IPv6_header.PayloadLength]
jb .dump
 
;-------------------------------------------------------------------
; No, it's just a regular IP packet, pass it to the higher protocols
 
.handle_it:
movzx ecx, [edx + IPv6_header.PayloadLength]
lea edi, [edx + IPv6_header.SourceAddress] ; make edi ptr to source and dest IPv6 address
lea esi, [edx + IPv6_header.Payload] ; make esi ptr to data
mov al, [edx + IPv6_header.NextHeader]
 
.scan:
cmp al, 59 ; no next
je .dump
 
cmp al, 0
je .hop_by_hop
 
cmp al, 43
je .routing
 
cmp al, 44
je .fragment
 
cmp al, 60
je .dest_opts
 
; cmp al, IP_PROTO_TCP
; je TCP_input
 
; cmp al, IP_PROTO_UDP
; je UDP_input
 
; cmp al, 58
; je ICMP6_input
 
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input - unknown protocol: %u\n", al
 
.dump:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input - dumping\n"
call net_buff_free
ret
 
.dump_options:
add esp, 2+4+4
jmp .dump
 
.nextheader:
pop esi
pop ecx
pop ax
jmp .scan
 
;-------------------------
; Hop-by-Hop
 
.hop_by_hop:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input - hop by hop\n"
pushw [esi] ; 8 bit identifier for option type
movzx eax, byte[esi + 1] ; Hdr Ext Len
inc eax ; first 8 octets not counted
shl eax, 3 ; * 8
sub ecx, eax
push ecx
add eax, esi
push eax
inc esi
inc esi
 
mov al, [esi]
 
cmp al, 0
je .pad_1
 
cmp al, 1
je .pad_n
 
; TODO: check with other known options
 
; unknown option.. discard packet or not?
; check highest two bits
test al, 0xc0 ; discard packet
jnz .dump_options
 
.pad_n:
movzx eax, byte[esi + 1]
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input - pad %u\n", eax
inc esi
inc esi
add esi, eax
sub ecx, eax
jmp .hop_by_hop
 
.pad_1:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input - pad 1\n"
inc esi
dec ecx
jmp .hop_by_hop
 
 
 
.dest_opts:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input - dest opts\n"
jmp .nextheader
 
.routing:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input - routing\n"
pushw [esi] ; 8 bit identifier for option type
movzx eax, byte[esi + 1] ; Hdr Ext Len
inc eax ; first 8 octets not counted
shl eax, 3 ; * 8
sub ecx, eax
push ecx
add eax, esi
push eax
inc esi
inc esi
 
cmp al, 0
je .pad_1
 
cmp al, 1
je .pad_n
 
mov al, [esi] ; routing type
 
jmp .nextheader
 
.fragment:
DEBUGF DEBUG_NETWORK_VERBOSE, "IPv6_input - fragment\n"
 
jmp .nextheader
 
 
 
 
 
 
;-----------------------------------------------------------------;
; ;
; ipv6_api: Part of system function 76 ;
; ;
; IN: bl = subfunction number ;
; bh = device number ;
; ecx, edx, .. depends on subfunction ;
; ;
; OUT: depends on subfunction ;
; ;
;-----------------------------------------------------------------;
align 4
ipv6_api:
 
movzx eax, bh
shl eax, 2
 
and ebx, 0x000000ff
cmp ebx, .number
ja .error
jmp dword [.table + 4*ebx]
 
.table:
dd .packets_tx ; 0
dd .packets_rx ; 1
; dd .read_ip ; 2
; dd .write_ip ; 3
; dd .read_dns ; 4
; dd .write_dns ; 5
; dd .read_subnet ; 6
; dd .write_subnet ; 7
; dd .read_gateway ; 8
; dd .write_gateway ; 9
.number = ($ - .table) / 4 - 1
 
.error:
mov eax, -1
ret
 
.packets_tx:
mov eax, [IPv6.packets_tx + eax]
ret
 
.packets_rx:
mov eax, [IPv6.packets_rx + eax]
ret
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/network
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/const.inc
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
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/asmxygen.py
0,0 → 1,2066
import re
import os
import argparse
import sys
import pickle
 
# Parameters
# Path to doxygen folder to make doxygen files in: -o <path>
doxygen_src_path = 'docs/doxygen'
# Remove generated doxygen files: --clean
clean_generated_stuff = False
# Dump all defined symbols: --dump
dump_symbols = False
# Print symbol stats: --stats
print_stats = False
# Do not write warnings file: --nowarn
enable_warnings = True
 
# Constants
link_root = "http://websvn.kolibrios.org/filedetails.php?repname=Kolibri+OS&path=/kernel/trunk"
 
# fasm keywords
keywords = [
# Generic keywords
"align",
"equ",
"org",
"while",
"load",
"store",
"times",
"repeat",
"virtual",
"display",
"err",
"assert",
"if",
# Instructions
"aaa",
"aad",
"aam",
"aas",
"adc",
"adcx",
"add",
"addpd",
"addps",
"addsd",
"addss",
"addsubpd",
"addsubps",
"adox",
"aesdec",
"aesdeclast",
"aesenc",
"aesenclast",
"aesimc",
"aeskeygenassist",
"and",
"andn",
"andnpd",
"andnps",
"andpd",
"andps",
"arpl",
"bextr",
"blendpd",
"blendps",
"blendvpd",
"blendvps",
"blsi",
"blsmsk",
"blsr",
"bndcl",
"bndcn",
"bndcu",
"bndldx",
"bndmk",
"bndmov",
"bndstx",
"bound",
"bsf",
"bsr",
"bswap",
"bt",
"btc",
"btr",
"bts",
"bzhi",
"call",
"cbw",
"cdq",
"cdqe",
"clac",
"clc",
"cld",
"cldemote",
"clflush",
"clflushopt",
"cli",
"clts",
"clwb",
"cmc",
"cmova",
"cmovae",
"cmovb",
"cmovbe",
"cmovc",
"cmove",
"cmovg",
"cmovge",
"cmovl",
"cmovle",
"cmovna",
"cmovnae",
"cmovnb",
"cmovnbe",
"cmovnc",
"cmovne",
"cmovng",
"cmovnge",
"cmovnl",
"cmovnle",
"cmovno",
"cmovnp",
"cmovns",
"cmovnz",
"cmovo",
"cmovp",
"cmovpe",
"cmovpo",
"cmovs",
"cmovz",
"cmp",
"cmppd",
"cmpps",
"cmps",
"cmpsb",
"cmpsd",
"cmpsd",
"cmpsq",
"cmpss",
"cmpsw",
"cmpxchg",
"cmpxchg16b",
"cmpxchg8b",
"comisd",
"comiss",
"cpuid",
"cqo",
"crc32",
"cvtdq2pd",
"cvtdq2ps",
"cvtpd2dq",
"cvtpd2pi",
"cvtpd2ps",
"cvtpi2pd",
"cvtpi2ps",
"cvtps2dq",
"cvtps2pd",
"cvtps2pi",
"cvtsd2si",
"cvtsd2ss",
"cvtsi2sd",
"cvtsi2ss",
"cvtss2sd",
"cvtss2si",
"cvttpd2dq",
"cvttpd2pi",
"cvttps2dq",
"cvttps2pi",
"cvttsd2si",
"cvttss2si",
"cwd",
"cwde",
"daa",
"das",
"dec",
"div",
"divpd",
"divps",
"divsd",
"divss",
"dppd",
"dpps",
"emms",
"enter",
"extractps",
"f2xm1",
"fabs",
"fadd",
"faddp",
"fbld",
"fbstp",
"fchs",
"fclex",
"fcmova",
"fcmovae",
"fcmovb",
"fcmovbe",
"fcmovc",
"fcmove",
"fcmovg",
"fcmovge",
"fcmovl",
"fcmovle",
"fcmovna",
"fcmovnae",
"fcmovnb",
"fcmovnbe",
"fcmovnc",
"fcmovne",
"fcmovng",
"fcmovnge",
"fcmovnl",
"fcmovnle",
"fcmovno",
"fcmovnp",
"fcmovns",
"fcmovnz",
"fcmovo",
"fcmovp",
"fcmovpe",
"fcmovpo",
"fcmovs",
"fcmovz",
"fcom",
"fcomi",
"fcomip",
"fcomp",
"fcompp",
"fcos",
"fdecstp",
"fdiv",
"fdivp",
"fdivr",
"fdivrp",
"ffree",
"fiadd",
"ficom",
"ficomp",
"fidiv",
"fidivr",
"fild",
"fimul",
"fincstp",
"finit",
"fist",
"fistp",
"fisttp",
"fisub",
"fisubr",
"fld",
"fld1",
"fldcw",
"fldenv",
"fldl2e",
"fldl2t",
"fldlg2",
"fldln2",
"fldpi",
"fldz",
"fmul",
"fmulp",
"fnclex",
"fninit",
"fnop",
"fnsave",
"fnstcw",
"fnstenv",
"fnstsw",
"fpatan",
"fprem",
"fprem1",
"fptan",
"frndint",
"frstor",
"fsave",
"fscale",
"fsin",
"fsincos",
"fsqrt",
"fst",
"fstcw",
"fstenv",
"fstp",
"fstsw",
"fsub",
"fsubp",
"fsubr",
"fsubrp",
"ftst",
"fucom",
"fucomi",
"fucomip",
"fucomp",
"fucompp",
"fwait",
"fxam",
"fxch",
"fxrstor",
"fxsave",
"fxtract",
"fyl2x",
"fyl2xp1",
"gf2p8affineinvqb",
"gf2p8affineqb",
"gf2p8mulb",
"haddpd",
"haddps",
"hlt",
"hsubpd",
"hsubps",
"idiv",
"imul",
"in",
"inc",
"ins",
"insb",
"insd",
"insertps",
"insw",
"int",
"int1",
"int3",
"into",
"invd",
"invlpg",
"invpcid",
"iret",
"iretd",
"jmp",
"ja",
"jae",
"jb",
"jbe",
"jc",
"jcxz",
"jecxz",
"je",
"jg",
"jge",
"jl",
"jle",
"jna",
"jnae",
"jnb",
"jnbe",
"jnc",
"jne",
"jng",
"jnge",
"jnl",
"jnle",
"jno",
"jnp",
"jns",
"jnz",
"jo",
"jp",
"jpe",
"jpo",
"js",
"jz",
"kaddb",
"kaddd",
"kaddq",
"kaddw",
"kandb",
"kandd",
"kandnb",
"kandnd",
"kandnq",
"kandnw",
"kandq",
"kandw",
"kmovb",
"kmovd",
"kmovq",
"kmovw",
"knotb",
"knotd",
"knotq",
"knotw",
"korb",
"kord",
"korq",
"kortestb",
"kortestd",
"kortestq",
"kortestw",
"korw",
"kshiftlb",
"kshiftld",
"kshiftlq",
"kshiftlw",
"kshiftrb",
"kshiftrd",
"kshiftrq",
"kshiftrw",
"ktestb",
"ktestd",
"ktestq",
"ktestw",
"kunpckbw",
"kunpckdq",
"kunpckwd",
"kxnorb",
"kxnord",
"kxnorq",
"kxnorw",
"kxorb",
"kxord",
"kxorq",
"kxorw",
"lahf",
"lar",
"lddqu",
"ldmxcsr",
"lds",
"lea",
"leave",
"les",
"lfence",
"lfs",
"lgdt",
"lgs",
"lidt",
"lldt",
"lmsw",
"lock",
"lods",
"lodsb",
"lodsd",
"lodsq",
"lodsw",
"loop",
"loopa",
"loopae",
"loopb",
"loopbe",
"loopc",
"loope",
"loopg",
"loopge",
"loopl",
"loople",
"loopna",
"loopnae",
"loopnb",
"loopnbe",
"loopnc",
"loopne",
"loopng",
"loopnge",
"loopnl",
"loopnle",
"loopno",
"loopnp",
"loopns",
"loopnz",
"loopo",
"loopp",
"looppe",
"looppo",
"loops",
"loopz",
"lsl",
"lss",
"ltr",
"lzcnt",
"maskmovdqu",
"maskmovq",
"maxpd",
"maxps",
"maxsd",
"maxss",
"mfence",
"minpd",
"minps",
"minsd",
"minss",
"monitor",
"mov",
"movapd",
"movaps",
"movbe",
"movd",
"movddup",
"movdir64b",
"movdiri",
"movdq2q",
"movdqa",
"movdqu",
"movhlps",
"movhpd",
"movhps",
"movlhps",
"movlpd",
"movlps",
"movmskpd",
"movmskps",
"movntdq",
"movntdqa",
"movnti",
"movntpd",
"movntps",
"movntq",
"movq",
"movq",
"movq2dq",
"movs",
"movsb",
"movsd",
"movsd",
"movshdup",
"movsldup",
"movsq",
"movss",
"movsw",
"movsx",
"movsxd",
"movupd",
"movups",
"movzx",
"mpsadbw",
"mul",
"mulpd",
"mulps",
"mulsd",
"mulss",
"mulx",
"mwait",
"neg",
"nop",
"not",
"or",
"orpd",
"orps",
"out",
"outs",
"outsb",
"outsd",
"outsw",
"pabsb",
"pabsd",
"pabsq",
"pabsw",
"packssdw",
"packsswb",
"packusdw",
"packuswb",
"paddb",
"paddd",
"paddq",
"paddsb",
"paddsw",
"paddusb",
"paddusw",
"paddw",
"palignr",
"pand",
"pandn",
"pause",
"pavgb",
"pavgw",
"pblendvb",
"pblendw",
"pclmulqdq",
"pcmpeqb",
"pcmpeqd",
"pcmpeqq",
"pcmpeqw",
"pcmpestri",
"pcmpestrm",
"pcmpgtb",
"pcmpgtd",
"pcmpgtq",
"pcmpgtw",
"pcmpistri",
"pcmpistrm",
"pdep",
"pext",
"pextrb",
"pextrd",
"pextrq",
"pextrw",
"phaddd",
"phaddsw",
"phaddw",
"phminposuw",
"phsubd",
"phsubsw",
"phsubw",
"pinsrb",
"pinsrd",
"pinsrq",
"pinsrw",
"pmaddubsw",
"pmaddwd",
"pmaxsb",
"pmaxsd",
"pmaxsq",
"pmaxsw",
"pmaxub",
"pmaxud",
"pmaxuq",
"pmaxuw",
"pminsb",
"pminsd",
"pminsq",
"pminsw",
"pminub",
"pminud",
"pminuq",
"pminuw",
"pmovmskb",
"pmovsx",
"pmovzx",
"pmuldq",
"pmulhrsw",
"pmulhuw",
"pmulhw",
"pmulld",
"pmullq",
"pmullw",
"pmuludq",
"pop",
"popa",
"popad",
"popcnt",
"popf",
"popfd",
"popfq",
"por",
"prefetchw",
"prefetchh",
"psadbw",
"pshufb",
"pshufd",
"pshufhw",
"pshuflw",
"pshufw",
"psignb",
"psignd",
"psignw",
"pslld",
"pslldq",
"psllq",
"psllw",
"psrad",
"psraq",
"psraw",
"psrld",
"psrldq",
"psrlq",
"psrlw",
"psubb",
"psubd",
"psubq",
"psubsb",
"psubsw",
"psubusb",
"psubusw",
"psubw",
"ptest",
"ptwrite",
"punpckhbw",
"punpckhdq",
"punpckhqdq",
"punpckhwd",
"punpcklbw",
"punpckldq",
"punpcklqdq",
"punpcklwd",
"push",
"pushw",
"pushd",
"pusha",
"pushad",
"pushf",
"pushfd",
"pushfq",
"pxor",
"rcl",
"rcpps",
"rcpss",
"rcr",
"rdfsbase",
"rdgsbase",
"rdmsr",
"rdpid",
"rdpkru",
"rdpmc",
"rdrand",
"rdseed",
"rdtsc",
"rdtscp",
"rep",
"repe",
"repne",
"repnz",
"repz",
"ret",
"rol",
"ror",
"rorx",
"roundpd",
"roundps",
"roundsd",
"roundss",
"rsm",
"rsqrtps",
"rsqrtss",
"sahf",
"sal",
"sar",
"sarx",
"sbb",
"scas",
"scasb",
"scasd",
"scasw",
"seta",
"setae",
"setb",
"setbe",
"setc",
"sete",
"setg",
"setge",
"setl",
"setle",
"setna",
"setnae",
"setnb",
"setnbe",
"setnc",
"setne",
"setng",
"setnge",
"setnl",
"setnle",
"setno",
"setnp",
"setns",
"setnz",
"seto",
"setp",
"setpe",
"setpo",
"sets",
"setz",
"sfence",
"sgdt",
"sha1msg1",
"sha1msg2",
"sha1nexte",
"sha1rnds4",
"sha256msg1",
"sha256msg2",
"sha256rnds2",
"shl",
"shld",
"shlx",
"shr",
"shrd",
"shrx",
"shufpd",
"shufps",
"sidt",
"sldt",
"smsw",
"sqrtpd",
"sqrtps",
"sqrtsd",
"sqrtss",
"stac",
"stc",
"std",
"sti",
"stmxcsr",
"stos",
"stosb",
"stosd",
"stosq",
"stosw",
"str",
"sub",
"subpd",
"subps",
"subsd",
"subss",
"swapgs",
"syscall",
"sysenter",
"sysexit",
"sysret",
"test",
"tpause",
"tzcnt",
"ucomisd",
"ucomiss",
"ud",
"umonitor",
"umwait",
"unpckhpd",
"unpckhps",
"unpcklpd",
"unpcklps",
"valignd",
"valignq",
"vblendmpd",
"vblendmps",
"vbroadcast",
"vcompresspd",
"vcompressps",
"vcvtpd2qq",
"vcvtpd2udq",
"vcvtpd2uqq",
"vcvtph2ps",
"vcvtps2ph",
"vcvtps2qq",
"vcvtps2udq",
"vcvtps2uqq",
"vcvtqq2pd",
"vcvtqq2ps",
"vcvtsd2usi",
"vcvtss2usi",
"vcvttpd2qq",
"vcvttpd2udq",
"vcvttpd2uqq",
"vcvttps2qq",
"vcvttps2udq",
"vcvttps2uqq",
"vcvttsd2usi",
"vcvttss2usi",
"vcvtudq2pd",
"vcvtudq2ps",
"vcvtuqq2pd",
"vcvtuqq2ps",
"vcvtusi2sd",
"vcvtusi2ss",
"vdbpsadbw",
"verr",
"verw",
"vexpandpd",
"vexpandps",
"vextractf128",
"vextractf32x4",
"vextractf32x8",
"vextractf64x2",
"vextractf64x4",
"vextracti128",
"vextracti32x4",
"vextracti32x8",
"vextracti64x2",
"vextracti64x4",
"vfixupimmpd",
"vfixupimmps",
"vfixupimmsd",
"vfixupimmss",
"vfmadd132pd",
"vfmadd132ps",
"vfmadd132sd",
"vfmadd132ss",
"vfmadd213pd",
"vfmadd213ps",
"vfmadd213sd",
"vfmadd213ss",
"vfmadd231pd",
"vfmadd231ps",
"vfmadd231sd",
"vfmadd231ss",
"vfmaddsub132pd",
"vfmaddsub132ps",
"vfmaddsub213pd",
"vfmaddsub213ps",
"vfmaddsub231pd",
"vfmaddsub231ps",
"vfmsub132pd",
"vfmsub132ps",
"vfmsub132sd",
"vfmsub132ss",
"vfmsub213pd",
"vfmsub213ps",
"vfmsub213sd",
"vfmsub213ss",
"vfmsub231pd",
"vfmsub231ps",
"vfmsub231sd",
"vfmsub231ss",
"vfmsubadd132pd",
"vfmsubadd132ps",
"vfmsubadd213pd",
"vfmsubadd213ps",
"vfmsubadd231pd",
"vfmsubadd231ps",
"vfnmadd132pd",
"vfnmadd132ps",
"vfnmadd132sd",
"vfnmadd132ss",
"vfnmadd213pd",
"vfnmadd213ps",
"vfnmadd213sd",
"vfnmadd213ss",
"vfnmadd231pd",
"vfnmadd231ps",
"vfnmadd231sd",
"vfnmadd231ss",
"vfnmsub132pd",
"vfnmsub132ps",
"vfnmsub132sd",
"vfnmsub132ss",
"vfnmsub213pd",
"vfnmsub213ps",
"vfnmsub213sd",
"vfnmsub213ss",
"vfnmsub231pd",
"vfnmsub231ps",
"vfnmsub231sd",
"vfnmsub231ss",
"vfpclasspd",
"vfpclassps",
"vfpclasssd",
"vfpclassss",
"vgatherdpd",
"vgatherdpd",
"vgatherdps",
"vgatherdps",
"vgatherqpd",
"vgatherqpd",
"vgatherqps",
"vgatherqps",
"vgetexppd",
"vgetexpps",
"vgetexpsd",
"vgetexpss",
"vgetmantpd",
"vgetmantps",
"vgetmantsd",
"vgetmantss",
"vinsertf128",
"vinsertf32x4",
"vinsertf32x8",
"vinsertf64x2",
"vinsertf64x4",
"vinserti128",
"vinserti32x4",
"vinserti32x8",
"vinserti64x2",
"vinserti64x4",
"vmaskmov",
"vmovdqa32",
"vmovdqa64",
"vmovdqu16",
"vmovdqu32",
"vmovdqu64",
"vmovdqu8",
"vpblendd",
"vpblendmb",
"vpblendmd",
"vpblendmq",
"vpblendmw",
"vpbroadcast",
"vpbroadcastb",
"vpbroadcastd",
"vpbroadcastm",
"vpbroadcastq",
"vpbroadcastw",
"vpcmpb",
"vpcmpd",
"vpcmpq",
"vpcmpub",
"vpcmpud",
"vpcmpuq",
"vpcmpuw",
"vpcmpw",
"vpcompressd",
"vpcompressq",
"vpconflictd",
"vpconflictq",
"vperm2f128",
"vperm2i128",
"vpermb",
"vpermd",
"vpermi2b",
"vpermi2d",
"vpermi2pd",
"vpermi2ps",
"vpermi2q",
"vpermi2w",
"vpermilpd",
"vpermilps",
"vpermpd",
"vpermps",
"vpermq",
"vpermt2b",
"vpermt2d",
"vpermt2pd",
"vpermt2ps",
"vpermt2q",
"vpermt2w",
"vpermw",
"vpexpandd",
"vpexpandq",
"vpgatherdd",
"vpgatherdd",
"vpgatherdq",
"vpgatherdq",
"vpgatherqd",
"vpgatherqd",
"vpgatherqq",
"vpgatherqq",
"vplzcntd",
"vplzcntq",
"vpmadd52huq",
"vpmadd52luq",
"vpmaskmov",
"vpmovb2m",
"vpmovd2m",
"vpmovdb",
"vpmovdw",
"vpmovm2b",
"vpmovm2d",
"vpmovm2q",
"vpmovm2w",
"vpmovq2m",
"vpmovqb",
"vpmovqd",
"vpmovqw",
"vpmovsdb",
"vpmovsdw",
"vpmovsqb",
"vpmovsqd",
"vpmovsqw",
"vpmovswb",
"vpmovusdb",
"vpmovusdw",
"vpmovusqb",
"vpmovusqd",
"vpmovusqw",
"vpmovuswb",
"vpmovw2m",
"vpmovwb",
"vpmultishiftqb",
"vprold",
"vprolq",
"vprolvd",
"vprolvq",
"vprord",
"vprorq",
"vprorvd",
"vprorvq",
"vpscatterdd",
"vpscatterdq",
"vpscatterqd",
"vpscatterqq",
"vpsllvd",
"vpsllvq",
"vpsllvw",
"vpsravd",
"vpsravq",
"vpsravw",
"vpsrlvd",
"vpsrlvq",
"vpsrlvw",
"vpternlogd",
"vpternlogq",
"vptestmb",
"vptestmd",
"vptestmq",
"vptestmw",
"vptestnmb",
"vptestnmd",
"vptestnmq",
"vptestnmw",
"vrangepd",
"vrangeps",
"vrangesd",
"vrangess",
"vrcp14pd",
"vrcp14ps",
"vrcp14sd",
"vrcp14ss",
"vreducepd",
"vreduceps",
"vreducesd",
"vreducess",
"vrndscalepd",
"vrndscaleps",
"vrndscalesd",
"vrndscaless",
"vrsqrt14pd",
"vrsqrt14ps",
"vrsqrt14sd",
"vrsqrt14ss",
"vscalefpd",
"vscalefps",
"vscalefsd",
"vscalefss",
"vscatterdpd",
"vscatterdps",
"vscatterqpd",
"vscatterqps",
"vshuff32x4",
"vshuff64x2",
"vshufi32x4",
"vshufi64x2",
"vtestpd",
"vtestps",
"vzeroall",
"vzeroupper",
"wait",
"wbinvd",
"wrfsbase",
"wrgsbase",
"wrmsr",
"wrpkru",
"xabort",
"xacquire",
"xadd",
"xbegin",
"xchg",
"xend",
"xgetbv",
"xlat",
"xlatb",
"xor",
"xorpd",
"xorps",
"xrelease",
"xrstor",
"xrstors",
"xsave",
"xsavec",
"xsaveopt",
"xsaves",
"xsetbv",
"xtest"
]
 
fasm_types = [
"db", "rb",
"dw", "rw",
"dd", "rd",
"dp", "rp",
"df", "rf",
"dq", "rq",
"dt", "rt",
"du",
]
 
# Dict where an identifier is assicoated with a string
# The string contains characters specifying flags
# Available flags:
# k - Keyword
# m - Macro name
# t - fasm data Type name (db, rq, etc.)
# s - Struct type name
# e - equated constant (name equ value)
# = - set constants (name = value)
ID_KIND_KEYWORD = 'k'
ID_KIND_MACRO_NAME = 'm'
ID_KIND_FASM_TYPE = 't'
ID_KIND_STRUCT_NAME = 's'
ID_KIND_EQUATED_CONSTANT = 'e'
ID_KIND_SET_CONSTANT = '='
id2kind = {}
 
# Add kind flag to identifier in id2kind
def id_add_kind(identifier, kind):
if identifier not in id2kind:
id2kind[identifier] = ''
id2kind[identifier] += kind
 
# Remove kind flag of identifier in id2kind
def id_remove_kind(identifier, kind):
if identifier in id2kind:
if kind in id2kind[identifier]:
id2kind[identifier] = id2kind[identifier].replace(kind, '')
 
# Get kind of an identifier
def id_get_kind(identifier):
if identifier in id2kind:
return id2kind[identifier]
else:
return ''
 
for keyword in keywords:
id_add_kind(keyword, ID_KIND_KEYWORD)
 
for fasm_type in fasm_types:
id_add_kind(fasm_type, ID_KIND_FASM_TYPE)
 
# Warning list
warnings = ""
 
# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument("-o", help="Doxygen output folder")
parser.add_argument("--clean", help="Remove generated files", action="store_true")
parser.add_argument("--dump", help="Dump all defined symbols", action="store_true")
parser.add_argument("--stats", help="Print symbol stats", action="store_true")
parser.add_argument("--nowarn", help="Do not write warnings file", action="store_true")
parser.add_argument("--noemit", help="Do not emit doxygen files (for testing)", action="store_true")
args = parser.parse_args()
doxygen_src_path = args.o if args.o else 'docs/doxygen'
clean_generated_stuff = args.clean
dump_symbols = args.dump
print_stats = args.stats
enable_warnings = not args.nowarn
noemit = args.noemit
 
# Variables, functions, labels, macros, structure types
elements = []
 
class LegacyAsmReader:
def __init__(self, file):
self.file = file
self.lines = open(file, "r", encoding="utf-8").readlines()
self.line_idx = 0
self.i = 0
 
def curr(self):
try: return self.lines[self.line_idx][self.i]
except: return ''
 
def step(self):
c = self.curr()
self.i += 1
# Wrap the line if '\\' followed by whitespaces and/or comment
while self.curr() == '\\':
i_of_backslash = self.i
self.i += 1
while self.curr().isspace():
self.i += 1
if self.curr() == ';' or self.curr() == '':
self.line_idx += 1
self.i = 0
else:
# There's something other than a comment after the backslash
# So don't interpret the backslash as a line wrap
self.i = i_of_backslash
break
return c
 
def nextline(self):
c = self.curr()
while c != '':
c = self.step()
self.line_idx += 1
self.i = 0
 
def no_lines(self):
if self.line_idx >= len(self.lines):
return True
return False
 
def location(self):
return f"{self.file}:{self.line_idx + 1}"
 
def skip_spaces(self):
while self.curr().isspace():
self.step()
 
class AsmReaderRecognizingStrings(LegacyAsmReader):
def __init__(self, file):
super().__init__(file)
self.in_string = None
self.should_recognize_strings = True
 
def step(self):
c = super().step()
if self.should_recognize_strings and (c == '"' or c == "'"):
# If just now we was at the double or single quotation mark
# and we aren't in a string yet
# then say "we are in a string openned with this quotation mark now"
if self.in_string == None:
self.in_string = c
# If just now we was at the double or single quotation mark
# and we are in the string entered with the same quotation mark
# then say "we aren't in a string anymore"
elif self.in_string == c:
self.in_string = None
return c
 
class AsmReaderReadingComments(AsmReaderRecognizingStrings):
def __init__(self, file):
super().__init__(file)
self.status = dict()
self.status_reset()
self.comment = ''
 
def status_reset(self):
# If the line has non-comment code
self.status_has_code = False
# If the line has a comment at the end
self.status_has_comment = False
# Let it recognize strings further, we are definitely out of a comment
self.should_recognize_strings = True
 
def status_set_has_comment(self):
self.status_has_comment = True
# Don't let it recognize strings cause we are in a comment now
self.should_recognize_strings = False
 
def status_set_has_code(self):
self.status_has_code = True
 
def update_status(self):
# If we aren't in a comment and we aren't in a string - say we are now in a comment if ';' met
if not self.status_has_comment and not self.in_string and self.curr() == ';':
self.status_set_has_comment()
# Else if we are in a comment - collect the comment
elif self.status_has_comment:
self.comment += self.curr()
# Else if there's some non-whitespace character out of a comment
# then the line has code
elif not self.status_has_comment and not self.curr().isspace():
self.status_set_has_code()
 
def step(self):
# Get to the next character
c = super().step()
# Update status of the line according to the next character
self.update_status()
return c
 
def nextline(self):
super().nextline()
# If the line we leave was not a comment-only line
# then forget the collected comment
# Otherwise the collected comment should be complemented by comment from next line in step()
if self.status_has_code:
self.comment = ''
# Reset the line status (now it's the status of the new line)
self.status_reset()
# Set new status for this line according to the first character in the line
self.update_status()
 
class AsmReaderFetchingIdentifiers(AsmReaderReadingComments):
def __init__(self, file):
super().__init__(file)
 
def fetch_identifier(self):
self.skip_spaces()
result = ''
while is_id(self.curr()):
result += self.step()
return result
 
class AsmReader(AsmReaderFetchingIdentifiers):
def __init__(self, file):
super().__init__(file)
 
created_files = []
 
class AsmElement:
def __init__(self, location, name, comment):
global warnings
 
# If the element was constructed during this execution then the element is new
self.new = True
self.location = location
self.file = self.location.split(':')[0].replace('\\', '/')
self.line = self.location.split(':')[1]
self.name = name
self.comment = comment
 
if self.comment == '':
warnings += f'{self.location}: Undocumented element\n'
 
def dump(self):
print(f"\n{self.location}: {self.name}")
print(f"{self.comment}")
 
def emit(self, dest, doxycomment = '', declaration = ''):
# Do not emit anything if the symbol is marked as hidden in its comment
if '@dont_give_a_doxygen' in self.comment:
return
 
global warnings
# Redefine default declaration
if declaration == '':
declaration = f'#define {self.name}'
# Check doxycomment
if not doxycomment.endswith('\n'):
doxycomment += '\n'
if doxycomment.split('@brief ')[1][0].islower():
warnings += f"{self.location}: Brief comment starting from lowercase\n"
# Build contents to emit
contents = ''
contents += '/**\n'
contents += doxycomment
contents += (f"@par Source\n" +
f"<a href='{link_root}/{self.file}#line-{self.line}'>{self.file}:{self.line}</a>\n")
contents += '*/\n'
contents += declaration
contents += '\n\n'
# Get path to file to emit this
full_path = dest + '/' + self.file
# Remove the file on first access if it was created by previous generation
if full_path not in created_files:
if os.path.isfile(full_path):
os.remove(full_path)
created_files.append(full_path)
# Create directories need for the file
os.makedirs(os.path.dirname(full_path), exist_ok=True)
f = open(full_path, "a")
contents = ''.join([i if ord(i) < 128 else '?' for i in contents])
f.write(contents)
f.close()
 
class AsmVariable(AsmElement):
def __init__(self, location, name, comment, type, init):
super().__init__(location, name, comment)
self.type = type
self.init = init
 
def dump(self):
super().dump()
print(f"(Variable)\n---")
 
def emit(self, dest):
# Build doxycomment specific for the variable
doxycomment = ''
doxycomment += self.comment
if '@brief' not in doxycomment:
doxycomment = '@brief ' + doxycomment
doxycomment += (f"@par Initial value\n" +
f"{self.init}\n")
# Build the declaration
name = self.name.replace(".", "_")
var_type = self.type.replace(".", "_")
declaration = f"{var_type} {name};"
# Emit this
super().emit(dest, doxycomment, declaration)
 
class AsmFunction(AsmElement):
def __init__(self, location, name, comment, calling_convention, args, used_regs):
super().__init__(location, name, comment)
self.calling_convention = calling_convention
self.args = args
self.used_regs = used_regs
 
def dump(self):
super().dump()
print(f"(Function)\n---")
 
def emit(self, dest):
# Build doxycomment specific for the variable
doxycomment = ''
doxycomment += self.comment
if '@brief' not in doxycomment:
doxycomment = '@brief ' + doxycomment
# If there was no arguments, maybe that's just a label
# then parse parameters from its comment
if len(self.args) == 0 and '@param' in self.comment:
i = 0
while '@param' in self.comment[i:]:
i = self.comment.index('@param', i)
# Skip '@param'
i += len('@param')
# Skip spaces after '@param'
while self.comment[i].isspace():
i += 1
# Get the parameter name
name = ''
while is_id(self.comment[i]):
name += self.comment[i]
i += 1
# Save the parameter
self.args.append((name, 'arg_t'))
# Build the arg list for declaration
arg_list = '('
if len(self.args) > 0:
argc = 0
for arg in self.args:
if argc != 0:
arg_list += ", "
arg_list += f"{arg[1]} {arg[0]}"
argc += 1
arg_list += ')'
# Build the declaration
name = self.name.replace(".", "_")
declaration = f"void {name}{arg_list};"
# Emit this
super().emit(dest, doxycomment, declaration)
 
class AsmLabel(AsmElement):
def __init__(self, location, name, comment):
super().__init__(location, name, comment)
 
def dump(self):
super().dump()
print(f"(Label)\n---")
 
def emit(self, dest):
# Build doxycomment specific for the variable
doxycomment = ''
doxycomment += self.comment
if '@brief' not in doxycomment:
doxycomment = '@brief ' + doxycomment
# Build the declaration
name = self.name.replace(".", "_")
declaration = f"label {name};"
# Emit this
super().emit(dest, doxycomment, declaration)
 
class AsmMacro(AsmElement):
def __init__(self, location, name, comment, args):
super().__init__(location, name, comment)
self.args = args
 
def dump(self):
super().dump()
print(f"(Macro)\n---")
 
def emit(self, dest):
# Construct arg list without '['s, ']'s and '*'s
args = [arg for arg in self.args if arg not in "[]*"]
# Construct C-like arg list
arg_list = ""
if len(args) > 0:
arg_list += '('
argc = 0
for arg in args:
if argc != 0:
arg_list += ", "
arg_list += arg
argc += 1
arg_list += ')'
# Build doxycomment
doxycomment = ''
doxycomment += self.comment
if '@brief' not in doxycomment:
doxycomment = '@brief ' + doxycomment
# Build declaration
declaration = f"#define {self.name}{arg_list}"
# Emit this
super().emit(dest, doxycomment, declaration)
 
class AsmStruct(AsmElement):
def __init__(self, location, name, comment, members):
super().__init__(location, name, comment)
self.members = members
 
def dump(self):
super().dump()
print(f"(Struct)\n---")
 
def emit(self, dest):
# Build doxycomment
doxycomment = ''
doxycomment += self.comment
if '@brief' not in doxycomment:
doxycomment = '@brief ' + doxycomment
doxycomment += '\n'
# Build declaration
declaration = f"struct {self.name}" + " {\n"
for member in self.members:
if type(member) == AsmVariable:
declaration += f'\t{member.type} {member.name}; /**< {member.comment} */\n'
declaration += '};'
# Emit this
super().emit(dest, doxycomment, declaration)
 
class AsmUnion(AsmElement):
def __init__(self, location, name, comment, members):
super().__init__(location, name, comment)
self.members = members
 
def dump(self):
super().dump()
print(f"(Union)\n---")
 
def emit(self, dest):
# Build doxycomment
doxycomment = ''
doxycomment += self.comment
if '@brief' not in doxycomment:
doxycomment = '@brief ' + doxycomment
# Build declaration
declaration = f"union {self.name}" + " {};"
# Emit this
super().emit(dest, doxycomment, declaration)
 
class VariableNameIsMacroName:
def __init__(self, name):
self.name = name
 
def is_id(c):
return c.isprintable() and c not in "+-/*=<>()[]{};:,|&~#`'\" \n\r\t\v"
 
def is_starts_as_id(s):
return not s[0].isdigit()
 
def parse_after_macro(r):
location = r.location()
 
# Skip spaces after the "macro" keyword
r.skip_spaces()
# Read macro name
name = ""
while is_id(r.curr()) or r.curr() == '#':
name += r.step()
# Skip spaces after macro name
r.skip_spaces()
# Find all arguments
args = []
arg = ''
while r.curr() and r.curr() != ';' and r.curr() != '{':
# Collect identifier
if is_id(r.curr()):
arg += r.step()
# Save the collected identifier
elif r.curr() == ',':
args.append(arg)
arg = ''
r.step()
# Just push the '['
elif r.curr() == '[':
args.append(r.step())
# Just push the identifier and get ']' ready to be pushed on next comma
elif r.curr() == ']':
args.append(arg)
arg = r.step()
# Just push the identifier and get '*' ready to be pushed on next comma
elif r.curr() == '*':
args.append(arg)
arg = r.step()
# Just skip whitespaces
elif r.curr().isspace():
r.step()
# Something unexpected
else:
raise Exception(f"Unexpected symbol '{r.curr()}' at index #{r.i} " +
f"in the macro declaration at {location} " +
f"(line: {r.lines[r.line_idx]})\n''")
# Append the last argument
if arg != '':
args.append(arg)
# Skip t spaces after the argument list
r.skip_spaces()
# Get a comment if it is: read till the end of the line and get the comment from the reader
while r.curr() != '':
r.step()
comment = r.comment
# Find end of the macro
prev = ''
while True:
if r.curr() == '}' and prev != '\\':
break
elif r.curr() == '':
prev = ''
r.nextline()
continue
prev = r.step()
# Build the output
return AsmMacro(location, name, comment, args)
 
def parse_variable(r, first_word = None):
global warnings
location = r.location()
 
# Skip spaces before variable name
r.skip_spaces()
# Get variable name
name = ""
# Read it if it was not supplied
if first_word == None:
while is_id(r.curr()):
name += r.step()
# Or use the supplied one instead
else:
name = first_word
# Check the name
# If it's 0 len, that means threr's something else than an identifier at the beginning
if len(name) == 0:
return None
# If it starts from digit or othervice illegally it's illegal
if not is_starts_as_id(name):
return None
# Get kind of the identifier from id2kind table
kind = id_get_kind(name)
# If it's a keyword, that's not a variable declaration
if ID_KIND_KEYWORD in kind:
return None
# If it's a macro name, that's not a variable declaration
if ID_KIND_MACRO_NAME in kind:
return VariableNameIsMacroName(name)
# If it's a datatype or a structure name that's not a variable declaration: that's just a data
# don't document just a data for now
if ID_KIND_STRUCT_NAME in kind or ID_KIND_FASM_TYPE in kind:
return None
# Skip spaces before type name
r.skip_spaces()
# Read type name
var_type = ""
while is_id(r.curr()):
var_type += r.step()
# Check the type name
if len(var_type) == 0:
# If there's no type identifier after the name
# maybe the name is something meaningful for the next parser
# return it
return name
# If it starts from digit or othervice illegally it's illegal
if not is_starts_as_id(var_type):
return None
# Get kind of type identifier
type_kind = id_get_kind(var_type)
# If it's a keyword, that's not a variable declaration
# return the two words of the lexical structure
if ID_KIND_KEYWORD in type_kind:
return (name, var_type)
# Skip spaces before the value
r.skip_spaces()
# Read the value until the comment or end of the line
value = ""
while r.curr() != ';' and r.curr() != '' and r.curr() != '\n':
value += r.step()
# Skip spaces after the value
r.skip_spaces()
# Read till end of the line to get a comment from the reader
while r.curr() != '':
r.step()
# Build the result
return AsmVariable(location, name, r.comment, var_type, value)
 
def parse_after_struct(r, as_union = True):
global warnings
location = r.location()
 
# Skip spaces after "struct" keyword
r.skip_spaces()
# Read struct name
name = ""
while is_id(r.curr()):
name += r.step()
# Read till end of the line and get the comment from the reader
while r.curr() != '':
r.step()
comment = r.comment
# Get to the next line to parse struct members
r.nextline()
# Parse struct members
members = []
while True:
r.skip_spaces()
var = parse_variable(r)
if type(var) == AsmVariable:
members.append(var)
elif type(var) == str:
if var == 'union':
# Parse the union as a struct
union = parse_after_struct(r, as_union = True)
members.append(union)
# Skip the ends of the union
r.nextline()
elif r.curr() == ':':
warnings += f"{r.location()}: Skept the label in the struct\n"
else:
raise Exception(f"Garbage in struct member at {location} (got '{var}' identifier)")
elif type(var) == VariableNameIsMacroName:
if var.name == 'ends':
break
r.nextline()
# Return the result
if as_union:
return AsmStruct(location, name, comment, members)
else:
return AsmUnion(location, name, comment, members)
 
def parse_after_proc(r):
# Get proc name
name = r.fetch_identifier()
# Next identifier after the proc name
identifier = r.fetch_identifier()
# Check if the id is 'stdcall' or 'c' (calling convention specifier)
# and if so - save the convention and lookup the next identifier
calling_convention = ''
if identifier == 'stdcall' or identifier == 'c':
calling_convention = identifier
# If next is a comma, just skip it
if r.curr() == ',':
r.step()
# Read the next identifier
identifier = r.fetch_identifier()
# Check if the id is 'uses' (used register list specifier)
# and if so save the used register list
used_regs = []
if identifier == 'uses':
# Read the registers
while True:
reg_name = r.fetch_identifier()
if reg_name != '':
used_regs.append(reg_name)
else:
break
# If next is a comma, just skip it
if r.curr() == ',':
r.step()
# Read the next identifier
identifier = r.fetch_identifier()
# Check if there are argument identifiers
args = []
while identifier != '':
arg_name = identifier
arg_type = 'arg_t'
# Skip spaces after argument name
r.skip_spaces()
# If there's a ':' after the name - the next identifier is type
if r.curr() == ':':
r.step()
arg_type = r.fetch_identifier()
# If there's a comma - there's one more argument
# else no arguments anymore
if r.curr() == ',':
r.step()
identifier = r.fetch_identifier()
else:
identifier = ''
args.append((arg_name, arg_type))
# Get to the end of the line and get a comment from the reader
while r.curr() != '':
r.step()
comment = r.comment
# Build the element
return AsmFunction(r.location(), name, comment, calling_convention, args, used_regs)
 
def get_declarations(asm_file_contents, asm_file_name):
r = AsmReader(asm_file_name)
 
while not r.no_lines():
# Skip leading spaces
r.skip_spaces()
# Skip the line if it's starting with a comment
if r.curr() == ';':
r.nextline()
continue
# Get first word
first_word = ""
while is_id(r.curr()):
first_word += r.step()
# Match macro declaration
if first_word == "macro":
macro = parse_after_macro(r)
elements.append(macro)
id_add_kind(macro.name, ID_KIND_MACRO_NAME)
# Match structure declaration
elif first_word == "struct":
struct = parse_after_struct(r)
elements.append(struct)
id_add_kind(struct.name, ID_KIND_STRUCT_NAME)
# Match function definition
elif first_word == "proc":
proc = parse_after_proc(r)
elements.append(proc)
elif first_word == 'format':
# Skip the format directive
pass
elif first_word == 'include':
# Skip the include directive
pass
elif first_word == 'if':
# Skip the conditional directive
pass
elif first_word == 'repeat':
# Skip the repeat directive
pass
elif first_word == 'purge':
while True:
# Skip spaces after the 'purge' keyword or after the comma what separated the previous macro name
r.skip_spaces()
# Get the purged macro name
name = ''
while is_id(r.curr()):
name += r.step()
# Remove the purged macro from the macro names list
try:
id_remove_kind(name, ID_KIND_MACRO_NAME)
except:
pass
# Skip spaces after the name
r.skip_spaces()
# If it's comma (',') after then that's not the last purged macro, continue purging
if r.curr() == ',':
r.step()
continue
# Here we purged all the macros should be purged
break
# Match label or a variable
elif len(first_word) != 0:
# Skip spaces after the identifier
r.skip_spaces()
# Match a variable
var = parse_variable(r, first_word)
if type(var) == AsmVariable:
elements.append(var)
# If it wasn't a variable but there was an identifier
# Maybe that's a label and the identifier is the label name
# The parse_variable returns the first found or supplied identifier
# In this case it returns the first_word which is supplied
# If it didn't match a type identifier after the word
elif type(var) == str:
name = var
# Match label beginning (':' after name)
if r.curr() == ':':
# Get to the end of the line and get the coment from the reader
while r.curr() != '':
r.step()
comment = r.comment
# Only handle non-local labels
if name[0] != '.' and name != "@@" and name != "$Revision":
if '@return' in comment or '@param' in comment:
element = AsmFunction(r.location(), name, comment, '', [], [])
else:
element = AsmLabel(r.location(), name, comment)
elements.append(element)
elif r.curr() == '=':
# Save the identifier as a set constant
id_add_kind(first_word, ID_KIND_SET_CONSTANT)
elif type(var) == tuple:
(word_one, word_two) = var
if word_two == 'equ':
# Save the identifier as an equated constant
id_add_kind(word_one, ID_KIND_EQUATED_CONSTANT)
r.nextline()
 
def it_neds_to_be_parsed(source_file):
# If there's no symbols file saved - parse it anyway
# cause we need to create the symbols file and use it
# if we gonna generate proper doxygen
if not os.path.isfile('asmxygen.elements.pickle'):
return True
dest = doxygen_src_path + '/' + source_file
# If there's no the doxygen file it should be compiled to
# then yes, we should compile it to doxygen
if not os.path.isfile(dest):
return True
source_change_time = os.path.getmtime(source_file)
dest_change_file = os.path.getmtime(dest)
# If the source is newer than the doxygen it was compiled to
# then the source should be recompiled (existing doxygen is old)
if source_change_time > dest_change_file:
return True
return False
 
def handle_file(handled_files, asm_file_name, subdir = "."):
global elements
# Canonicalize the file path and get it relative to cwd
cwd = os.path.abspath(os.path.dirname(sys.argv[0]))
asm_file_name = os.path.realpath(asm_file_name)
asm_file_name = asm_file_name[len(cwd) + 1:]
# If it's lang.inc - skip it
if asm_file_name == 'lang.inc':
return
# If the file was handled in this execution before - skip it
if asm_file_name in handled_files:
return
# Say that the file was handled in this execution
handled_files.append(asm_file_name)
# Check if the file should be parsed (if it was modified or wasn't parsed yet)
should_get_declarations = True
if not it_neds_to_be_parsed(asm_file_name):
print(f"Skipping {asm_file_name} (already newest)")
should_get_declarations = False
else:
print(f"Handling {asm_file_name}")
# Remove elements parsed from this file before if any
elements_to_remove = [x for x in elements if x.location.split(':')[0] == asm_file_name]
elements = [x for x in elements if x.location.split(':')[0] != asm_file_name]
# Forget types of identifiers of names of the removed elements
for element in elements_to_remove:
if type(element) == AsmStruct:
id_remove_kind(element.name, ID_KIND_STRUCT_NAME)
elif type(element) == AsmMacro:
id_remove_kind(element.name, ID_KIND_MACRO_NAME)
# Read the source
asm_file_contents = open(asm_file_name, "r", encoding="utf-8").read()
# Find includes, fix their paths and handle em recoursively
includes = re.findall(r'^include (["\'])(.*)\1', asm_file_contents, flags=re.MULTILINE)
for include in includes:
include = include[1].replace('\\', '/');
full_path = subdir + '/' + include;
# If the path isn't valid, maybe that's not relative path
if not os.path.isfile(full_path):
full_path = include
new_subdir = full_path.rsplit('/', 1)[0]
handle_file(handled_files, full_path, new_subdir)
# Only collect declarations from the file if it wasn't parsed before
if should_get_declarations and not clean_generated_stuff:
get_declarations(asm_file_contents, asm_file_name)
 
kernel_files = []
 
# Load remembered list of symbols
if os.path.isfile('asmxygen.elements.pickle'):
print('Reading existing dump of symbols')
(elements, id2kind) = pickle.load(open('asmxygen.elements.pickle', 'rb'))
 
handle_file(kernel_files, "./kernel.asm");
 
if dump_symbols:
stdout = sys.stdout
sys.stdout = open('asmxygen.dump.txt', 'w', encoding = 'utf-8')
for asm_element in elements:
asm_element.dump()
sys.stdout = stdout
 
if clean_generated_stuff:
kernel_files_set = set(kernel_files)
for file in kernel_files:
doxygen_file = f"{doxygen_src_path}/{file}"
if (os.path.isfile(doxygen_file)):
print(f"Removing {file}... ", end = '')
os.remove(doxygen_file)
print("Done.")
elif not noemit:
print(f"Writing doumented sources to {doxygen_src_path}")
 
i = 0
new_elements = [x for x in elements if x.new]
for element in new_elements:
print(f"[{i + 1}/{len(new_elements)}] Emitting {element.name} from {element.location}")
element.emit(doxygen_src_path)
i += 1
 
print(f"Writing dump of symbols to asmxygen.elements.pickle")
 
# Now when the new elements already was written, there's no new elements anymore
for element in elements:
element.new = False
pickle.dump((elements, id2kind), open('asmxygen.elements.pickle', 'wb'))
 
if print_stats:
var_count = 0
mac_count = 0
lab_count = 0
fun_count = 0
uni_count = 0
str_count = 0
for element in elements:
if type(element) == AsmVariable:
var_count += 1
elif type(element) == AsmMacro:
mac_count += 1
elif type(element) == AsmLabel:
lab_count += 1
elif type(element) == AsmFunction:
fun_count += 1
elif type(element) == AsmUnion:
uni_count += 1
elif type(element) == AsmStruct:
str_count += 1
print(f'Parsed variable count: {var_count}')
print(f'Parsed macro count: {mac_count}')
print(f'Parsed label count: {lab_count}')
print(f'Parsed function count: {fun_count}')
print(f'Parsed union type count: {uni_count}')
print(f'Parsed structure type count: {str_count}')
 
if enable_warnings:
open('asmxygen.txt', "w", encoding = "utf-8").write(warnings)
/kernel/branches/kolibrios-pe-clevermouse/unpacker.inc
0,0 → 1,534
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
; @brief Unpack LZMA-compressed data. C-style declaration of the function.
;
; ```void __stdcall unpack(void *packed_data, void *unpacked_data);```
;
; @param packed_data Data to unpack
; @param unpacked_data Buffer to hold unpacked data
; @returns Nothing
unpack:
pushad
mov esi, [esp+32+4]
mov edi, [esp+32+8]
mov eax, [esi+8]
and al, 0xC0
cmp al, 0xC0
jz .failed
mov eax, [esi+8]
push eax
add esi, 12
and al, not 0xC0
dec al
jz .lzma
.failed:
pop eax
popad
ret 8
.lzma:
call .lzma_unpack
.common:
pop eax
test al, 0x80
jnz .ctr1
test al, 0x40
jz .ok
lodsd
mov ecx, eax
jecxz .ok
mov dl, [esi]
mov esi, [esp+32+8]
.c1:
lodsb
sub al, 0E8h
cmp al, 1
ja .c1
cmp byte [esi], dl
jnz .c1
lodsd
; "bswap eax" is not supported on i386
shr ax, 8
ror eax, 16
xchg al, ah
sub eax, esi
add eax, [esp+32+8]
mov [esi-4], eax
loop .c1
.ok:
popad
ret 8
.ctr1:
lodsd
mov ecx, eax
jecxz .ok
mov dl, [esi]
mov esi, [esp+32+8]
.c2:
lodsb
@@:
cmp al, 0xF
jnz .f
lodsb
cmp al, 80h
jb @b
cmp al, 90h
jb @f
.f:
sub al, 0E8h
cmp al, 1
ja .c2
@@:
cmp byte [esi], dl
jnz .c2
lodsd
shr ax, 8
ror eax, 16
xchg al, ah
sub eax, esi
add eax, [esp+32+8]
mov [esi-4], eax
loop .c2
jmp .ok
 
.lzma_unpack:
 
.pb = 2 ; pos state bits
.lp = 0 ; literal pos state bits
.lc = 3 ; literal context bits
.posStateMask = ((1 shl .pb)-1)
.literalPosMask = ((1 shl .lp)-1)
 
.kNumPosBitsMax = 4
.kNumPosStatesMax = (1 shl .kNumPosBitsMax)
 
.kLenNumLowBits = 3
.kLenNumLowSymbols = (1 shl .kLenNumLowBits)
.kLenNumMidBits = 3
.kLenNumMidSymbols = (1 shl .kLenNumMidBits)
.kLenNumHighBits = 8
.kLenNumHighSymbols = (1 shl .kLenNumHighBits)
 
.LenChoice = 0
.LenChoice2 = 1
.LenLow = 2
.LenMid = (.LenLow + (.kNumPosStatesMax shl .kLenNumLowBits))
.LenHigh = (.LenMid + (.kNumPosStatesMax shl .kLenNumMidBits))
.kNumLenProbs = (.LenHigh + .kLenNumHighSymbols)
 
.kNumStates = 12
.kNumLitStates = 7
.kStartPosModelIndex = 4
.kEndPosModelIndex = 14
.kNumFullDistances = (1 shl (.kEndPosModelIndex/2))
.kNumPosSlotBits = 6
.kNumLenToPosStates = 4
.kNumAlignBits = 4
.kAlignTableSize = (1 shl .kNumAlignBits)
.kMatchMinLen = 2
 
.IsMatch = 0
.IsRep = (.IsMatch + (.kNumStates shl .kNumPosBitsMax))
.IsRepG0 = (.IsRep + .kNumStates)
.IsRepG1 = (.IsRepG0 + .kNumStates)
.IsRepG2 = (.IsRepG1 + .kNumStates)
.IsRep0Long = (.IsRepG2 + .kNumStates)
.PosSlot = (.IsRep0Long + (.kNumStates shl .kNumPosBitsMax))
.SpecPos = (.PosSlot + (.kNumLenToPosStates shl .kNumPosSlotBits))
.Align_ = (.SpecPos + .kNumFullDistances - .kEndPosModelIndex)
.Lencoder = (.Align_ + .kAlignTableSize)
.RepLencoder = (.Lencoder + .kNumLenProbs)
.Literal = (.RepLencoder + .kNumLenProbs)
 
.LZMA_BASE_SIZE = 1846 ; must be ==Literal
.LZMA_LIT_SIZE = 768
 
.kNumTopBits = 24
.kTopValue = (1 shl .kNumTopBits)
 
.kNumBitModelTotalBits = 11
.kBitModelTotal = (1 shl .kNumBitModelTotalBits)
.kNumMoveBits = 5
 
push edi
; int state=0;
xor ebx, ebx
mov [.previousByte], bl
; unsigned rep0=1,rep1=1,rep2=1,rep3=1;
mov eax, 1
mov edi, .rep0
stosd
stosd
stosd
stosd
; int len=0;
; result=0;
mov ecx, .Literal + (.LZMA_LIT_SIZE shl (.lc+.lp))
mov eax, .kBitModelTotal/2
mov edi, [.p]
rep stosd
; RangeDecoderInit
; rd->ExtraBytes = 0
; rd->Buffer = stream
; rd->BufferLim = stream+bufferSize
; rd->Range = 0xFFFFFFFF
pop edi
mov ebp, [esi-8] ; dest_length
add ebp, edi ; ebp = destination limit
lodsd
; rd->code_ = eax
mov [.code_], eax
or [.range], -1
.main_loop:
cmp edi, ebp
jae .main_loop_done
mov edx, edi
and edx, .posStateMask
mov eax, ebx
shl eax, .kNumPosBitsMax+2
lea eax, [.IsMatch*4 + eax + edx*4]
add eax, [.p]
call .RangeDecoderBitDecode
jc .1
movzx eax, [.previousByte]
if .literalPosMask
mov ah, dl
and ah, .literalPosMask
end if
shr eax, 8-.lc
imul eax, .LZMA_LIT_SIZE*4
add eax, .Literal*4
add eax, [.p]
cmp ebx, .kNumLitStates
jb .literal
xor edx, edx
sub edx, [.rep0]
mov dl, [edi + edx]
call .LzmaLiteralDecodeMatch
jmp @f
.literal:
call .LzmaLiteralDecode
@@:
mov [.previousByte], al
stosb
mov al, bl
cmp bl, 4
jb @f
mov al, 3
cmp bl, 10
jb @f
mov al, 6
@@:
sub bl, al
jmp .main_loop
.1:
lea eax, [.IsRep*4 + ebx*4]
add eax, [.p]
call .RangeDecoderBitDecode
jnc .10
lea eax, [.IsRepG0*4 + ebx*4]
add eax, [.p]
call .RangeDecoderBitDecode
jc .111
mov eax, ebx
shl eax, .kNumPosBitsMax+2
lea eax, [.IsRep0Long*4 + eax + edx*4]
add eax, [.p]
call .RangeDecoderBitDecode
jc .1101
cmp bl, 7
setae bl
lea ebx, [9 + ebx + ebx]
xor edx, edx
sub edx, [.rep0]
mov al, [edi + edx]
stosb
mov [.previousByte], al
jmp .main_loop
.111:
lea eax, [.IsRepG1*4 + ebx*4]
add eax, [.p]
call .RangeDecoderBitDecode
mov eax, [.rep1]
jnc .l3
.l1:
lea eax, [.IsRepG2*4 + ebx*4]
add eax, [.p]
call .RangeDecoderBitDecode
mov eax, [.rep2]
jnc .l2
xchg [.rep3], eax
.l2:
push [.rep1]
pop [.rep2]
.l3:
xchg eax, [.rep0]
mov [.rep1], eax
.1101:
mov eax, .RepLencoder*4
add eax, [.p]
call .LzmaLenDecode
cmp bl, 7
setc bl
adc bl, bl
xor bl, 3
add bl, 8
jmp .repmovsb
.10:
mov eax, [.rep0]
xchg eax, [.rep1]
xchg eax, [.rep2]
xchg eax, [.rep3]
cmp bl, 7
setc bl
adc bl, bl
xor bl, 3
add bl, 7
mov eax, .Lencoder*4
add eax, [.p]
call .LzmaLenDecode
mov eax, .kNumLenToPosStates-1
cmp eax, ecx
jb @f
mov eax, ecx
@@:
push ecx
mov ecx, .kNumPosSlotBits
shl eax, cl
shl eax, 2
add eax, .PosSlot*4
add eax, [.p]
call .RangeDecoderBitTreeDecode
mov [.rep0], ecx
cmp ecx, .kStartPosModelIndex
jb .l6
push ecx
mov eax, ecx
and eax, 1
shr ecx, 1
or eax, 2
dec ecx
shl eax, cl
mov [.rep0], eax
pop edx
cmp edx, .kEndPosModelIndex
jae .l5
sub eax, edx
shl eax, 2
add eax, (.SpecPos - 1)*4
add eax, [.p]
call .RangeDecoderReverseBitTreeDecode
add [.rep0], ecx
jmp .l6
.l5:
sub ecx, .kNumAlignBits
call .RangeDecoderDecodeDirectBits
mov ecx, .kNumAlignBits
shl eax, cl
add [.rep0], eax
mov eax, .Align_*4
add eax, [.p]
call .RangeDecoderReverseBitTreeDecode
add [.rep0], ecx
.l6:
pop ecx
inc [.rep0]
jz .main_loop_done
.repmovsb:
add ecx, .kMatchMinLen
push esi
mov esi, edi
sub esi, [.rep0]
rep movsb
pop esi
mov al, [edi-1]
mov [.previousByte], al
jmp .main_loop
.main_loop_done:
ret
 
.RangeDecoderBitDecode:
; in: eax->prob
; out: CF=bit; destroys eax
push edx
mov edx, [.range]
shr edx, .kNumBitModelTotalBits
imul edx, [eax]
cmp [.code_], edx
jae .ae
mov [.range], edx
mov edx, .kBitModelTotal
sub edx, [eax]
shr edx, .kNumMoveBits
add [eax], edx
clc
.n:
lahf
cmp [.range], .kTopValue
jae @f
shl [.range], 8
shl [.code_], 8
lodsb
mov byte [.code_], al
@@:
sahf
pop edx
ret
.ae:
sub [.range], edx
sub [.code_], edx
mov edx, [eax]
shr edx, .kNumMoveBits
sub [eax], edx
stc
jmp .n
 
.RangeDecoderDecodeDirectBits:
; in: ecx=numTotalBits
; out: eax=result; destroys edx
xor eax, eax
.l:
shr [.range], 1
shl eax, 1
mov edx, [.code_]
sub edx, [.range]
jb @f
mov [.code_], edx
or eax, 1
@@:
cmp [.range], .kTopValue
jae @f
shl [.range], 8
shl [.code_], 8
push eax
lodsb
mov byte [.code_], al
pop eax
@@:
loop .l
ret
 
.LzmaLiteralDecode:
; in: eax->probs
; out: al=byte; destroys edx
push ecx
mov ecx, 1
@@:
push eax
lea eax, [eax+ecx*4]
call .RangeDecoderBitDecode
pop eax
adc cl, cl
jnc @b
.LzmaLiteralDecode.ret:
mov al, cl
pop ecx
ret
.LzmaLiteralDecodeMatch:
; in: eax->probs, dl=matchByte
; out: al=byte; destroys edx
push ecx
mov ecx, 1
.LzmaLiteralDecodeMatch.1:
add dl, dl
setc ch
push eax
lea eax, [eax+ecx*4+0x100*4]
call .RangeDecoderBitDecode
pop eax
adc cl, cl
jc .LzmaLiteralDecode.ret
xor ch, cl
test ch, 1
mov ch, 0
jnz @b
jmp .LzmaLiteralDecodeMatch.1
 
.LzmaLenDecode:
; in: eax->prob, edx=posState
; out: ecx=len
push eax
add eax, .LenChoice*4
call .RangeDecoderBitDecode
pop eax
jnc .0
push eax
add eax, .LenChoice2*4
call .RangeDecoderBitDecode
pop eax
jc @f
mov ecx, .kLenNumMidBits
shl edx, cl
lea eax, [eax + .LenMid*4 + edx*4]
call .RangeDecoderBitTreeDecode
add ecx, .kLenNumLowSymbols
ret
@@:
add eax, .LenHigh*4
mov ecx, .kLenNumHighBits
call .RangeDecoderBitTreeDecode
add ecx, .kLenNumLowSymbols + .kLenNumMidSymbols
ret
.0:
mov ecx, .kLenNumLowBits
shl edx, cl
lea eax, [eax + .LenLow*4 + edx*4]
.RangeDecoderBitTreeDecode:
; in: eax->probs,ecx=numLevels
; out: ecx=length; destroys edx
push ebx
mov edx, 1
mov ebx, edx
@@:
push eax
lea eax, [eax+edx*4]
call .RangeDecoderBitDecode
pop eax
adc dl, dl
add bl, bl
loop @b
sub dl, bl
pop ebx
mov ecx, edx
ret
.RangeDecoderReverseBitTreeDecode:
; in: eax->probs,ecx=numLevels
; out: ecx=length; destroys edx
push ebx ecx
mov edx, 1
xor ebx, ebx
@@:
push eax
lea eax, [eax+edx*4]
call .RangeDecoderBitDecode
lahf
adc edx, edx
sahf
rcr ebx, 1
pop eax
loop @b
pop ecx
rol ebx, cl
mov ecx, ebx
pop ebx
ret
 
uglobal
align 4
;unpack.p rd unpack.LZMA_BASE_SIZE + (unpack.LZMA_LIT_SIZE shl (unpack.lc+unpack.lp))
unpack.p dd ?
unpack.code_ dd ?
unpack.range dd ?
unpack.rep0 dd ?
unpack.rep1 dd ?
unpack.rep2 dd ?
unpack.rep3 dd ?
unpack.previousByte db ?
endg
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/struct.inc
0,0 → 1,246
 
; Macroinstructions for defining data structures
 
macro struct name
{ virtual at 0
fields@struct equ name
match child parent, name \{ fields@struct equ child,fields@\#parent \}
sub@struct equ
struc db [val] \{ \common define field@struct .,db,<val>
fields@struct equ fields@struct,field@struct \}
struc dw [val] \{ \common define field@struct .,dw,<val>
fields@struct equ fields@struct,field@struct \}
struc du [val] \{ \common define field@struct .,du,<val>
fields@struct equ fields@struct,field@struct \}
struc dd [val] \{ \common define field@struct .,dd,<val>
fields@struct equ fields@struct,field@struct \}
struc dp [val] \{ \common define field@struct .,dp,<val>
fields@struct equ fields@struct,field@struct \}
struc dq [val] \{ \common define field@struct .,dq,<val>
fields@struct equ fields@struct,field@struct \}
struc dt [val] \{ \common define field@struct .,dt,<val>
fields@struct equ fields@struct,field@struct \}
struc rb count \{ define field@struct .,db,count dup (?)
fields@struct equ fields@struct,field@struct \}
struc rw count \{ define field@struct .,dw,count dup (?)
fields@struct equ fields@struct,field@struct \}
struc rd count \{ define field@struct .,dd,count dup (?)
fields@struct equ fields@struct,field@struct \}
struc rp count \{ define field@struct .,dp,count dup (?)
fields@struct equ fields@struct,field@struct \}
struc rq count \{ define field@struct .,dq,count dup (?)
fields@struct equ fields@struct,field@struct \}
struc rt count \{ define field@struct .,dt,count dup (?)
fields@struct equ fields@struct,field@struct \}
macro db [val] \{ \common \local anonymous
define field@struct anonymous,db,<val>
fields@struct equ fields@struct,field@struct \}
macro dw [val] \{ \common \local anonymous
define field@struct anonymous,dw,<val>
fields@struct equ fields@struct,field@struct \}
macro du [val] \{ \common \local anonymous
define field@struct anonymous,du,<val>
fields@struct equ fields@struct,field@struct \}
macro dd [val] \{ \common \local anonymous
define field@struct anonymous,dd,<val>
fields@struct equ fields@struct,field@struct \}
macro dp [val] \{ \common \local anonymous
define field@struct anonymous,dp,<val>
fields@struct equ fields@struct,field@struct \}
macro dq [val] \{ \common \local anonymous
define field@struct anonymous,dq,<val>
fields@struct equ fields@struct,field@struct \}
macro dt [val] \{ \common \local anonymous
define field@struct anonymous,dt,<val>
fields@struct equ fields@struct,field@struct \}
macro rb count \{ \local anonymous
define field@struct anonymous,db,count dup (?)
fields@struct equ fields@struct,field@struct \}
macro rw count \{ \local anonymous
define field@struct anonymous,dw,count dup (?)
fields@struct equ fields@struct,field@struct \}
macro rd count \{ \local anonymous
define field@struct anonymous,dd,count dup (?)
fields@struct equ fields@struct,field@struct \}
macro rp count \{ \local anonymous
define field@struct anonymous,dp,count dup (?)
fields@struct equ fields@struct,field@struct \}
macro rq count \{ \local anonymous
define field@struct anonymous,dq,count dup (?)
fields@struct equ fields@struct,field@struct \}
macro rt count \{ \local anonymous
define field@struct anonymous,dt,count dup (?)
fields@struct equ fields@struct,field@struct \}
macro union \{ fields@struct equ fields@struct,,union,<
sub@struct equ union \}
macro struct \{ fields@struct equ fields@struct,,substruct,<
sub@struct equ substruct \} }
 
macro ends
{ match , sub@struct \{ restruc db,dw,du,dd,dp,dq,dt
restruc rb,rw,rd,rp,rq,rt
purge db,dw,du,dd,dp,dq,dt
purge rb,rw,rd,rp,rq,rt
purge union,struct
match name tail,fields@struct, \\{ if $
display 'Error: definition of ',\\`name,' contains illegal instructions.',0Dh,0Ah
err
end if \\}
match name=,fields,fields@struct \\{ fields@struct equ
make@struct name,fields
define fields@\\#name fields \\}
end virtual \}
match any, sub@struct \{ fields@struct equ fields@struct> \}
restore sub@struct }
 
; @dont_give_a_doxygen
macro make@struct name,[field,type,def]
{ common
local define
define equ name
forward
local sub
match , field \{ make@substruct type,name,sub def
define equ define,.,sub, \}
match any, field \{ define equ define,.#field,type,<def> \}
common
match fields, define \{ define@struct fields \} }
 
; @dont_give_a_doxygen
macro define@struct name,[field,type,def]
{ common
virtual
db `name
load initial@struct byte from 0
if initial@struct = '.'
display 'Error: name of structure should not begin with a dot.',0Dh,0Ah
err
end if
end virtual
local list
list equ
forward
if ~ field eq .
name#field type def
sizeof.#name#field = $ - name#field
else
label name#.#type
rb sizeof.#type
end if
local value
match any, list \{ list equ list, \}
list equ list <value>
common
sizeof.#name = $
restruc name
match values, list \{
struc name value \\{ \\local \\..base
match any, fields@struct \\\{ fields@struct equ fields@struct,.,name,<values> \\\}
match , fields@struct \\\{ label \\..base
forward
match , value \\\\{ field type def \\\\}
match any, value \\\\{ field type value
if ~ field eq .
rb sizeof.#name#field - ($-field)
end if \\\\}
common label . at \\..base \\\}
\\}
macro name value \\{
match any, fields@struct \\\{ \\\local anonymous
fields@struct equ fields@struct,anonymous,name,<values> \\\}
match , fields@struct \\\{
forward
match , value \\\\{ type def \\\\}
match any, value \\\\{ \\\\local ..field
..field = $
type value
if ~ field eq .
rb sizeof.#name#field - ($-..field)
end if \\\\}
common \\\} \\} \} }
 
; @dont_give_a_doxygen
macro enable@substruct
{ macro make@substruct substruct,parent,name,[field,type,def]
\{ \common
\local define
define equ parent,name
\forward
\local sub
match , field \\{ match any, type \\\{ enable@substruct
make@substruct type,parent,sub def
purge make@substruct
define equ define,.,sub, \\\} \\}
match any, field \\{ define equ define,.\#field,type,<def> \\}
\common
match fields, define \\{ define@\#substruct fields \\} \} }
 
; @dont_give_a_doxygen
enable@substruct
 
; @dont_give_a_doxygen
macro define@union parent,name,[field,type,def]
{ common
virtual at parent#.#name
forward
if ~ field eq .
virtual at parent#.#name
parent#field type def
sizeof.#parent#field = $ - parent#field
end virtual
if sizeof.#parent#field > $ - parent#.#name
rb sizeof.#parent#field - ($ - parent#.#name)
end if
else
virtual at parent#.#name
label parent#.#type
type def
end virtual
label name#.#type at parent#.#name
if sizeof.#type > $ - parent#.#name
rb sizeof.#type - ($ - parent#.#name)
end if
end if
common
sizeof.#name = $ - parent#.#name
end virtual
struc name [value] \{ \common
label .\#name
last@union equ
forward
match any, last@union \\{ virtual at .\#name
field type def
end virtual \\}
match , last@union \\{ match , value \\\{ field type def \\\}
match any, value \\\{ field type value \\\} \\}
last@union equ field
common rb sizeof.#name - ($ - .\#name) \}
macro name [value] \{ \common \local ..anonymous
..anonymous name value \} }
 
; @dont_give_a_doxygen
macro define@substruct parent,name,[field,type,def]
{ common
virtual at parent#.#name
forward
if ~ field eq .
parent#field type def
sizeof.#parent#field = $ - parent#field
else
label parent#.#type
rb sizeof.#type
end if
common
sizeof.#name = $ - parent#.#name
end virtual
struc name value \{
label .\#name
forward
match , value \\{ field type def \\}
match any, value \\{ field type value
if ~ field eq .
rb sizeof.#parent#field - ($-field)
end if \\}
common \}
macro name value \{ \local ..anonymous
..anonymous name \} }
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/docs/sysfuncr.txt
0,0 → 1,5081
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
СИСТЕМНЫЕ ФУНКЦИИ ОПЕРАЦИОННОЙ СИСТЕМЫ Kolibri 0.7.7.0
 
Номер функции помещается в регистр eax.
Вызов системной функции осуществляется командой "int 0x40".
Все регистры, кроме явно указанных в возвращаемом значении,
включая регистр флагов eflags, сохраняются.
 
 
======================================================================
============== Функция 0 - определить и нарисовать окно. =============
======================================================================
Определяет окно приложения. Рисует рамку окна, заголовок и рабочую
область. Для окон со скином определяет стандартные кнопки закрытия и
минимизации.
Параметры:
* eax = 0 - номер функции
* ebx = [координата по оси x]*65536 + [размер по оси x]
* ecx = [координата по оси y]*65536 + [размер по оси y]
* edx = 0xXYRRGGBB, где:
* Y = стиль окна:
* Y=1 - только определить область окна, ничего не рисовать
* Y=3 - окно со скином
* Y=4 - окно со скином фиксированных размеров
* Y=0,2 эти стили не должны более использоваться и оставлены
только для совместимости со старыми приложениями
* остальные возможные значения (от 5 до 15) зарезервированы,
вызов функции с такими Y игнорируется
* RR, GG, BB = соответственно красная, зеленая, синяя
составляющие цвета рабочей области окна
(игнорируется для стиля Y=1)
* X = DCBA (биты)
* A = 1 - у окна есть заголовок
* B = 1 - координаты всех графических примитивов задаются
относительно клиентской области окна
* C = 1 - не закрашивать рабочую область при отрисовке окна
* D = 0 - нормальная заливка рабочей области, 1 - градиентная
Следующие параметры предназначены для окон типа I и II и
игнорируются для стилей Y=1,3:
* esi = 0xXYRRGGBB - цвет заголовка
* RR, GG, BB определяют сам цвет
* Y = 0 - обычное окно
Y = 1 - неперемещаемое окно (работает для всех стилей окон)
* X определяет градиент заголовка:
X = 0 - нет градиента,
X = 8 - обычный градиент,
для окон типа II X=4 - негативный градиент
* прочие значения X и Y зарезервированы
* edi = адрес строки заголовка для стилей Y=3,4 (см. функцию 71.1)
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Положение и размеры окна устанавливаются при первом вызове
этой функции и игнорируются при последующих; для изменения
положения и/или размеров уже созданного окна используйте
67-ю функцию.
* Для окон стилей Y=3,4 с заголовком (A=1) строка заголовка
устанавливается при первом вызове этой функции и игнорируется при
последующих (точнее говоря, игнорируется после вызова
подфункции 2 функции 12 - конца перерисовки);
для изменения строки заголовка уже созданного окна используйте
подфункцию 1 функции 71.
* Если использовать окна соответствующих стилей, то положение
и/или размеры окна могут меняться пользователем.
Текущие положение и размеры могут быть получены вызовом функции 9.
* Окно должно умещаться на экране. Если переданные координаты
и размеры не удовлетворяют этому условию, то соответствующая
координата (или, возможно, обе) считается нулем, а если и это
не помогает, то соответствующий размер (или, возможно, оба)
устанавливается в размер экрана.
 
Далее обозначим xpos,ypos,xsize,ysize - значения, передаваемые
в ebx,ecx. Координаты приводятся относительно левого верхнего
угла окна, который, таким образом, задается как (0,0), координаты
правого нижнего угла суть (xsize,ysize).
* Размеры окна понимаются в смысле координат правого нижнего угла.
Это же относится и ко всем остальным функциям.
Это означает, что реальные размеры на 1 пиксель больше.
* Вид окна стиля Y=1:
* полностью определяется приложением
* Вид окна со скином Y=3,4:
* рисуется внешняя рамка шириной 1 пиксель
цвета 'outer' из скина
* рисуется промежуточная рамка шириной 3 пикселя
цвета 'frame' из скина
* рисуется внутренняя рамка шириной 1 пиксель
цвета 'inner' из скина
* рисуется заголовок (по картинкам из скина) в прямоугольнике
(0,0) - (xsize,_skinh-1)
* если ysize>=26, то закрашивается рабочая область окна -
прямоугольник с левым верхним углом (5,_skinh) и правым нижним
(xsize-5,ysize-5) - цветом, указанным в edx (с учетом градиента)
* определяются две стандартные кнопки: закрытия и минимизации
(смотри функцию 8)
* если A=1 и в edi (ненулевой) указатель на строку заголовка,
то она выводится в заголовке в месте, определяемом скином
* Значение переменной _skinh доступно как результат вызова
подфункции 4 функции 48
 
---------------------- Константы для регистров: ----------------------
eax - SF_CREATE_WINDOW (0)
======================================================================
================= Функция 1 - поставить точку в окне. ================
======================================================================
Параметры:
* eax = 1 - номер функции
* ebx = x-координата (относительно окна)
* ecx = y-координата (относительно окна)
* edx = 0x00RRGGBB - цвет точки
edx = 0x01xxxxxx - инвертировать цвет точки
(младшие 24 бита игнорируются)
Возвращаемое значение:
* функция не возвращает значения
 
---------------------- Константы для регистров: ----------------------
eax - SF_PUT_PIXEL (1)
======================================================================
============== Функция 2 - получить код нажатой клавиши. =============
======================================================================
Забирает код нажатой клавиши из буфера.
Параметры:
* eax = 2 - номер функции
Возвращаемое значение:
* если буфер пуст, возвращается eax=1
* если буфер непуст, то возвращается al=0, ah=код нажатой клавиши,
биты 16-23 содержат сканкод нажатой клавиши в режиме ASCII,
в режиме сканкодов биты обнулены.
биты 23-31 обнулены
* если есть "горячая клавиша", то возвращается
al=2, ah=сканкод нажатой клавиши (0 для управляющих клавиш),
старшее слово регистра eax содержит состояние управляющих клавиш
в момент нажатия горячей клавиши
Замечания:
* Существует общесистемный буфер нажатых клавиш размером 120 байт,
организованный как очередь.
* Существует ещё один общесистемный буфер на 120 "горячих клавиш".
* При вызове этой функции приложением с неактивным окном
считается, что буфер нажатых клавиш пуст.
* По умолчанию эта функция возвращает ASCII-коды; переключиться на
режим сканкодов (и назад) можно с использованием функции 66.
Однако, горячие клавиши всегда возвращаются как сканкоды.
* Узнать, какие комбинации клавиш соответствуют каким кодам, можно,
запустив приложения keyascii и scancode.
* Сканкоды возвращаются непосредственно клавиатурой и фиксированы;
ASCII-коды получаются с использованием таблиц преобразования,
которые можно установить подфункцией 2 функции 21 и прочитать
подфункцией 2 функции 26.
* Как следствие, ASCII-коды учитывают текущую раскладку клавиатуры
(rus/en) в отличие от сканкодов.
* Поступает информация только о тех горячих клавишах, которые были
определены этим потоком подфункцией 4 функции 66.
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_KEY (2)
======================================================================
================ Функция 3 - получить системное время. ===============
======================================================================
Параметры:
* eax = 3 - номер функции
Возвращаемое значение:
* eax = 0x00SSMMHH, где HH:MM:SS = часы:минуты:секунды
* каждый элемент возвращается как BCD-число, например,
для времени 23:59:59 результат будет 0x00595923
Замечания:
* Смотри также подфункцию 9 функции 26 - получение времени
с момента запуска системы; она во многих случаях удобнее,
поскольку возвращает просто DWORD-значение счетчика времени.
* Системное время можно установить функцией 22.
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_SYS_TIME (3)
======================================================================
================ Функция 4 - нарисовать строку текста. ===============
======================================================================
Параметры:
* eax = 4 - номер функции
* ebx = X*65536+Y, координаты в окне или буфере
* ecx = 0xXXRRGGBB, где
* RR, GG, BB задают цвет текста
* XX=ABFFCSSS (биты):
* A=1 - рисуемая строка заканчивается нулём
* B=1 - закрашивать фон (цвет = edi)
* FF задает шрифт и кодировку:
0 = 6x9 cp866
1 = 8x16 cp866
2 = 8x16 UTF-16LE
3 = 8x16 UTF-8
* C=0 - рисовать в окно,
С=1 - рисовать в буфер (edi)
* SSS = (множитель размера)-1, то-есть 0 = x1, 7 = x8
* edx = указатель на начало строки
* esi = для A=0 длина строки, для A=1 игнорируется
* edi = если B=1 - цвет для закраски фона,
если C=1 - указатель на буфер
 
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Нельзя одновременно использовать B=1 и C=1,
поскольку в обоих случаях используется регистр edi.
* Если SSS=0, шрифт может сглаживаться,
в зависимости от системной настройки.
* Структура буфера:
Xsize dd
Ysize dd
picture rb Xsize*Ysize*4 ; 32 бита
 
---------------------- Константы для регистров: ----------------------
eax - SF_DRAW_TEXT (4)
======================================================================
========================= Функция 5 - пауза. =========================
======================================================================
Задерживает выполнение программы на заданное время.
Параметры:
* eax = 5 - номер функции
* ebx = время в сотых долях секунды
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Передача ebx=0 не передает управление следующему процессу и
вообще не производит никаких действий. Если действительно
требуется передать управление следующему процессу
(закончить текущий квант времени), используйте подфункцию 1
функции 68.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SLEEP (5)
======================================================================
=============== Функция 7 - вывести изображение в окно. ==============
======================================================================
Параметры:
* eax = 7 - номер функции
* ebx = указатель на изображение в формате BBGGRRBBGGRR...
* ecx = [размер по оси x]*65536 + [размер по оси y]
* edx = [координата по оси x]*65536 + [координата по оси y]
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Координаты изображения - это координаты верхнего левого угла
изображения относительно окна.
* Размер изображения в байтах есть 3*xsize*ysize.
 
---------------------- Константы для регистров: ----------------------
eax - SF_PUT_IMAGE (7)
======================================================================
=============== Функция 8 - определить/удалить кнопку. ===============
======================================================================
Параметры для определения кнопки:
* eax = 8 - номер функции
* ebx = [координата по оси x]*65536 + [размер по оси x]
* ecx = [координата по оси y]*65536 + [размер по оси y]
* edx = 0xXYnnnnnn, где:
* nnnnnn = идентификатор кнопки
* старший (31-й) бит edx сброшен
* если 30-й бит edx установлен - не прорисовывать кнопку
* если 29-й бит edx установлен - не рисовать рамку
при нажатии на кнопку
* esi = 0x00RRGGBB - цвет кнопки
Параметры для удаления кнопки:
* eax = 8 - номер функции
* edx = 0x80nnnnnn, где nnnnnn - идентификатор кнопки
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Размеры кнопки должны быть больше 0 и меньше 0x8000.
* Для окон со скином при определении окна (вызове 0-й функции)
создаются две стандартные кнопки - закрытия окна
с идентификатором 1 и минимизации окна с идентификатором 0xffff.
* Создание двух кнопок с одинаковыми идентификаторами
вполне допустимо.
* Кнопка с идентификатором 0xffff при нажатии интерпретируется
системой как кнопка минимизации, система обрабатывает такое
нажатие самостоятельно, не обращаясь к приложению.
В остальном это обычная кнопка.
* Общее количество кнопок для всех приложений ограничено
числом 4095.
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEFINE_BUTTON (8)
======================================================================
============= Функция 9 - информация о потоке выполнения. ============
======================================================================
Параметры:
* eax = 9 - номер функции
* ebx = указатель на буфер размера 1 Кб
* ecx = номер слота потока
ecx = -1 - получить информацию о текущем потоке
Возвращаемое значение:
* eax = максимальный номер слота потока
но, если указатель в ebx недопустимый, например,
регион [ebx, ebx + 0x4C) пересекается с памятью ядра,
то тогда функция возвращает -1
* буфер, на который указывает ebx, содержит следующую информацию:
* +0: dword: использование процессора (сколько тактов в секунду
уходит на исполнение именно этого потока)
* +4: word: позиция окна потока в оконном стэке
* +6: word: (не имеет отношения к запрошенному потоку)
номер слота потока, окно которого находится в оконном стэке
в позиции ecx
* +8: word: зарезервировано
* +10 = +0xA: 11 байт: имя процесса
(имя запущенного файла - исполняемый файл без расширения)
* +21 = +0x15: byte: зарезервировано, этот байт не изменяется
* +22 = +0x16: dword: адрес процесса в памяти
* +26 = +0x1A: dword: размер используемой памяти - 1
* +30 = +0x1E: dword: идентификатор (PID/TID)
* +34 = +0x22: dword: координата окна потока по оси x
* +38 = +0x26: dword: координата окна потока по оси y
* +42 = +0x2A: dword: размер окна потока по оси x
* +46 = +0x2E: dword: размер окна потока по оси y
* +50 = +0x32: word: состояние слота потока:
* 0 = поток выполняется
* 1 = поток приостановлен
* 2 = поток приостановлен в момент ожидания события
* 3 = поток завершается в результате вызова функции -1 или
насильственно как следствие вызова подфункции 2 функции 18
или завершения работы системы
* 4 = поток завершается в результате исключения
* 5 = поток ожидает события
* 9 = запрошенный слот свободен, вся остальная информация о
слоте не имеет смысла
* +52 = +0x34: word: зарезервировано, это слово не изменяется
* +54 = +0x36: dword: координата начала клиентской области
по оси x
* +58 = +0x3A: dword: координата начала клиентской области
по оси y
* +62 = +0x3E: dword: ширина клиентской области
* +66 = +0x42: dword: высота клиентской области
* +70 = +0x46: byte: состояние окна - битовое поле
* бит 0 (маска 1): окно максимизировано
* бит 1 (маска 2): окно минимизировано в панель задач
* бит 2 (маска 4): окно свёрнуто в заголовок
* +71 = +0x47: dword: маска событий
* +75 = +0x4B: byte: режим ввода с клавиатуры(ASCII = 0; SCAN = 1)
Замечания:
* Слоты нумеруются с 1.
* Возвращаемое значение не есть общее число потоков, поскольку
бывают свободные слоты.
* При создании процесса автоматически создается поток выполнения.
* Функция выдает информацию о потоке. Каждый процесс имеет
хотя бы один поток. Один процесс может создать несколько потоков,
в этом случае каждый поток получает свой слот, причем поля
+10, +22, +26 в этих слотах совпадают.
Для приложений не существует общего способа определить,
принадлежат ли два потока одному процессу.
* Активное окно - окно, находящееся на вершине оконного стэка,
оно получает сообщения о вводе с клавиатуры. Для него позиция в
оконном стэке совпадает с возвращаемым значением.
* Слот 1 соответствует специальному потоку операционной системы,
для которого:
* окно находится внизу оконного стэка, поля +4 и +6 содержат
значение 1
* имя процесса - "OS/IDLE" (дополненное пробелами)
* адрес процесса в памяти равен 0, размер используемой памяти
16 Mb (0x1000000)
* PID=1
* координаты и размеры окна, равно как и клиентской области,
условно полагаются равными 0
* состояние слота - всегда 0 (выполняется)
* время выполнения складывается из времени, уходящего на
собственно работу, и времени простоя в ожидании прерывания
(которое можно получить вызовом подфункции 4 функции 18).
* Начиная со слота 2, размещаются обычные приложения.
* Обычные приложения размещаются в памяти по адресу 0
(константа ядра std_application_base_address).
Наложения не происходит, поскольку у каждого процесса своя
таблица страниц.
* При создании потока ему назначаются слот в системной таблице и
идентификатор (Process/Thread IDentifier = PID/TID), которые для
заданного потока не изменяются со временем.
После завершения потока его слот может быть заново использован
для другого потока. Идентификатор потока не может быть назначен
другому потоку даже после завершения первого.
Назначаемые новым потокам идентификаторы монотонно растут.
* Если поток еще не определил свое окно вызовом функции 0, то
положение и размеры этого окна полагаются нулями.
* Координаты клиентской области окна берутся относительно окна.
* В данный момент используется только часть буфера размером
76 = 0x4C байта. Тем не менее рекомендуется использовать буфер
размером 1 Кб для будущей совместимости, в будущем могут быть
добавлены некоторые поля.
 
---------------------- Константы для регистров: ----------------------
eax - SF_THREAD_INFO (9)
======================================================================
==================== Функция 10 - ожидать события. ===================
======================================================================
Если очередь сообщений пуста, то ждет появления сообщения в очереди.
В таком состоянии поток не получает процессорного времени.
Затем считывает сообщение из очереди.
 
Параметры:
* eax = 10 - номер функции
Возвращаемое значение:
* eax = событие (смотри список событий)
Замечания:
* Учитываются только те события, которые входят в маску,
устанавливаемую функцией 40. По умолчанию это события
перерисовки, нажатия на клавиши и на кнопки.
* Для проверки, есть ли сообщение в очереди, используйте функцию 11.
Чтобы ждать не более определенного времени, используйте
функцию 23.
 
---------------------- Константы для регистров: ----------------------
eax - SF_WAIT_EVENT (10)
======================================================================
======= Функция 11 - проверить, есть ли событие, без ожидания. =======
======================================================================
Если в очереди сообщений есть какое-то событие, то считывает и
возвращает его. Если очередь пуста, возвращает нуль.
Параметры:
* eax = 11 - номер функции
Возвращаемое значение:
* eax = 0 - очередь сообщений пуста
* иначе eax = событие (смотри список событий)
Замечания:
* Учитываются только те события, которые входят в маску,
устанавливаемую функцией 40. По умолчанию это события
перерисовки, нажатия на клавиши и на кнопки.
* Для ожидания появления события в очереди, используйте функцию 10.
Чтобы ждать не более определенного времени, используйте
функцию 23.
 
---------------------- Константы для регистров: ----------------------
eax - SF_CHECK_EVENT (11)
======================================================================
=========== Функция 12 - начать/закончить перерисовку окна. ==========
======================================================================
 
-------------- Подфункция 1 - начать перерисовку окна. ---------------
Параметры:
* eax = 12 - номер функции
* ebx = 1 - номер подфункции
Возвращаемое значение:
* функция не возвращает значения
 
------------- Подфункция 2 - закончить перерисовку окна. -------------
Параметры:
* eax = 12 - номер функции
* ebx = 2 - номер подфункции
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Функция начала перерисовки удаляет все определённые
функцией 8 кнопки, их следует определить повторно.
 
---------------------- Константы для регистров: ----------------------
eax - SF_REDRAW (12)
ebx - SSF_BEGIN_DRAW (1), SSF_END_DRAW (2)
======================================================================
============ Функция 13 - нарисовать прямоугольник в окне. ===========
======================================================================
Параметры:
* eax = 13 - номер функции
* ebx = [координата по оси x]*65536 + [размер по оси x]
* ecx = [координата по оси y]*65536 + [размер по оси y]
* edx = цвет 0xRRGGBB или 0x80RRGGBB для градиентной заливки
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Под координатами понимаются координаты левого верхнего угла
прямоугольника относительно окна.
 
---------------------- Константы для регистров: ----------------------
eax - SF_DRAW_RECT (13)
======================================================================
================ Функция 14 - получить размеры экрана. ===============
======================================================================
Параметры:
* eax = 14 - номер функции
Возвращаемое значение:
* eax = [xsize]*65536 + [ysize], где
* xsize = x-координата правого нижнего угла экрана =
размер по горизонтали - 1
* ysize = y-координата правого нижнего угла экрана =
размер по вертикали - 1
Замечания:
* Смотри также подфункцию 5 функции 48 - получить размеры рабочей
области экрана.
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_SCREEN_SIZE (14)
======================================================================
= Функция 15, подфункция 1 - установить размер фонового изображения. =
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 1 - номер подфункции
* ecx = ширина изображения
* edx = высота изображения
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Вызов функции обязателен перед вызовом подфункций 2 и 5.
* Для обновления экрана (после завершения серии команд, работающих с
фоном) вызывайте подфункцию 3 перерисовки фона.
* Есть парная функция получения размеров фонового изображения -
подфункция 1 функции 39.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_SIZE_BG (1)
======================================================================
= Функция 15, подфункция 2 - поставить точку на фоновом изображении. =
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 2 - номер подфункции
* ecx = смещение
* edx = цвет точки 0xRRGGBB
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Смещение для точки с координатами (x,y) вычисляется как
(x+y*xsize)*3.
* Если указанное смещение превышает установленный подфункцией 1
размер, вызов игнорируется.
* Для обновления экрана (после завершения серии команд, работающих с
фоном) вызывайте подфункцию 3 перерисовки фона.
* Есть парная функция получения точки с фонового изображения -
подфункция 2 функции 39.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_PIXEL_BG (2)
======================================================================
============ Функция 15, подфункция 3 - перерисовать фон. ============
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 3 - номер подфункции
Возвращаемое значение:
* функция не возвращает значения
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_REDRAW_BG (3)
======================================================================
===== Функция 15, подфункция 4 - установить режим отрисовки фона. ====
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 4 - номер подфункции
* ecx = режим отрисовки:
* 1 = замостить
* 2 = растянуть
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Для обновления экрана (после завершения серии команд, работающих с
фоном) вызывайте подфункцию 3 перерисовки фона.
* Есть парная команда получения режима отрисовки фона -
подфункция 4 функции 39.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_MODE_BG (4)
======================================================================
===== Функция 15, подфункция 5 - поместить блок пикселей на фон. =====
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 5 - номер подфункции
* ecx = указатель на данные в формате BBGGRRBBGGRR...
* edx = смещение в данных фонового изображения
* esi = размер данных в байтах = 3 * число пикселей
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Проверки корректности смещения и размера не производится.
* Цвет каждого пикселя хранится как 3-байтная величина BBGGRR.
* Пиксели фонового изображения записываются последовательно
слева направо, сверху вниз.
* Смещение пикселя с координатами (x,y) есть (x+y*xsize)*3.
* Для обновления экрана (после завершения серии команд, работающих с
фоном) вызывайте подфункцию 3 перерисовки фона.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_IMAGE_BG (5)
======================================================================
====================== Функция 15, подфункция 6 ======================
==== Спроецировать данные фона на адресное пространство процесса. ====
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 6 - номер подфункции
Возвращаемое значение:
* eax = указатель на данные фона, 0 при ошибке
Замечания:
* Спроецированные данные доступны на чтение и запись.
* Размер данных фона равен 3*xsize*ysize. Изменение размеров фона
блокируется на время работы с спроецированными данными.
* Цвет каждого пикселя хранится как 3-байтовая величина BBGGRR.
* Пиксели фонового изображения записываются последовательно
слева направо, сверху вниз.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_MAP_BG (6)
======================================================================
====================== Функция 15, подфункция 7 ======================
=== Закрыть проекцию данных фона на адресное пространство процесса. ==
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 7 - номер подфункции
* ecx = указатель на данные фона
Возвращаемое значение:
* eax = 1 при успехе, 0 при ошибке
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_UNMAP_BG (7)
======================================================================
====================== Функция 15, подфункция 8 ======================
=========== Получить координаты последней отрисовки фона. ============
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 8 - номер подфункции
Возвращаемое значение:
* eax = [left]*65536 + [right]
* ebx = [top]*65536 + [bottom]
Замечания:
* (left,top) - координаты левого верхнего угла,
(right,bottom) - координаты правого нижнего.
* Для получения более достоверных сведений, необходимо вызвать
функцию сразу после получения события:
5 = завершилась перерисовка фона рабочего стола
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_LAST_DRAW (8)
======================================================================
====================== Функция 15, подфункция 9 ======================
=============== Перерисовать прямоугольную часть фона. ===============
======================================================================
Параметры:
* eax = 15 - номер функции
* ebx = 9 - номер подфункции
* ecx = [left]*65536 + [right]
* edx = [top]*65536 + [bottom]
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* (left,top) - координаты левого верхнего угла,
(right,bottom) - координаты правого нижнего.
* Если параметры установлены некорректно - фон не перерисовывается.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_REDRAW_RECT (9)
======================================================================
============= Функция 16 - сохранить рамдиск на дискету. =============
======================================================================
Параметры:
* eax = 16 - номер функции
* ebx = 1 или ebx = 2 - на какую дискету сохранять
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - ошибка
 
---------------------- Константы для регистров: ----------------------
eax - SF_RD_TO_FLOPPY (16)
======================================================================
============== Функция 17 - получить код нажатой кнопки. =============
======================================================================
Забирает код нажатой кнопки из буфера.
Параметры:
* eax = 17 - номер функции
Возвращаемое значение:
* если буфер пуст, возвращается eax=1
* если буфер непуст:
* старшие 24 бита eax содержат идентификатор кнопки
(в частности, в ah оказывается младший байт идентификатора;
если все кнопки имеют идентификатор, меньший 256,
то для различения достаточно ah)
* al = 0 - кнопка была нажата левой кнопкой мыши
* al = бит, соответствующий нажавшей кнопке мыши, если не левой
Замечания:
* "Буфер" хранит только одну кнопку, при нажатии новой кнопки
информация о старой теряется.
* При вызове этой функции приложением с неактивным окном
возвращается ответ "буфер пуст".
* Возвращаемое значение al соответствует состоянию кнопок мыши
в формате подфункции 2 функции 37 в момент начала нажатия
на кнопку, за исключением младшего бита (соответствующего левой
кнопке мыши), который сбрасывается.
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_BUTTON (17)
======================================================================
= Функция 18, подфункция 1 - сделать самым нижним окно потока. =======
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 1 - номер подфункции
* ecx = номер слота потока
Возвращаемое значение:
* функция не возвращает значения
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_UNFOCUS_WINDOW (1)
======================================================================
==== Функция 18, подфункция 2 - завершить процесс/поток по слоту. ====
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 2 - номер подфункции
* ecx = номер слота процесса/потока
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Нельзя завершить поток операционной системы OS/IDLE (номер слота
1), можно завершить любой обычный поток/процесс.
* Смотри также подфункцию 18 - завершение
процесса/потока с заданным идентификатором.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_TERMINATE_THREAD (2)
======================================================================
= Функция 18, подфункция 3 - сделать активным окно заданного потока. =
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 3 - номер подфункции
* ecx = номер слота потока
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* При указании корректного, но несуществующего слота активизируется
какое-то окно.
* Узнать, какое окно является активным, можно вызовом подфункции 7.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_FOCUS_WINDOW (3)
======================================================================
Функция 18, подфункция 4 - получить счётчик пустых тактов в секунду.
======================================================================
Под пустыми тактами понимается время, в которое процессор простаивает
в ожидании прерывания (в инструкции hlt).
 
Параметры:
* eax = 18 - номер функции
* ebx = 4 - номер подфункции
Возвращаемое значение:
* eax = значение счётчика пустых тактов в секунду
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_IDLE_COUNT (4)
======================================================================
======== Функция 18, подфункция 5 - получить тактовую частоту. =======
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 5 - номер подфункции
Возвращаемое значение:
* eax = тактовая частота (по модулю 2^32 тактов = 4ГГц)
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_CPU_FREQUENCY (5)
======================================================================
Функция 18, подфункция 6 - сохранить рамдиск в файл на жёстком диске.
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 6 - номер подфункции
* ecx = указатель на строку с полным именем файла
(например, "/hd0/1/kolibri/kolibri.img")
Возвращаемое значение:
* eax = 0 - успешно
* иначе eax = код ошибки файловой системы
Замечания:
* Все папки в указанном пути должны существовать, иначе вернётся
значение 5, "файл не найден".
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_RD_TO_HDD (6)
======================================================================
====== Функция 18, подфункция 7 - получить номер активного окна. =====
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 7 - номер подфункции
Возвращаемое значение:
* eax = номер активного окна (номер слота потока, окно которого
активно)
Замечания:
* Активное окно находится вверху оконного стэка и получает
сообщения обо всём вводе с клавиатуры.
* Сделать окно активным можно вызовом подфункции 3.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_ACTIVE_WINDOW (7)
======================================================================
==== Функция 18, подфункция 8 - отключить/разрешить звук спикера. ====
======================================================================
При отключённом звуке вызовы подфункции 55 функции 55 игнорируются.
При включённом - направляются на встроенный спикер.
 
--------------- Подподфункция 1 - получить состояние. ----------------
Параметры:
* eax = 18 - номер функции
* ebx = 8 - номер подфункции
* ecx = 1 - номер подподфункции
Возвращаемое значение:
* eax = 0 - звук спикера разрешён; 1 - запрещён
 
-------------- Подподфункция 2 - переключить состояние. --------------
Переключает состояния разрешения/запрещения.
Параметры:
* eax = 18 - номер функции
* ebx = 8 - номер подфункции
* ecx = 2 - номер подподфункции
Возвращаемое значение:
* функция не возвращает значения
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_SPEAKER (8)
ecx - SSSF_GET_STATE (1), SSSF_TOGGLE (2)
======================================================================
= Функция 18, подфункция 9 - завершение работы системы с параметром. =
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 9 - номер подфункции
* ecx = параметр:
* 2 = выключить компьютер
* 3 = перезагрузить компьютер
* 4 = перезапустить ядро из файла kernel.mnt на рамдиске
Возвращаемое значение:
* при неверном ecx регистры не меняются (т.е. eax=18)
* при правильном вызове всегда возвращается признак успеха eax=0
Замечания:
* Не следует полагаться на возвращаемое значение при неверном
вызове, оно может измениться в последующих версиях ядра.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_SHUTDOWN (9)
======================================================================
========= Функция 18, подфункция 10 - свернуть активное окно. ========
======================================================================
Сворачивает активное окно.
Параметры:
* eax = 18 - номер функции
* ebx = 10 - номер подфункции
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Минимизированное окно с точки зрения функции 9 сохраняет положение
и размеры.
* Восстановление окна приложения происходит при активизировании
подфункцией 3.
* Обычно нет необходимости явно сворачивать/разворачивать своё окно:
сворачивание окна осуществляется системой при нажатии на кнопку
минимизации (которая для окон со скином определяется автоматически
функцией 0, для окон без скина её можно определить функцией 8),
восстановление - приложением @taskbar.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_MINIMIZE_WINDOW (10)
======================================================================
====================== Функция 18, подфункция 11 =====================
============= Получить информацию о дисковой подсистеме. =============
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 11 - номер подфункции
* ecx = тип таблицы:
* 1 = короткая версия, 16 байт
* edx = указатель на буфер (в приложении) для таблицы
Возвращаемое значение:
* функция не возвращает значения
Формат таблицы: короткая версия:
* +0: byte: информация о НГМД (дисководах для дискет), AAAABBBB,
где AAAA задаёт тип первого дисковода, BBBB - второго согласно
следующему списку:
* 0 = нет дисковода
* 1 = 360Kb, 5.25''
* 2 = 1.2Mb, 5.25''
* 3 = 720Kb, 3.5''
* 4 = 1.44Mb, 3.5''
* 5 = 2.88Mb, 3.5'' (такие дискеты сейчас уже не используются)
Например, для стандартной конфигурации из одного 1.44-дисковода
здесь будет 40h, а для случая 1.2Mb на A: и 1.44Mb на B:
значение оказывается 24h.
 
Первый контроллер IDE:
* +1: byte: информация о жёстких дисках и CD-приводах, AABBCCDD,
где AA соответствует контроллеру IDE0, ..., DD - IDE3:
* 0 = устройство отсутствует
* 1 = жёсткий диск
* 2 = CD-привод
Например, в случае HD на IDE0 и CD на IDE2 здесь будет 48h.
* +2: 4 db: число найденных разделов на жёстких дисках с
соответственно IDE0,...,IDE3.
 
Второй контроллер IDE:
* +6: byte: информация о жёстких дисках и CD-приводах, AABBCCDD
где AA соответствует контроллеру IDE4, ..., DD - IDE7:
* 0 = устройство отсутствует
* 1 = жёсткий диск
* 2 = CD-привод
Например, в случае HD на IDE4 и CD на IDE6 здесь будет 48h.
* +7: 4 db: число найденных разделов на жёстких дисках с
соответственно IDE4,...,IDE7.
 
Третий контроллер IDE:
* +11: byte: информация о жёстких дисках и CD-приводах, AABBCCDD
где AA соответствует контроллеру IDE8, ..., DD - IDE11:
* 0 = устройство отсутствует
* 1 = жёсткий диск
* 2 = CD-привод
Например, в случае HD на IDE8 и CD на IDE10 здесь будет 48h.
* +12: 4 db: число найденных разделов на жёстких дисках с
соответственно IDE8,...,IDE11.
 
При отсутствии жёсткого диска на IDEx соответствующий байт
нулевой, при наличии показывает число распознанных разделов,
которых может и не быть (если носитель не отформатирован или
если файловая система не поддерживается). В текущей версии ядра
для жёстких дисков поддерживаются только FAT12/16/32, NTFS,
ext2/3/4 и XFS.
 
Замечания:
* Таблица может быть использована для получения информации
об имеющихся устройствах.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_INFO_DISC_SYS (11)
======================================================================
========== Функция 18, подфункция 13 - получить версию ядра. =========
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 13 - номер подфункции
* ecx = указатель на буфер (не менее 16 байт), куда будет помещена
информация
Возвращаемое значение:
* функция не возвращает значения
но, если указатель в ecx недопустимый, например,
регион [ecx, ecx + 9) пересекается с памятью ядра,
то тогда функция возвращает -1
Замечания:
* В данный момент используется только часть буфера размером
9 байт. Тем не менее рекомендуется использовать буфер
размером 16 байт для будущей совместимости, в будущем могут быть
добавлены некоторые поля.
Структура буфера:
db a,b,c,d для версии a.b.c.d
db 0: зарезервировано
dd REV - номер svn-ревизии ядра
Для ядра Kolibri 0.7.7.0+:
db 0,7,7,0
db 0
dd 1675
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_KERNEL_VERSION (13)
======================================================================
====================== Функция 18, подфункция 14 =====================
======= Ожидать начала обратного хода луча развёртки монитора. =======
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 14 - номер подфункции
Возвращаемое значение:
* eax = 0 как признак успеха
Замечания:
* Функция предназначена исключительно для активных
высокопроизводительных графических приложений; используется для
плавного вывода графики.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_WAIT_RETRACE (14)
======================================================================
== Функция 18, подфункция 15 - поместить курсор мыши в центр экрана. =
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 15 - номер подфункции
Возвращаемое значение:
* eax = 0 как признак успеха
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_CURSOR_CENTER (15)
======================================================================
====================== Функция 18, подфункция 16 =====================
============ Получить размер свободной оперативной памяти. ===========
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 16 - номер подфункции
Возвращаемое значение:
* eax = размер свободной памяти в килобайтах
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_FREE_RAM (16)
======================================================================
====================== Функция 18, подфункция 17 =====================
============ Получить размер имеющейся оперативной памяти. ===========
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 17 - номер подфункции
Возвращаемое значение:
* eax = общий размер имеющейся памяти в килобайтах
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_TOTAL_RAM (17)
======================================================================
====================== Функция 18, подфункция 18 =====================
============= Завершить процесс/поток по идентификатору. =============
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 18 - номер подфункции
* ecx = идентификатор процесса/потока (PID/TID)
Возвращаемое значение:
* eax = 0 - успешно
* eax = -1 - ошибка (процесс не найден или является системным)
Замечания:
* Нельзя завершить поток операционной системы OS/IDLE (номер слота
1), можно завершить любой обычный поток/процесс.
* Смотри также подфункцию 2 - завершение
процесса/потока по заданному слоту.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_TERMINATE_THREAD_ID (18)
======================================================================
=== Функция 18, подфункция 19 - получить/установить настройки мыши. ==
======================================================================
 
------------- Подподфункция 0 - получить скорость мыши. --------------
Параметры:
* eax = 18 - номер функции
* ebx = 19 - номер подфункции
* ecx = 0 - номер подподфункции
Возвращаемое значение:
* eax = текущий делитель скорости
 
------------ Подподфункция 1 - установить скорость мыши. -------------
Параметры:
* eax = 18 - номер функции
* ebx = 19 - номер подфункции
* ecx = 1 - номер подподфункции
* edx = новое значение делителя скорости
Возвращаемое значение:
* функция не возвращает значения
 
Замечание: рекомендуемый делитель скорости = 4
 
---------- Подподфункция 2 - получить чувствительность мыши ----------
Параметры:
* eax = 18 - номер функции
* ebx = 19 - номер подфункции
* ecx = 2 - номер подподфункции
Возвращаемое значение:
* eax = текущий коэффициент чувствительности
 
--------- Подподфункция 3 - установить чувствительность мыши ---------
Параметры:
* eax = 18 - номер функции
* ebx = 19 - номер подфункции
* ecx = 3 - номер подподфункции
* edx = новое значение коэффициента чувствительности
Возвращаемое значение:
* функция не возвращает значения
 
Замечание: рекомендуемый коэффициент чувствительности = 3
 
-------- Подподфункция 4 - установить положение курсора мыши. --------
Параметры:
* eax = 18 - номер функции
* ebx = 19 - номер подфункции
* ecx = 4 - номер подподфункции
* edx = [координата по оси x]*65536 + [координата по оси y]
Возвращаемое значение:
* функция не возвращает значения
 
------- Подподфункция 5 - симулировать состояние клавиш мыши. --------
Параметры:
* eax = 18 - номер функции
* ebx = 19 - номер подфункции
* ecx = 5 - номер подподфункции
* edx = информация о эмулируемом состоянии кнопок мыши:
(соответствует возвращаемому значению подфункции 2 функции 37)
* бит 0 установлен = левая кнопка нажата
* бит 1 установлен = правая кнопка нажата
* бит 2 установлен = средняя кнопка нажата
* бит 3 установлен = 4-я кнопка нажата
* бит 4 установлен = 5-я кнопка нажата
Возвращаемое значение:
* функция не возвращает значения
 
-------- Подподфункция 6 - получить задержку двойного щелчка. --------
Параметры:
* eax = 18 - номер функции
* ebx = 19 - номер подфункции
* ecx = 6 - номер подподфункции
Возвращаемое значение:
* eax = текущая задержка двойного щелчка (100 = секунда)
 
------- Подподфункция 7 - установить задержку двойного щелчка. -------
Параметры:
* eax = 18 - номер функции
* ebx = 19 - номер подфункции
* ecx = 7 - номер подподфункции
* dl = новое значение задержки двойного щелчка (100 = секунда)
Возвращаемое значение:
* функция не возвращает значения
 
Замечание: настройки мыши можно регулировать в приложении mouse_cfg.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_MOUSE_SETTINGS (19)
ecx - SSSF_GET_SPEED (0), SSSF_SET_SPEED (1), SSSF_GET_SPEEDUP (2),
SSSF_SET_SPEEDUP (3), SSSF_SET_POS (4), SSSF_SET_BUTTON (5),
SSSF_GET_DOUBLE_CLICK_DELAY (6), SSSF_SET_DOUBLE_CLICK_DELAY (7)
======================================================================
====================== Функция 18, подфункция 20 =====================
============= Получить информацию об оперативной памяти. =============
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 20 - номер подфункции
* ecx = указатель на буфер для информации (36 байт)
Возвращаемое значение:
* eax = общий размер имеющейся оперативной памяти в байтах
или -1 в случае ошибки
* буфер, на который указывает ecx, содержит следующую информацию:
* +0: dword: общий размер имеющейся оперативной памяти в страницах
* +4: dword: размер свободной оперативной памяти в страницах
* +8: dword: число страничных ошибок (исключений #PF)
в приложениях
* +12: dword: размер кучи ядра в байтах
* +16: dword: размер свободной памяти в куче ядра в байтах
* +20: dword: общее количество блоков памяти в куче ядра
* +24: dword: количество свободных блоков памяти в куче ядра
* +28: dword: размер наибольшего свободного блока в куче ядра
(зарезервировано)
* +32: dword: размер наибольшего выделенного блока в куче ядра
(зарезервировано)
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_RAM_INFO (20)
======================================================================
====================== Функция 18, подфункция 21 =====================
======= Получить номер слота процесса/потока по идентификатору. ======
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 21 - номер подфункции
* ecx = идентификатор процесса/потока (PID/TID)
Возвращаемое значение:
* eax = 0 - ошибка (неверный идентификатор)
* иначе eax = номер слота
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_THREAD_SLOT (21)
======================================================================
Функция 18, подфункция 22 - операции с окном другого процесса/потока.
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 22 - номер подфункции
* ecx = тип операции:
* 0 = минимизация окна, поток задан номером слота
* 1 = минимизация окна, поток задан идентификатором
* 2 = восстановление окна, поток задан номером слота
* 3 = восстановление окна, поток задан идентификатором
* edx = параметр операции (номер слота или PID/TID)
Возвращаемое значение:
* eax = 0 - успешно
* eax = -1 - ошибка (неправильный параметр)
Замечания:
* Поток может свернуть своё окно вызовом подфункции 10.
* Восстановление окна с одновременной активизацией осуществляется
подфункции 3 (принимающей номер слота).
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_FOREIGN_WINDOW (22)
ecx - SSSF_MINIMIZE (0), SSSF_MINIMIZE_ID (1), SSSF_RESTORE (2),
SSSF_RESTORE_ID (3)
======================================================================
======= Функция 18, подфункция 23 - минимизировать все окна. =========
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 23 - номер подфункции
Возвращаемое значение:
* eax = 0 - все окна были минимизированы до вызова функции
* eax = N - количество окон свернутых функцией
Замечания:
* Окна спец. потоков (имя начинается с символа @) не сворачиваются.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_MINIMIZE_ALL (23)
======================================================================
===== Функция 18, подфункция 24 - установить пределы отрисовки. ======
======================================================================
Параметры:
* eax = 18 - номер функции
* ebx = 24 - номер подфункции
* ecx = новый размер по X
* edx = новый размер по Y
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Функция не меняет физический размер видеорежима. Она предназначена
для нестандартных дисплеев, отображающих изображение частично.
* Размеры указываемые в функции не должны превышать размеры текущего
видеорежима, иначе функция ничего не изменит.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_SET_SCREEN_LIMITS (24)
======================================================================
===================== Функция 18, подфункция 25 ======================
======== Управление положением окна относительно других окон. ========
======================================================================
 
------------- Подподфункция 1 - получить положение ------------------
Параметры:
* eax = 18 - номер функции
* ebx = 25 - номер подфункции
* ecx = 1 - номер подподфункции
* edx = -1(для текущего окна) или PID приложения
Возвращаемое значение:
* eax = одна из констант положения окна
 
------------- Подподфункция 2 - установить положение ----------------
Параметры:
* eax = 18 - номер функции
* ebx = 25 - номер подфункции
* ecx = 2 - номер подподфункции
* edx = -1(для текущего окна) или PID приложения
* esi = новое положение окна (одна из констант ниже)
Возвращаемое значение:
* eax = 0 - неудача
* eax = 1 - успех
 
Константы положения окна относительно других окон:
ZPOS_DESKTOP = -2 - на самом заднем плане
ZPOS_ALWAYS_BACK = -1 - позади всех окон
ZPOS_NORMAL = 0 - обычное
ZPOS_ALWAYS_TOP = 1 - поверх всех окон
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_WINDOW_BEHAVIOR (25)
ecx - SSSF_GET_WB (1), SSSF_SET_WB (2)
======================================================================
==================== Функция 20 - интерфейс MIDI. ====================
======================================================================
 
------------------------ Подфункция 1 - сброс ------------------------
Параметры:
* eax = 20 - номер функции
* ebx = 1 - номер подфункции
 
-------------------- Подфункция 2 - вывести байт ---------------------
Параметры:
* eax = 20 - номер функции
* ebx = 2 - номер подфункции
* cl = байт для вывода
Возвращаемое значение (одинаково для обеих подфункций):
* eax = 0 - успешно
* eax = 1 - не определён базовый порт
Замечания:
* Предварительно должен быть определён базовый порт вызовом
подфункции 1 функции 21.
 
---------------------- Константы для регистров: ----------------------
eax - SF_MIDI (20)
ebx - SSF_RESET (1), SSF_OUTPUT (2)
======================================================================
==== Функция 21, подфункция 1 - установить базовый порт MPU MIDI. ====
======================================================================
Параметры:
* eax = 21 - номер функции
* ebx = 1 - номер подфункции
* ecx = номер базового порта
Возвращаемое значение:
* eax = 0 - успешно
* eax = -1 - ошибочный номер порта
Замечания:
* Номер порта должен удовлетворять условиям 0x100<=ecx<=0xFFFF.
* Установка базы нужна для работы функции 20.
* Получить установленный базовый порт можно вызовом
подфункции 1 функции 26.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_MPU_MIDI_BASE (1)
======================================================================
===== Функция 21, подфункция 2 - установить раскладку клавиатуры. ====
======================================================================
Раскладка клавиатуры используется для преобразования сканкодов,
поступающих от клавиатуры, в ASCII-коды, считываемые функцией 2.
Параметры:
* eax = 21 - номер функции
* ebx = 2 - номер подфункции
* ecx = какую раскладку устанавливать:
* 1 = нормальную
* 2 = раскладку при нажатом Shift
* 3 = раскладку при нажатом Alt
* edx = указатель на раскладку - таблицу длиной 128 байт
Или:
* ecx = 9
* dx = идентификатор страны (1=eng, 2=fi, 3=ger, 4=rus)
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - параметр задан неверно
Замечания:
* Если нажат Alt, то используется раскладка с Alt;
если не нажат Alt, но нажат Shift, то
используется раскладка с Shift;
если не нажаты Alt и Shift, но нажат Ctrl, то используется
нормальная раскладка, после чего из кода вычитается 0x60;
если не нажата ни одна из управляющих клавиш, то используется
нормальная раскладка.
* Получить раскладки и идентификатор страны можно с помощью
подфункции 2 функции 26.
* Идентификатор страны - глобальная системная переменная, которая
самим ядром не используется; однако приложение @taskbar отображает
соответствующую текущей стране иконку.
* Приложение @taskbar переключает раскладки по запросу пользователя.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_KEYBOARD_LAYOUT (2)
======================================================================
========= Функция 21, подфункция 5 - установить язык системы. ========
======================================================================
Параметры:
* eax = 21 - номер функции
* ebx = 5 - номер подфункции
* ecx = язык системы (1=eng, 2=fi, 3=ger, 4=rus)
Возвращаемое значение:
* eax = 0
Замечания:
* Язык системы - глобальная системная переменная, никак
не используемая самим ядром, однако приложение @taskbar рисует
соответствующую иконку.
* Проверок на корректность не делается, поскольку ядро эту
переменную не использует.
* Получить язык системы можно вызовом подфункции 5 функции 26.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_SYS_LANG (5)
======================================================================
====================== Функция 21, подфункция 11 =====================
=========== Разрешить/запретить низкоуровневый доступ к HD. ==========
======================================================================
Параметры:
* eax = 21 - номер функции
* ebx = 11 - номер подфункции
* ecx = 0/1 - запретить/разрешить
Возвращаемое значение:
* eax = 0
Замечания:
* Используется при LBA-чтении (подфункция 8 функции 58).
* Текущая реализация использует только младший бит ecx.
* Получить текущее состояние можно вызовом подфункции 11 функции 26.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_ACCESS_HD_LBA (11)
======================================================================
====================== Функция 21, подфункция 12 =====================
========== Разрешить/запретить низкоуровневый доступ к PCI. ==========
======================================================================
Параметры:
* eax = 21 - номер функции
* ebx = 12 - номер подфункции
* ecx = 0/1 - запретить/разрешить
Возвращаемое значение:
* eax = 0
Замечания:
* Используется при работе с шиной PCI (функция 62).
* Текущая реализация использует только младший бит ecx.
* Получить текущее состояние можно вызовом подфункции 12 функции 26.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_ACCESS_PCI (12)
======================================================================
============ Функция 22 - установить системную дату/время. ===========
======================================================================
Параметры:
* eax = 22 - номер функции
* ebx = 0 - установить время
* ecx = 0x00SSMMHH - время в двоично-десятичном коде (BCD):
* HH=час 00..23
* MM=минута 00..59
* SS=секунда 00..59
* ebx = 1 - установить дату
* ecx = 0x00DDMMYY - дата в двоично-десятичном коде (BCD):
* DD=день 01..31
* MM=месяц 01..12
* YY=год 00..99
* ebx = 2 - установить день недели
* ecx = 1 для воскресенья, ..., 7 для субботы
* ebx = 3 - установить будильник
* ecx = 0x00SSMMHH
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - параметр задан неверно
* eax = 2 - CMOS-батарейки разрядились
Замечания:
* Ценность установки дня недели представляется сомнительной,
поскольку он мало где используется
(день недели можно рассчитать по дате).
* Будильник можно установить на срабатывание в заданное время
каждые сутки. При этом отключить его существующими системными
функциями нельзя.
* Срабатывание будильника заключается в генерации IRQ8.
* Вообще-то CMOS поддерживает для будильника установку значения
0xFF в качестве одного из параметров и означает это, что
соответствующий параметр игнорируется. Но в текущей реализации
это не пройдёт (вернётся значение 1).
* Будильник - глобальный системный ресурс; установка будильника
автоматически отменяет предыдущую установку. Впрочем, на данный
момент ни одна программа его не использует.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SET_TIME_DATE (22)
======================================================================
============== Функция 23 - ожидать события с таймаутом. =============
======================================================================
Если очередь сообщений пуста, ждёт появления сообщения в очереди,
но не более указанного времени. Затем считывает сообщение из очереди.
 
Параметры:
* eax = 23 - номер функции
* ebx = таймаут (в сотых долях секунды)
Возвращаемое значение:
* eax = 0 - очередь сообщений пуста
* иначе eax = событие (смотри список событий)
Замечания:
* Учитываются только те события, которые входят в маску,
устанавливаемую функцией 40. По умолчанию это события
перерисовки, нажатия на клавиши и на кнопки.
* Для проверки, есть ли сообщение в очереди, используйте функцию 11.
Чтобы ждать сколь угодно долго, используйте функцию 10.
* Передача ebx=0 приводит к моментальному возвращению eax=0.
* При текущей реализации произойдёт немедленный возврат из функции
с eax=0, если сложение ebx с текущим значением счётчика времени
вызовет 32-битное переполнение.
 
---------------------- Константы для регистров: ----------------------
eax - SF_WAIT_EVENT_TIMEOUT (23)
======================================================================
======= Функция 24, подфункция 4 - извлечь лоток привода диска. ======
======================================================================
Параметры:
* eax = 24 - номер функции
* ebx = 4 - номер подфункции
* ecx = номер CD/DVD-диска
от 0=Primary Master до 3=Secondary Slave для первого IDE контр.
от 4=Primary Master до 7=Secondary Slave для второго IDE контр.
от 8=Primary Master до 11=Secondary Slave для третьего IDE контр.
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Функция поддерживается только для ATAPI-устройств (CD и DVD).
* При извлечении лотка производится разблокировка ручного управления
механизмом лотка.
* При извлечении лотка код производит очистку кэша соответствующего
устройства.
* Примером использования функции является приложение CD_tray.
 
---------------------- Константы для регистров: ----------------------
eax - SF_CD (24)
ebx - SSF_EJECT_TRAY (4), SSF_INSERT_TRAY (5)
======================================================================
====== Функция 24, подфункция 5 - загрузить лоток привода диска. =====
======================================================================
Параметры:
* eax = 24 - номер функции
* ebx = 5 - номер подфункции
* ecx = номер CD/DVD-диска
от 0=Primary Master до 3=Secondary Slave для первого IDE контр.
от 4=Primary Master до 7=Secondary Slave для второго IDE контр.
от 8=Primary Master до 11=Secondary Slave для третьего IDE контр.
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Функция поддерживается только для ATAPI-устройств (CD и DVD).
* Примером использования функции является приложение CD_tray.
 
---------------------- Константы для регистров: ----------------------
eax - SF_CD (24)
ebx - SSF_EJECT_TRAY (4), SSF_INSERT_TRAY (5)
======================================================================
========== Функция 25 - записать область на слой фона. ===============
======================================================================
Параметры:
* eax = 25 - номер функции
* ebx = указатель на предварительно выделенную область памяти,
где размещено исходное изображение в формате BBGGRRTTBBGGRRTT...
* ecx = [размер по оси x]*65536 + [размер по оси y]
* edx = [координата по оси x]*65536 + [координата по оси y]
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Координаты области - это координаты верхнего левого угла
области относительно экрана.
* Размер изображения в байтах есть 4*xsize*ysize.
* TT - байт указатель прозрачности, в настоящее время:
от 1 до FF - непрозрачно, от 0 - прозрачно.
* Функция размещает изображение не на фоновое изображение (ф.15),
а напрямую в LFB. Опции ф.15 для ф. 25 не имеют смысла.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SCREEN_PUT_IMAGE (25)
======================================================================
===== Функция 26, подфункция 1 - получить базовый порт MPU MIDI. =====
======================================================================
Параметры:
* eax = 26 - номер функции
* ebx = 1 - номер подфункции
Возвращаемое значение:
* eax = номер порта
Замечания:
* Установить базовый порт можно вызовом
подфункции 1 функции 21.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_MPU_MIDI_BASE (1)
======================================================================
====== Функция 26, подфункция 2 - получить раскладку клавиатуры. =====
======================================================================
Раскладка клавиатуры используется для преобразования сканкодов,
поступающих от клавиатуры, в ASCII-коды, считываемые функцией 2.
Параметры:
* eax = 26 - номер функции
* ebx = 2 - номер подфункции
* ecx = какую раскладку получать:
* 1 = нормальную
* 2 = раскладку при нажатом Shift
* 3 = раскладку при нажатом Alt
* edx = указатель на буфер длиной 128 байт, куда будет скопирована
раскладка
Возвращаемое значение:
* функция не возвращает значения,
но, если указатель в edx недопустимый, например,
регион [edx, edx + 128) пересекается с памятью ядра,
то тогда функция возвращает -1
Или:
* eax = 26 - номер функции
* ebx = 2 - номер подфункции
* ecx = 9
Возвращаемое значение:
* eax = идентификатор страны (1=eng, 2=fi, 3=ger, 4=rus)
Замечания:
* Если нажат Alt, то используется раскладка с Alt;
если не нажат Alt, но нажат Shift, то используется
раскладка с Shift;
если не нажаты Alt и Shift, но нажат Ctrl, то используется
нормальная раскладка, после чего из кода вычитается 0x60;
если не нажата ни одна из управляющих клавиш, то используется
нормальная раскладка.
* Установить раскладки и идентификатор страны можно с помощью
подфункции 2 функции 21.
* Идентификатор страны - глобальная системная переменная, которая
самим ядром не используется; однако приложение @taskbar отображает
соответствующую текущей стране иконку
(используя описываемую функцию).
* Приложение @taskbar переключает раскладки по запросу пользователя.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_KEYBOARD_LAYOUT (2)
======================================================================
========== Функция 26, подфункция 5 - получить язык системы. =========
======================================================================
Параметры:
* eax = 26 - номер функции
* ebx = 5 - номер подфункции
Возвращаемое значение:
* eax = язык системы (1=eng, 2=fi, 3=ger, 4=rus)
Замечания:
* Язык системы - глобальная системная переменная, никак
не используемая самим ядром, однако приложение @taskbar рисует
соответствующую иконку (используя описываемую функцию).
* Установить язык системы можно вызовом подфункции 5 функции 21.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_SYS_LANG (5)
======================================================================
=== Функция 26, подфункция 9 - получить значение счётчика времени. ===
======================================================================
Параметры:
* eax = 26 - номер функции
* ebx = 9 - номер подфункции
Возвращаемое значение:
* eax = число сотых долей секунды, прошедших с момента
запуска системы
Замечания:
* Счётчик берётся по модулю 2^32, что соответствует немногим более
497 суток.
* Системное время можно получить функцией 3.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_TIME_COUNT (9)
======================================================================
===================== Функция 26, подфункция 10 ======================
========== Получить значение высокоточного счётчика времени. =========
======================================================================
Parameters:
* eax = 26 - номер функции
* ebx = 10 - номер подфункции
Returned value:
* edx:eax = число наносекунд с момента загрузки ядра
* eax = младшее двойное слово
* edx = старшее двойное слово
Remarks:
* функция использует счётчик HPET, если HPET не доступен используется
счётчик PIT. В этом случае точность будет уменьшена до 10 000 000
наносекунд.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_TIME_COUNT_PRO (10)
======================================================================
====================== Функция 26, подфункция 11 =====================
=========== Узнать, разрешён ли низкоуровневый доступ к HD. ==========
======================================================================
Параметры:
* eax = 26 - номер функции
* ebx = 11 - номер подфункции
Возвращаемое значение:
* eax = 0/1 - запрещён/разрешён
Замечания:
* Используется при LBA-чтении (подфункция 8 функции 58).
* Установить текущее состояние можно вызовом
подфункции 11 функции 21.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_ACCESS_HD_LBA (11)
======================================================================
====================== Функция 26, подфункция 12 =====================
========== Узнать, разрешён ли низкоуровневый доступ к PCI. ==========
======================================================================
Параметры:
* eax = 26 - номер функции
* ebx = 12 - номер подфункции
Возвращаемое значение:
* eax = 0/1 - запрещён/разрешён
Замечания:
* Используется при работе с шиной PCI (функция 62).
* Текущая реализация использует только младший бит ecx.
* Установить текущее состояние можно вызовом
подфункции 12 функции 21.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_ACCESS_PCI (12)
======================================================================
================ Функция 29 - получить системную дату. ===============
======================================================================
Параметры:
* eax = 29 - номер функции
Возвращаемое значение:
* eax = 0x00DDMMYY, где
(используется двоично-десятичное кодирование, BCD)
* YY = две младшие цифры года (00..99)
* MM = месяц (01..12)
* DD = день (01..31)
Замечания:
* Системную дату можно установить функцией 22.
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_SYS_DATE (29)
======================================================================
================ Функция 30 - работа с текущей папкой. ===============
======================================================================
-------- Подфункция 1 - установить текущую папку для потока. ---------
Параметры:
* eax = 30 - номер функции
* ebx = 1 - номер подфункции
* ecx = указатель на строку с путём к новой текущей папке,
правила формирования строки указаны в описании функции 70.
Возвращаемое значение:
* функция не возвращает значения
----------------------------------------------------------------------
--------- Подфункция 2 - получить текущую папку для потока. ----------
Параметры:
* eax = 30 - номер функции
* ebx = 2 - номер подфункции
* ecx = указатель на буфер
* edx = размер буфера
Возвращаемое значение:
* eax = длина строки (включая завершающий 0)
Замечания:
* Если размера буфера недостаточно для копирования всего пути,
копируются только часть строки и в конце ставится завершающий 0.
* По умолчанию, текущая папка для потока - "/rd/1".
* При создании процесса/потока текущая папка наследуется от
родителя.
----------------------------------------------------------------------
---- Подфункция 3 - установить доп. системную директорию для ядра ----
Параметры:
* eax = 30 - номер функции
* ebx = 3 - номер подфункции
* ecx = указатель на блок данных:
key rb 64
path rb 64
Пример:
align 64
key db 'kolibrios',0 ; ключ должен быть в нижнем регистре
align 64
path db 'HD0/1',0
 
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Функция может быть вызвана только 1 раз за 1 сессию работы ОС.
* При вводе пути символьный ключ не зависит от кодировки.
----------------------------------------------------------------------
--- Подфункция 4 - установить текущую папку с указанием кодировки. ---
Параметры:
* eax = 30 - номер функции
* ebx = 4 - номер подфункции
* ecx = указатель на строку с путём к новой текущей папке
* edx = кодировка строки, подробности указаны в описании функции 80.
Возвращаемое значение:
* функция не возвращает значения
----------------------------------------------------------------------
---- Подфункция 5 - получить текущую папку с указанием кодировки. ----
Параметры:
* eax = 30 - номер функции
* ebx = 5 - номер подфункции
* ecx = указатель на буфер
* edx = размер буфера
* esi = кодировка строки
Возвращаемое значение:
* eax = длина строки в байтах (включая завершающий 0)
Замечания:
* Если размера буфера недостаточно для копирования всего пути,
копируются только часть строки и в конце ставится завершающий 0.
* По умолчанию, текущая папка для потока - "/rd/1".
* При создании процесса/потока текущая папка наследуется от
родителя.
 
---------------------- Константы для регистров: ----------------------
eax - SF_CURRENT_FOLDER (30)
ebx - SSF_SET_CF (1), SSF_GET_CF (2), SSF_ADD_SYS_FOLDER (3)
======================================================================
========= Функция 34 - узнать кому принадлежит точка экрана. =========
======================================================================
Параметры:
* eax = 34 - номер функции
* ebx = x-координата (относительно экрана)
* ecx = y-координата (относительно экрана)
 
Возвращаемое значение:
* eax = 0x000000XX - точка принадлежит слоту окна N
При некорректных значениях ebx и ecx функция возвращает 0
* Функция берет значения из области [_WinMapAddress]
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_PIXEL_OWNER (34)
======================================================================
============ Функция 35 - прочитать цвет точки на экране. ============
======================================================================
Параметры:
* eax = 35
* ebx = y*xsize+x, где
* (x,y) = координаты точки (считая от 0)
* xsize = размер экрана по горизонтали
Возвращаемое значение:
* eax = цвет 0x00RRGGBB
Замечания:
* Узнать размеры экрана можно вызовом функции 14. Обратите внимание,
что она вычитает 1 из обоих размеров.
* К видеопамяти есть также прямой доступ (без вызовов системных
функций) через селектор gs. Параметры текущего видеорежима
можно получить функцией 61.
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_PIXEL (35)
======================================================================
=============== Функция 36 - прочитать область экрана. ===============
======================================================================
Параметры:
* eax = 36 - номер функции
* ebx = указатель на предварительно выделенную область памяти,
куда будет помещено изображение в формате BBGGRRBBGGRR...
* ecx = [размер по оси x]*65536 + [размер по оси y]
* edx = [координата по оси x]*65536 + [координата по оси y]
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Координаты области - это координаты верхнего левого угла
области относительно экрана.
* Размер изображения в байтах есть 3*xsize*ysize.
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_IMAGE (36)
======================================================================
==================== Функция 37 - работа с мышью. ====================
======================================================================
 
-------------- Подфункция 0 - экранные координаты мыши ---------------
Параметры:
* eax = 37 - номер функции
* ebx = 0 - номер подфункции
Возвращаемое значение:
* eax = x*65536 + y, (x,y)=координаты курсора мыши (считая от 0)
 
---------- Подфункция 1 - координаты мыши относительно окна ----------
Параметры:
* eax = 37 - номер функции
* ebx = 1 - номер подфункции
Возвращаемое значение:
* eax = x*65536 + y, (x,y)=координаты курсора мыши относительно
окна приложения (считая от 0)
Замечания:
* Значение вычисляется по формуле (x-xwnd)*65536 + (y-ywnd).
Если y>=ywnd, то младшее слово неотрицательно и содержит
относительную y-координату, а старшее - относительную x-координату
(правильного знака). В противном случае младшее слово отрицательно
и всё равно содержит относительную y-координату,
а к старшему слову следует прибавить 1.
 
---------------- Подфункция 2 - состояния кнопок мыши ----------------
Параметры:
* eax = 37 - номер функции
* ebx = 2 - номер подфункции
Возвращаемое значение:
* eax = биты 0-4 соответствуют подфункции 3
 
----------- Подфункция 3 - состояния и события кнопок мыши -----------
Параметры:
* eax = 37 - номер функции
* ebx = 3 - номер подфункции
Возвращаемое значение:
* eax содержит следующую информацию:
 
состояния:
* бит 0 установлен = удерживается левая кнопка
* бит 1 установлен = удерживается правая кнопка
* бит 2 установлен = удерживается средняя кнопка
* бит 3 установлен = удерживается 4-я кнопка
* бит 4 установлен = удерживается 5-я кнопка
 
события:
* бит 8 установлен = нажата левая кнопка
* бит 9 установлен = нажата правая кнопка
* бит 10 установлен = нажата средняя кнопка
 
* бит 15 установлен = используется вертикальная прокрутка
 
* бит 16 установлен = отпущена левая кнопка
* бит 17 установлен = отпущена правая кнопка
* бит 18 установлен = отпущена средняя кнопка
 
* бит 23 установлен = используется горизонтальная прокрутка
 
* бит 24 установлен = двойной щелчёк левой кнопкой
 
------------------ Подфункция 4 - загрузить курсор -------------------
Параметры:
* eax = 37 - номер функции
* ebx = 4 - номер подфункции
* dx = источник данных:
* dx = LOAD_FROM_FILE = 0 - данные в файле
* ecx = указатель на полный путь к файлу курсора
* файл курсора должен быть в формате .cur, стандартном для
MS Windows, причём размером 32*32 пикселя
* dx = LOAD_FROM_MEM = 1 - данные файла уже загружены в память
* ecx = указатель на данные файла курсора
* формат данных такой же, как и в предыдущем случае
* dx = LOAD_INDIRECT = 2 - данные в памяти
* ecx = указатель на образ курсора в формате ARGB 32*32 пикселя
* edx = 0xXXYY0002, где
* XX = x-координата "горячей точки" курсора
* YY = y-координата
* 0 <= XX, YY <= 31
Возвращаемое значение:
* eax = 0 - неудача
* иначе eax = хэндл курсора
 
------------------ Подфункция 5 - установить курсор ------------------
Устанавливает новый курсор для окна текущего потока.
Параметры:
* eax = 37 - номер функции
* ebx = 5 - номер подфункции
* ecx = хэндл курсора
Возвращаемое значение:
* eax = хэндл предыдущего установленного курсора
Замечания:
* Если передан некорректный хэндл, то функция восстановит курсор
по умолчанию (стандартную стрелку). В частности, к восстановлению
курсора по умолчанию приводит передача ecx=0.
 
------------------- Подфункция 6 - удалить курсор --------------------
Параметры:
* eax = 37 - номер функции
* ebx = 6 - номер подфункции
* ecx = хэндл курсора
Возвращаемое значение:
* eax разрушается
Замечания:
* Курсор должен был быть ранее загружен текущим потоком
(вызовом подфункции 4). Функция не удаляет системные курсоры и
курсоры, загруженные другими приложениями.
* Если удаляется активный (установленный подфункцией 5) курсор, то
восстанавливается курсор по умолчанию (стандартная стрелка).
 
------------------ Подфункция 7 - данные прокрутки -------------------
Параметры:
* eax = 37 - номер функции
* ebx = 7 - номер подфункции
Возвращаемое значение:
* eax = [horizontal offset]*65536 + [vertical offset]
Замечания:
* Данные доступны только активному окну.
* После прочтения значения обнуляются.
* Данные имеют знаковые значения.
 
------- Подфункция 8 - загрузить курсор с указанием кодировки. -------
Параметры:
* eax = 37 - номер функции
* ebx = 8 - номер подфункции
* ecx = указатель на строку с путём к файлу курсора
* edx = кодировка строки, подробности указаны в описании функции 80.
Возвращаемое значение:
* eax = хэндл курсора, 0 - неудача
 
---------------------- Константы для регистров: ----------------------
eax - SF_MOUSE_GET (37)
ebx - SSF_SCREEN_POSITION (0), SSF_WINDOW_POSITION (1),
SSF_BUTTON (2), SSF_BUTTON_EXT (3), SSF_LOAD_CURSOR (4),
SSF_SET_CURSOR (5), SSF_DEL_CURSOR (6), SSF_SCROLL_DATA (7)
======================================================================
================== Функция 38 - нарисовать отрезок. ==================
======================================================================
Параметры:
* eax = 38 - номер функции
* ebx = [координата начала по оси x]*65536 +
[координата конца по оси x]
* ecx = [координата начала по оси y]*65536 +
[координата конца по оси y]
* edx = 0x00RRGGBB - цвет
edx = 0x01xxxxxx - рисовать инверсный отрезок
(младшие 24 бита игнорируются)
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Координаты берутся относительно окна.
* Конечная точка также рисуется.
 
---------------------- Константы для регистров: ----------------------
eax - SF_DRAW_LINE (38)
======================================================================
== Функция 39, подфункция 1 - получить размер фонового изображения. ==
======================================================================
Параметры:
* eax = 39 - номер функции
* ebx = 1 - номер подфункции
Возвращаемое значение:
* eax = [ширина]*65536 + [высота]
Замечания:
* Есть парная команда установки размеров фонового изображения -
подфункция 1 функции 15. После которой, разумеется, следует
заново определить само изображение.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_GET (39)
======================================================================
= Функция 39, подфункция 2 - прочитать точку с фонового изображения. =
======================================================================
Параметры:
* eax = 39 - номер функции
* ebx = 2 - номер подфункции
* ecx = смещение
Возвращаемое значение:
* eax = 0x00RRGGBB - цвет точки, если смещение допустимо
(меньше 0x160000-16)
* eax = 2 - иначе
Замечания:
* Не следует полагаться на возвращаемое значение в случае неверного
смещения, оно может измениться в следующих версиях ядра.
* Смещение точки с координатами (x,y) вычисляется как (x+y*xsize)*3.
* Есть парная функция установки точки на фоновом изображении -
подфункция 2 функции 15.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_GET (39)
======================================================================
====== Функция 39, подфункция 4 - получить режим отрисовки фона. =====
======================================================================
Параметры:
* eax = 39 - номер функции
* ebx = 4 - номер подфункции
Возвращаемое значение:
* eax = 1 - замостить
* eax = 2 - растянуть
Замечания:
* Есть парная функция установки режима отрисовки фона -
подфункция 4 функции 15.
 
---------------------- Константы для регистров: ----------------------
eax - SF_BACKGROUND_GET (39)
======================================================================
======== Функция 40 - установить маску для ожидаемых событий. ========
======================================================================
Маска для ожидаемых событий влияет на функции работы с событиями 10,
11, 23 - они сообщают только о событиях, разрешённых этой маской.
Параметры:
* eax = 40 - номер функции
* ebx = маска: бит i соответствует событию i+1 (см. список событий)
(установленный бит разрешает извещение о событии)
bit 31: фильтр активности событий мыши
bit 31 = 0 - неактивное окно всегда получает события от мыши
bit 31 = 1 - неактивное окно не получает события от мыши
bit 30: фильтр позиции курсора
bit 30 = 0 - окно принимает события мыши, если курсор
за пределами окна
bit 30 = 1 - окно не принимает события мыши, если курсор
за пределами окна
Возвращаемое значение:
* eax = предыдущее значение маски
Замечания:
* Маска по умолчанию (7=111b) разрешает извещения о перерисовке
и нажатиях клавиш и кнопок.
Этого достаточно для большинства приложений.
* События, запрещённые в маске, всё равно сохраняются, если
приходят; о них просто не извещают функции работы с событиями.
* Функции работы с событиями учитывают маску на момент
вызова функции, а не на момент поступления сообщения.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SET_EVENTS_MASK (40)
======================================================================
=================== Функция 43 - ввод/вывод в порт. ==================
======================================================================
 
------------------------ Вывод данных в порт -------------------------
Параметры:
* eax = 43 - номер функции
* bl = байт для вывода
* ecx = номер порта 0xnnnn (от 0 до 0xFFFF)
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - поток не зарезервировал указанный порт
 
------------------------ Ввод данных из порта ------------------------
Параметры:
* eax = 43 - номер функции
* ebx игнорируется
* ecx = 0x8000nnnn, где nnnn = номер порта (от 0 до 0xFFFF)
Возвращаемое значение:
* eax = 0 - успешно, при этом ebx = введённый байт
* eax = 1 - поток не зарезервировал данный порт
Замечания:
* Предварительно поток должен зарезервировать за собой
указанный порт функцией 46.
* Для зарезервированных портов вместо вызова этих функций
лучше использовать команды процессора in/out - это значительно
быстрее и несколько короче и проще. Из незарезервированных
портов читать всё равно нельзя.
 
---------------------- Константы для регистров: ----------------------
eax - SF_PORT_IN_OUT (43)
======================================================================
= Функция 46 - зарезервировать/освободить группу портов ввода/вывода.
======================================================================
К зарезервированным портам можно обращаться напрямую из приложения
командами in/out (рекомендуемый способ) и вызовом функции 43
(нерекомендуемый способ).
Параметры:
* eax = 46 - номер функции
* ebx = 0 - зарезервировать, 1 - освободить
* ecx = номер начала диапазона портов
* edx = номер конца диапазона портов (включительно)
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - ошибка
Замечания:
* В случае резервирования портов ошибкой считается выполнение
одного из условий:
* начальный адрес больше конечного;
* указанный диапазон содержит некорректный номер порта
(корректные - от 0 до 0xFFFF);
* превышено ограничение на общее число зарезервированных областей
- допускается максимум 255;
* указанный диапазон пересекается с одним из
ранее зарезервированных
* В случае освобождения портов ошибкой считается попытка
освобождения диапазона, который ранее не был целиком
зарезервирован этой же функцией (с такими же значениями ecx,edx).
* При обнаружении ошибки (в обоих случаях) никаких действий
не производится.
* При загрузке система резервирует за собой порты
0..0x2d, 0x30..0x4d, 0x50..0xdf, 0xe5..0xff (включительно).
* При завершении потока автоматически освобождаются все
зарезервированные им порты.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SET_PORTS (46)
======================================================================
================= Функция 47 - вывести число в окно. =================
======================================================================
Параметры:
* eax = 47 - номер функции
* ebx = параметры преобразования числа в текст:
* bl = 0 - ecx содержит число
* bl = 1 - ecx содержит указатель на dword/qword-число
* bh = 0 - отображать в десятичной системе счисления
* bh = 1 - отображать в шестнадцатеричной системе
* bh = 2 - отображать в двоичной системе
* биты 16-21 = сколько цифр отображать
* биты 22-29 зарезервированы и должны быть установлены в 0
* бит 30 установлен = выводить qword (64-битное число);
при этом должно быть bl = 1
* бит 31 установлен = не выводить ведущие нули числа
* ecx = число (при bl=0) или указатель (при bl=1)
* edx = [координата по оси x]*65536 + [координата по оси y]
* esi = 0xXXRRGGBB, где
* RR, GG, BB задают цвет текста
* XX=0B0FCSSS (биты):
* B=1 - закрашивать фон (цвет = edi)
* F задает шрифт:
0 = 6x9
1 = 8x16
* C=0 - рисовать в окно,
С=1 - рисовать в буфер (edi)
* SSS = (множитель размера)-1, то-есть 0 = x1, 7 = x8
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Указанная длина не должна превосходить 60.
* Выводится ровно указанное количество цифр. Если число мало и
может быть записано меньшим количеством цифр, оно дополняется
ведущими нулями; если число велико и не может быть записано
таким количеством цифр, "лишние" ведущие цифры обрезаются.
 
---------------------- Константы для регистров: ----------------------
eax - SF_DRAW_NUMBER (47)
======================================================================
======= Функция 48, подфункция 0 - применить настройки экрана. =======
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 0 - номер подфункции
* ecx = 0 - зарезервировано
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Функция перерисовывает экран после изменения параметров
подфункциями 1 и 2.
* Вызов функции без предшествующих вызовов указанных подфункций
игнорируется.
* Вызов функции с ненулевым ecx игнорируется.
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_APPLY (0)
======================================================================
========= Функция 48, подфункция 1 - установить стиль кнопок. ========
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 1 - номер подфункции
* ecx = тип кнопок:
* 0 = плоские
* 1 = объёмные
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* После вызова описываемой функции следует перерисовать экран
подфункцией 0.
* Тип кнопок влияет только на их прорисовку функцией 8.
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_BUTTON_STYLE (1)
======================================================================
==== Функция 48, подфункция 2 - установить стандартные цвета окон. ===
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 2 - номер подфункции
* ecx = указатель на таблицу цветов
* edx = размер таблицы цветов
(должен быть 40 байт для будущей совместимости)
Формат таблицы цветов указан в описании подфункции 3.
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* После вызова описываемой функции следует перерисовать экран
подфункцией 0.
* Таблица стандартных цветов влияет только на приложения,
которые эту таблицу явным образом получают (подфункцией 3) и
используют (указывая цвета из неё при вызовах функций рисования).
* Таблица стандартных цветов входит в скин и устанавливается заново
при установке скина (подфункции 8).
* Таблицу цветов можно просматривать/изменять интерактивно с помощью
приложения desktop.
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_COLORS (2)
======================================================================
===== Функция 48, подфункция 3 - получить стандартные цвета окон. ====
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 3 - номер подфункции
* ecx = указатель на буфер размером edx байт,
куда будет записана таблица
* edx = размер таблицы цветов
(должен быть 40 байт для будущей совместимости)
Возвращаемое значение:
* функция не возвращает значения
Формат таблицы цветов: каждый элемент -
dword-значение цвета 0x00RRGGBB
* +0: dword: frames - цвет рамки
* +4: dword: grab - цвет заголовка
* +8: dword: grab_button - цвет кнопки на полосе заголовка
* +12 = +0xC: dword: grab_button_text - цвет текста на кнопке
на полосе заголовка
* +16 = +0x10: dword: grab_text - цвет текста на заголовке
* +20 = +0x14: dword: work - цвет рабочей области
* +24 = +0x18: dword: work_button - цвет кнопки в рабочей области
* +28 = +0x1C: dword: work_button_text - цвет текста на кнопке
в рабочей области
* +32 = +0x20: dword: work_text - цвет текста в рабочей области
* +36 = +0x24: dword: work_graph - цвет графики в рабочей области
Замечания:
* Структура таблицы цветов описана в стандартном включаемом файле
macros.inc под названием system_colors; например, можно писать:
sc system_colors ; объявление переменной
... ; где-то надо вызвать
; описываемую функцию с ecx=sc
mov ecx, [sc.work_button_text] ; читаем цвет текста
; на кнопке в рабочей области
* Использование/неиспользование этих цветов - дело исключительно
самой программы. Для использования нужно просто при вызове функций
рисования указывать цвет, взятый из этой таблицы.
* При изменении таблицы стандартных цветов (подфункцией 2 с
последующим применением изменений подфункцией 0 или
при установке скина подфункцией 8) всем окнам посылается сообщение
о необходимости перерисовки (событие с кодом 1).
* Стандартные цвета можно просматривать/изменять интерактивно
с помощью приложения desktop.
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_COLORS (3)
======================================================================
========== Функция 48, подфункция 4 - получить высоту скина. =========
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 4 - номер подфункции
Возвращаемое значение:
* eax = высота скина
Замечания:
* Высотой скина по определению считается высота заголовка окон,
использующих скин.
* Смотри также общую структуру окна в описании функции 0.
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_SKIN_HEIGHT (4)
======================================================================
===== Функция 48, подфункция 5 - получить рабочую область экрана. ====
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 5 - номер подфункции
Возвращаемое значение:
* eax = [left]*65536 + [right]
* ebx = [top]*65536 + [bottom]
Замечания:
* Рабочая область экрана определяет положение и координаты
максимизированного окна.
* Рабочая область экрана при нормальной работе есть весь экран
за вычетом панели (@taskbar).
* (left,top) - координаты левого верхнего угла,
(right,bottom) - координаты правого нижнего.
Таким образом, размер рабочей области по оси x определяется
формулой right-left+1, по оси y - формулой bottom-top+1.
* Смотри также функцию 14,
позволяющую определить размеры всего экрана.
* Есть парная функция установки рабочей области - подфункция 6.
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_SCREEN_AREA (5)
======================================================================
==== Функция 48, подфункция 6 - установить рабочую область экрана. ===
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 6 - номер подфункции
* ecx = [left]*65536 + [right]
* edx = [top]*65536 + [bottom]
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Рабочая область экрана определяет положение и координаты
максимизированного окна.
* Эта функция используется только приложением @taskbar,
устанавливающим рабочей областью весь экран за вычетом панели.
* (left,top) - координаты левого верхнего угла,
(right,bottom) - координаты правого нижнего.
Таким образом, размер рабочей области по оси x определяется
формулой right-left+1, по оси y - формулой bottom-right+1.
* Если left>=right, то x-координаты рабочей области не изменяются.
Если left<0, то left не устанавливается. Если right больше
или равно ширины экрана, то right не устанавливается.
Аналогично по оси y.
* Смотри также функцию 14,
позволяющую определить размеры всего экрана.
* Есть парная функция получения рабочей области -
подфункция 5.
* Эта функция автоматически перерисовывает экран, по ходу дела
обновляет координаты и размеры максимизированных окон.
Все окна извещаются о необходимости перерисовки (событие 1).
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_SCREEN_AREA (6)
======================================================================
====================== Функция 48, подфункция 7 ======================
============ Получить область скина для текста заголовка. ============
======================================================================
Возвращает область заголовка окна со скином, предназначенную
для вывода текста заголовка.
Параметры:
* eax = 48 - номер функции
* ebx = 7 - номер подфункции
Возвращаемое значение:
* eax = [left]*65536 + [right]
* ebx = [top]*65536 + [bottom]
Замечания:
* Использование/неиспользование этой функции -
личное дело приложения.
* Рекомендуется учитывать значения, возвращаемые этой функцией,
при выборе места для рисования текста заголовка (функцией 4) или
какого-нибудь заменителя текста заголовка
(по усмотрению приложения).
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_SKIN_MARGINS (7)
======================================================================
==== Функция 48, подфункция 8 - установить используемый скин окон. ===
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 8 - номер подфункции
* ecx = указатель на имя файла скина
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - не удалось загрузить файл
* eax = 2 - файл не является файлом скина
Замечания:
* При успешной загрузке скина все окна извещаются о необходимости
перерисовки (событие 1).
* При загрузке система считывает скин из файла default.skn
на рамдиске.
* Пользователь может изменять скин статически, создав свой
default.skn, или динамически с помощью приложения desktop.
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_SKIN (8)
======================================================================
= Функция 48, подфункция 9 - получить настройку сглаживания шрифтов. =
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 9 - номер подфункции
Возвращаемое значение:
* eax = 2 - субпиксельное, 1 - обычное, 0 - выключить
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_FONT_SMOOTH (9)
======================================================================
===== Функция 48, подфункция 10 - настроить сглаживание шрифтов. =====
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 10 - номер подфункции
* cl = 2 - субпиксельное, 1 - обычное, 0 - выключить
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_FONT_SMOOTH (10)
======================================================================
======== Функция 48, подфункция 11 - получить размер шрифтов. ========
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 11 - номер подфункции
Возвращаемое значение:
* eax = текущая высота шрифта в пикселях
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_FONT_SIZE (11)
======================================================================
======= Функция 48, подфункция 12 - установить размер шрифтов. =======
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 12 - номер подфункции
* cl = новая высота шрифта в пикселях
 
---------------------- Константы для регистров: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_FONT_SIZE (12)
======================================================================
= Функция 48, подфункция 13 - установить скин с указанием кодировки. =
======================================================================
Параметры:
* eax = 48 - номер функции
* ebx = 13 - номер подфункции
* ecx = указатель на строку с путём к файлу скина
* edx = кодировка строки, подробности указаны в описании функции 80.
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - не удалось загрузить файл
* eax = 2 - файл не является файлом скина
Замечания:
* При успешной загрузке скина все окна извещаются о необходимости
перерисовки (событие 1).
* При загрузке система считывает скин из файла default.skn
на рамдиске.
* Пользователь может изменять скин статически, создав свой
default.skn, или динамически с помощью приложения desktop.
 
======================================================================
============ Функция 49 - Advanced Power Management (APM). ===========
======================================================================
Параметры:
* eax = 49 - номер функции
* dx = номер функции APM (аналог ax в спецификации)
* bx, cx = параметры функции APM
Возвращаемое значение:
* 16-битные регистры ax, bx, cx, dx, si, di и флаг CF
установлены в соответствии со спецификацией APM
* старшие половины 32-битных регистров eax, ebx, ecx,
edx, esi, edi разрушаются
Замечания:
* Спецификация APM 1.2 описывается в документе
"Advanced Power Management (APM) BIOS Specification"
(Revision 1.2), доступном на
http://www.microsoft.com/whdc/archive/amp_12.mspx;
кроме того, она включена в известный Interrupt List by Ralf Brown
(http://www.pobox.com/~ralf/files.html,
ftp://ftp.cs.cmu.edu/afs/cs/user/ralf/pub/).
 
---------------------- Константы для регистров: ----------------------
eax - SF_APM (49)
======================================================================
================= Функция 50 - установка формы окна. =================
======================================================================
Обычные окна представляют собой прямоугольники. С помощью этой функции
окну можно придать произвольную форму. Форма задаётся набором точек
внутри обрамляющего прямоугольника, принадлежащих окну. Положение и
размеры обрамляющего прямоугольника задаются функцией 0 и изменяются
функцией 67.
 
--------------- Установка данных с информацией о форме ---------------
Параметры:
* eax = 50 - номер функции
* ebx = 0 - номер подфункции
* ecx = указатель на данные формы (массив байт 0/1)
Возвращаемое значение:
* функция не возвращает значения
 
------------------ Установка масштаба данных формы -------------------
Параметры:
* eax = 50 - номер функции
* ebx = 1 - номер подфункции
* ecx задаёт масштаб: каждый байт данных определяет
(2^scale)*(2^scale) пикселей
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Масштаб по умолчанию равен 0 (масштабирующий множитель 1). Если в
данных формы один байт соответствует одному пикселю, то масштаб
можно не устанавливать.
* Обозначим xsize = ширина окна (в пикселях), ysize = высота;
обратите внимание, что они на единицу больше, чем устанавливаемые
функциями 0, 67.
* По определению масштаба xsize и ysize должны делиться на 2^scale.
* Байт данных по смещению a должен быть 0/1 и
определяет принадлежность окну квадрата со стороной 2^scale
(при scale=0 получаем пиксель) и координатами левого верхнего угла
(a mod (xsize shr scale), a div (xsize shr scale))
* Размер данных: (xsize shr scale)*(ysize shr scale).
* Данные должны присутствовать в памяти и не меняться
после установки формы.
* Система просматривает данные о форме при каждой перерисовке окна
функцией 0.
* Вызов подфункции 0 с нулевым указателем приводит к возврату
к прямоугольной форме.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SET_WINDOW_SHAPE (50)
======================================================================
===================== Функция 51 - создать поток. ====================
======================================================================
Параметры:
* eax = 51 - номер функции
* ebx = 1 - единственная подфункция
* ecx = адрес точки входа потока (начальный eip)
* edx = указатель стэка потока (начальный esp)
Возвращаемое значение:
* eax = -1 - ошибка (в системе слишком много потоков)
* иначе eax = TID - идентификатор потока
 
---------------------- Константы для регистров: ----------------------
eax - SF_CREATE_THREAD (51)
======================================================================
====================== Функция 54, подфункция 0 ======================
============== Узнать количество слотов в буфере обмена. =============
======================================================================
Параметры:
* eax = 54 - номер функции
* ebx = 0 - номер подфункции
Возвращаемое значение:
* eax = количество слотов в буфере
* eax = -1 - отсутствует область главного списка
 
---------------------- Константы для регистров: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_GET_SLOT_COUNT (0)
======================================================================
====================== Функция 54, подфункция 1 ======================
================== Считать данные из буфера обмена. ==================
======================================================================
Параметры:
* eax = 54 - номер функции
* ebx = 1 - номер подфункции
* eсx = номер слота
Возвращаемое значение:
* eax = если успешно - указатель на область памяти с данными
* eax = 1 - ошибка
* eax = -1 - отсутствует область главного списка
Замечания:
* буфер, на который указывает eax, содержит следующую информацию:
* +0: dword: общая длина данных
* +4: dword: определяет тип данныx:
* 0 = Текст
* 1 = Текст с блочным выделением
* 2 = Изображение
* 3 = RAW
* 4 и выше зарезервировано
* +8: более детально смотрите файл clipboard_container_rus.txt
* Функция должна использоваться совместно с 68.11. Приложение должно
предварительно проинициализировать локальную кучу вызовом 68.11.
---------------------- Константы для регистров: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_READ_CB (1)
======================================================================
====================== Функция 54, подфункция 2 ======================
================== Записать данные в буфер обмена. ===================
======================================================================
Параметры:
* eax = 54 - номер функции
* ebx = 2 - номер подфункции
* eсx = количество копируемых байт
* edx = указатель на буфер под копируемые данные
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - ошибка
* eax = -1 - отсутствует область главного списка
 
---------------------- Константы для регистров: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_WRITE_CB (2)
======================================================================
====================== Функция 54, подфункция 3 ======================
========= Удалить последний слот с данными в буфере обмена ===========
======================================================================
Параметры:
* eax = 54 - номер функции
* ebx = 3 - номер подфункции
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - ошибка
* eax = -1 - отсутствует область главного списка
 
---------------------- Константы для регистров: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_DEL_SLOT (3)
======================================================================
====================== Функция 54, подфункция 4 ======================
=================== Аварийный сброс блокировки буфера ================
======================================================================
Параметры:
* eax = 54 - номер функции
* ebx = 4 - номер подфункции
Возвращаемое значение:
* eax = 0 - успешно
* eax = -1 - отсутствует область главного списка или нет блокировки
Замечания:
* Используется в исключительных случаях, когда зависшее или убитое
приложение заблокировало работу с буфером обмена.
 
---------------------- Константы для регистров: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_UNLOCK_BUFFER (4)
======================================================================
====================== Функция 55, подфункция 55 =====================
========== Начать проигрывать данные на встроенном спикере. ==========
======================================================================
Параметры:
* eax = 55 - номер функции
* ebx = 55 - номер подфункции
* esi = указатель на данные
Возвращаемое значение:
* eax = 0 - успешно
* eax = 55 - ошибка (спикер отключён или занят)
Данные - это массив элементов переменной длины.
Формат каждого элемента определяется первым байтом:
* 0 = конец данных
* 1..0x80 = задаёт длительность звучания в сотых долях секунды
ноты, определяемой непосредственным значением частоты
* следующее слово (2 байта) содержит делитель частоты;
частота определяется как 1193180/divider
* 0x81 = invalid
* 0x82..0xFF = нота, определяемая октавой и номером:
* длительность в сотых долях секунды = (первый байт)-0x81
* присутствует ещё один байт;
* (второй байт)=0xFF - пауза
* иначе он имеет вид a*0x10+b, где b=номер ноты в октаве от 1
до 12, a=номер октавы (считая с 0)
Замечания:
* Пищание спикером может быть запрещено/разрешено подфункцией 8
функции 18.
* Функция возвращает управление, сообщив куда следует информацию
о запросе. Само проигрывание идёт независимо от программы.
* Данные должны сохраняться в памяти по крайней мере
до конца проигрывания.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SPEAKER_PLAY (55)
======================================================================
======================= Функция 57 - PCI BIOS. =======================
======================================================================
Параметры:
* eax = 57 - номер функции
* ebp соответствует регистру al в спецификации PCI BIOS
* остальные регистры - по спецификации PCI BIOS
Возвращаемое значение:
* CF не определён
* остальные регистры - по спецификации PCI BIOS
Замечания:
* Многих результатов этой функции можно также добиться вызовом
соответствующих подфункций функции 62.
* Функция вызывает расширение PCI32 BIOS, документированное,
например, в http://alpha1.dyns.net/files/PCI/bios21.pdf.
* Если BIOS не поддерживает это расширение, поведение функции
эмулируется (через аналоги подфункций функции 62 режима ядра).
 
---------------------- Константы для регистров: ----------------------
eax - SF_PCI_BIOS (57)
======================================================================
=========== Функция 60 - Inter Process Communication (IPC). ==========
======================================================================
IPC применяется для посылок сообщений от одного процесса/потока
другому. При этом следует предварительно договориться о том, как
интерпретировать конкретное сообщение.
 
-------- Подфункция 1 - установить область для получения IPC ---------
Вызывается процессом-приёмником.
Параметры:
* eax = 60 - номер функции
* ebx = 1 - номер подфункции
* ecx = указатель на буфер
* edx = размер буфера
Возвращаемое значение:
* eax = 0 - всегда успешно
Формат IPC-буфера:
* +0: dword: если здесь не 0, то буфер считается заблокированным;
блокируйте/разблокируйте буфер, когда вы с ним активно работаете
и вам надо, чтобы извне не изменялись данные буфера
(не поступали новые сообщения)
* +4: dword: занято места в буфере (в байтах)
* +8: первое сообщение
* +8+n: второе сообщение
* ...
Формат сообщения:
* +0: dword: PID процесса/потока, пославшего сообщение
* +4: dword: длина сообщения (не считая этот заголовок)
* +8: n*byte: данные сообщения
 
--------------- Подфункция 2 - послать сообщение IPC. ----------------
Вызывается процессом-инициатором.
Параметры:
* eax = 60 - номер функции
* ebx = 2 - номер подфункции
* ecx = PID приёмника
* edx = указатель на данные сообщения
* esi = длина сообщения (в байтах)
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - приёмник не определил буфер для IPC-сообщений
(может быть, ещё не успел, а может быть, это не тот поток,
который нужен)
* eax = 2 - приёмник заблокировал IPC-буфер;
попробуйте немного подождать
* eax = 3 - переполнение IPC-буфера приёмника
* eax = 4 - процесса/потока с таким PID не существует
Замечания:
* Система сразу после записи IPC-сообщения в буфер посылает
потоку-приёмнику событие с кодом 7 (см. коды событий).
 
---------------------- Константы для регистров: ----------------------
eax - SF_IPC (60)
ebx - SSF_SET_AREA (1), SSF_SEND_MESSAGE (2)
======================================================================
=== Функция 61 - получить параметры для прямого доступа к графике. ===
======================================================================
Программе доступны данные графического экрана (область памяти, которая
собственно и отображает содержимое экрана) напрямую без вызовов
системных функций через селектор gs:
mov eax, [gs:0]
поместит в eax первый dword буфера, содержащий информацию о цвете
левой верхней точки (и, возможно, цвета нескольких следующих).
mov [gs:0], eax
при работе в режимах VESA c LFB
установит цвет левой верхней точки
(и возможно, цвета нескольких следующих).
Для интерпретации данных графического экрана требуется знание
некоторых параметров, которые возвращаются этой функцией.
Замечания:
* Параметры графики очень редко меняются при работе системы.
* При изменении видеорежима система перерисовывает все окна
(событие с кодом 1) и перерисовывает фон (событие 5).
Эти же события происходят и в других случаях,
которые встречаются значительно чаще, чем изменение видеорежима.
* При работе в видеорежимах с LFB селектор gs указывает на
собственно LFB, так что чтение/запись по gs приводят
непосредственно к изменению содержимого экрана. При работе в
видеорежимах без LFB gs указывает на некоторую область данных
ядра, причём все функции вывода на экран добросовестно выполняют
двойную работу по записи непосредственно на экран и по записи
в этот буфер. В результате при чтении содержимого этого буфера
результаты соответствуют содержимому экрана
(с, вообще говоря, большим цветовым разрешением),
а запись игнорируется.
Исключением является режим 320*200, для которого в главном цикле
системного потока выполняется обновление экрана в соответствии
с движениями курсора мыши.
 
------------------------- Разрешение экрана --------------------------
Параметры:
* eax = 61 - номер функции
* ebx = 1 - номер подфункции
Возвращаемое значение:
* eax = [разрешение по оси x]*65536 + [разрешение по оси y]
Замечания:
* Можно использовать функцию 14 с учётом того, что она возвращает
размеры на 1 меньше. Это полностью эквивалентный способ.
 
------------------------ Число бит на пиксель ------------------------
Параметры:
* eax = 61 - номер функции
* ebx = 2 - номер подфункции
Возвращаемое значение:
* eax = число бит на пиксель (24 или 32)
 
------------------------ Число байт на строку ------------------------
Параметры:
* eax = 61 - номер функции
* ebx = 3 - номер подфункции
Возвращаемое значение:
* eax = число байт, которое занимает одна строка развёртки
(горизонтальная линия на экране)
 
---------------------- Константы для регистров: ----------------------
eax - SF_GET_GRAPHICAL_PARAMS (61)
ebx - SSF_SCREEN_SIZE (1), SSF_BITS_PER_PIXEL (2),
SSF_BYTES_PER_LINE (3)
======================================================================
===== Функция 62, подфункция 0 - получить версию PCI-интерфейса. =====
======================================================================
Параметры:
* eax = 62 - номер функции
* bl = 0 - номер подфункции
Возвращаемое значение:
* eax = -1 - доступ к PCI запрещён; иначе
* ah.al = версия PCI-интерфейса (ah=версия, al=подверсия)
* старшее слово eax обнулено
Замечания:
* Предварительно должен быть разрешён низкоуровневый доступ к PCI
для приложений подфункцией 12 функции 21.
* Если PCI BIOS не поддерживается, то значение ax неопределено.
 
---------------------- Константы для регистров: ----------------------
eax - SF_PCI (62)
ebx - SSF_GET_VERSION (0)
======================================================================
==== Функция 62, подфункция 1 - получить номер последней PCI-шины. ===
======================================================================
Параметры:
* eax = 62 - номер функции
* bl = 1 - номер подфункции
Возвращаемое значение:
* eax = -1 - доступ к PCI запрещён; иначе
* al = номер последней PCI-шины; оставшиеся байты eax разрушаются
Замечания:
* Предварительно должен быть разрешён низкоуровневый доступ к PCI
для приложений подфункцией 12 функции 21.
* Если PCI BIOS не поддерживается, то значение al неопределено.
 
---------------------- Константы для регистров: ----------------------
eax - SF_PCI (62)
ebx - SSF_GET_LAST_BUS (1)
======================================================================
====================== Функция 62, подфункция 2 ======================
== Получить механизм обращения к конфигурационному пространству PCI. =
======================================================================
Параметры:
* eax = 62 - номер функции
* bl = 2 - номер подфункции
Возвращаемое значение:
* eax = -1 - доступ к PCI запрещён; иначе
* al = механизм (1 или 2); прочие байты eax разрушаются
Замечания:
* Предварительно должен быть разрешён низкоуровневый доступ к PCI
для приложений подфункцией 12 функции 21.
* Механизм обращения выбирается в соответствии
с характеристиками оборудования.
* Подфункции чтения и записи автоматически работают
с выбранным механизмом.
 
---------------------- Константы для регистров: ----------------------
eax - SF_PCI (62)
ebx - SSF_GET_ADRR_MODE (2)
======================================================================
======== Функция 62, подфункции 4,5,6 - прочитать PCI-регистр. =======
======================================================================
Параметры:
* eax = 62 - номер функции
* bl = 4 - читать байт
* bl = 5 - читать слово
* bl = 6 - читать двойное слово
* bh = номер PCI-шины
* ch = dddddfff, где ddddd = номер устройства на шине,
fff = номер функции устройства
* cl = номер регистра (должен быть чётным для bl=5,
делиться на 4 для bl=6)
Возвращаемое значение:
* eax = -1 - ошибка (запрещён доступ к PCI или
неподдерживаемые параметры); иначе
* al/ax/eax (в зависимости от запрошенного размера) содержит данные;
оставшаяся часть регистра eax разрушается
Замечания:
* Предварительно должен быть разрешён низкоуровневый доступ к PCI
для приложений подфункцией 12 функции 21.
* Механизм доступа 2 поддерживает только 16 устройств на шине и
игнорирует номер функции. Получить механизм доступа можно вызовом
подфункции 2.
* Некоторые регистры стандартны и существуют для всех устройств,
некоторые определяются конкретным устройством. Список первых
входит, например, в известный Interrupt List by Ralf Brown
(http://www.pobox.com/~ralf/files.html,
ftp://ftp.cs.cmu.edu/afs/cs/user/ralf/pub/);
список вторых должен быть указан в документации по устройству.
 
---------------------- Константы для регистров: ----------------------
eax - SF_PCI (62)
ebx - SSF_READ_BYTE (4), SSF_READ_WORD (5), SSF_READ_DWORD (6)
======================================================================
======= Функция 62, подфункции 8,9,10 - записать в PCI-регистр. ======
======================================================================
Параметры:
* eax = 62 - номер функции
* bl = 8 - писать байт
* bl = 9 - писать слово
* bl = 10 - писать двойное слово
* bh = номер PCI-шины
* ch = dddddfff, где ddddd = номер устройства на шине,
fff = номер функции устройства
* cl = номер регистра (должен быть чётным для bl=9,
делиться на 4 для bl=10)
* dl/dx/edx (в зависимости от запрошенного размера) содержит
данные для записи
Возвращаемое значение:
* eax = -1 - ошибка (запрещён доступ к PCI или
неподдерживаемые параметры)
* eax = 0 - успешно
Замечания:
* Предварительно должен быть разрешён низкоуровневый доступ к PCI
для приложений подфункцией 12 функции 21.
* Механизм доступа 2 поддерживает только 16 устройств на шине и
игнорирует номер функции. Получить механизм доступа можно вызовом
подфункции 2.
* Некоторые регистры стандартны и существуют для всех устройств,
некоторые определяются конкретным устройством. Список первых
входит, например, в известный Interrupt List by Ralf Brown;
список вторых должен быть указан в документации по устройству.
 
---------------------- Константы для регистров: ----------------------
eax - SF_PCI (62)
ebx - SSF_WRITE_BYTE (8), SSF_WRITE_WORD (9), SSF_WRITE_DWORD (10)
======================================================================
================ Функция 63 - работа с доской отладки. ===============
======================================================================
Доска отладки представляет собой системный буфер (на 4096 байт),
в который любая программа может записать (вообще говоря, произвольные)
данные и из которого другая программа может эти данные прочитать.
Есть соглашение, в соответствии с которым записываемые данные -
текстовые строки, интерпретируемые как отладочные сообщения о ходе
выполнения программы. Ядро в определённых ситуациях также записывает
на доску отладки сведения о выполнении некоторых функций;
по соглашению сообщения ядра начинаются с префикса "K : ".
Для просмотра доски отладки создано приложение board,
которое считывает данные из буфера и отображает их в своём окне. board
понимает последовательность кодов 13,10 как переход на новую строку.
Символ с нулевым кодом в конце строки не обязателен, но и не мешает.
В связи с появлением отладчика ценность доски отладки несколько
снизилась, поскольку отладчик позволяет полностью контролировать ход
выполнения программы, причём для этого не требуется никаких усилий
со стороны самой программы. Тем не менее во многих случаях
доска отладки продолжает оставаться полезной.
 
---------------------------- Запись байта ----------------------------
Параметры:
* eax = 63 - номер функции
* ebx = 1 - номер подфункции
* cl = байт данных
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Байт записывается в буфер. Длина буфера - 512 байт.
При переполнении буфера все полученные данные теряются
и заполнение начинается снова с нуля.
* Для вывода на доску отладки более сложных объектов (строк, чисел)
достаточно этой функции, вызываемой в цикле. Можно не писать
вручную соответствующий код, а воспользоваться файлом debug.inc,
входящим в дистрибутив.
 
---------------------------- Чтение байта ----------------------------
Забирает байт из буфера.
Параметры:
* eax = 63 - номер функции
* ebx = 2 - номер подфункции
Возвращаемое значение:
* eax = ebx = 0 - буфер пуст
* eax = байт, ebx = 1 - байт успешно прочитан
 
---------------------- Константы для регистров: ----------------------
eax - SF_BOARD (63)
ebx - SSF_DEBUG_WRITE (1), SSF_DEBUG_READ (2)
======================================================================
========== Функция 64 - перераспределить память приложения. ==========
======================================================================
Параметры:
* eax = 64 - номер функции
* ebx = 1 - единственная подфункция
* ecx = новый размер памяти
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - недостаточно памяти
Замечания:
* Есть другой способ выделения/освобождения динамической памяти -
подфункции 11, 12, 13 функции 68.
* Функция не может использоваться совместно с 68.11, 68.12, 68.13.
Вызов функции будет игнорироваться, если приложение создаст
локальную кучу вызовом 68.11.
 
---------------------- Константы для регистров: ----------------------
eax - SF_MEMORY_RESIZE (64)
======================================================================
========= Функция 65 - вывести изображение с палитрой в окно. ========
======================================================================
Параметры:
* eax = 65 - номер функции
* ebx = указатель на изображение
* ecx = [размер по оси x]*65536 + [размер по оси y]
* edx = [координата по оси x]*65536 + [координата по оси y]
* esi = число бит на пиксель, должно быть 1,2,4,8,9,15,16,24 или 32
* edi = указатель на палитру (2 в степени esi цветов 0x00RRGGBB);
игнорируется при esi > 8
* ebp = смещение данных каждой следующей строки изображения
относительно предыдущей
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Координаты изображения - это координаты верхнего левого угла
изображения относительно окна.
* Формат изображения с 1 битом на пиксель: каждый байт изображения,
за исключением, быть может, последних байтов строк, содержит
информацию о цвете 8 пикселей, старший бит соответствует первому
пикселю.
* Формат изображения с 2 битами на пиксель: каждый байт изображения,
за исключением, быть может, последних байтов строк, содержит
информацию о цвете 4 пикселей, старшие два бита соответствуют
первому пикселю.
* Формат изображения с 4 битами на пиксель: каждый байт изображения,
за исключением последних байтов строк (если ширина изображения
нечётна), содержит информацию о цвете 2 пикселей, старшая тетрада
соответствует первому пикселю.
* Формат изображения с 8 битами на пиксель: каждый байт изображения
рассматривается как индекс в палитре.
* Формат изображения с 9 битами на пиксель: каждый байт изображения
(8 бит) обозначает интенсивность серого для одного пикселя, т.о.
этот тип изображения идентичен 8 бит на пиксель без палитры.
* Формат изображения с 15 битами на пиксель: цвет каждого пикселя
кодируется как (в битовом представлении) 0RRRRRGGGGGBBBBB -
по 5 пикселей на каждый цвет.
* Формат изображения с 16 битами на пиксель: цвет каждого пикселя
кодируется как RRRRRGGGGGGBBBBB (схема 5+6+5).
* Формат изображения с 24 битами на пиксель: цвет каждого пикселя
кодируется тремя байтами - последовательно синяя, зелёная, красная
составляющие цвета.
* Формат изображения с 32 битами на пиксель: аналогично 24, только
есть ещё игнорируемый четвёртый байт.
* Вызов функции 7 эквивалентен вызову этой функции с параметрами
esi=24, ebp=0.
 
---------------------- Константы для регистров: ----------------------
eax - SF_PUT_IMAGE_EXT (65)
======================================================================
================= Функция 66 - работа с клавиатурой. =================
======================================================================
Режим ввода влияет на результаты чтения клавиш функцией 2.
При загрузке программы для неё устанавливается ASCII-режим ввода.
 
-------- Подфункция 1 - установить режим ввода с клавиатуры. ---------
Параметры:
* eax = 66 - номер функции
* ebx = 1 - номер подфункции
* ecx = режим:
* 0 = обычный (ASCII-символы)
* 1 = сканкоды
Возвращаемое значение:
* функция не возвращает значения
 
--------- Подфункция 2 - получить режим ввода с клавиатуры. ----------
Параметры:
* eax = 66 - номер функции
* ebx = 2 - номер подфункции
Возвращаемое значение:
* eax = текущий режим
 
------- Подфункция 3 - получить состояние управляющих клавиш. --------
Параметры:
* eax = 66 - номер функции
* ebx = 3 - номер подфункции
Возвращаемое значение:
* eax = битовая маска:
* бит 0 (маска 1): левый Shift нажат
* бит 1 (маска 2): правый Shift нажат
* бит 2 (маска 4): левый Ctrl нажат
* бит 3 (маска 8): правый Ctrl нажат
* бит 4 (маска 0x10): левый Alt нажат
* бит 5 (маска 0x20): правый Alt нажат
* бит 6 (маска 0x40): CapsLock включён
* бит 7 (маска 0x80): NumLock включён
* бит 8 (маска 0x100): ScrollLock включён
* бит 9 (маска 0x200): левый Win нажат
* бит 10 (маска 0x400): правый Win нажат
* прочие биты сброшены
 
----- Подфункция 4 - установить общесистемную "горячую клавишу". -----
О нажатии "горячей клавиши" извещаются только приложения,
установившие её; активное приложение (к которому поступает
весь нормальный ввод) таких клавиш не получает.
Извещение заключается в посылке события с кодом 2.
Прочитать "горячую клавишу" можно так же, как и обычную, -
функцией 2.
Параметры:
* eax = 66 - номер функции
* ebx = 4 - номер подфункции
* cl задаёт сканкод клавиши;
используйте cl=0 для задания комбинаций типа Ctrl+Shift
* edx = 0xXYZ задаёт возможные состояния управляющих клавиш:
* Z (младшие 4 бита) задаёт состояние клавиш LShift и RShift:
* 0 = ни одна из клавиш не должна быть нажата;
* 1 = ровно одна из клавиш должна быть нажата;
* 2 = обе клавиши должны быть нажаты;
* 3 = должна быть нажата LShift, но не RShift;
* 4 = должна быть нажата RShift, но не LShift
* Y - аналогично для LCtrl и RCtrl;
* X - аналогично для LAlt и RAlt
Возвращаемое значение:
* eax=0 - успешно
* eax=1 - слишком много "горячих клавиш" (допускается максимум 256)
Замечания:
* Горячая клавиша может срабатывать либо при нажатии,
либо при отпускании. Сканкод отпускания клавиши на 128 больше,
чем сканкод нажатия (т.е. установлен старший бит).
* Несколько приложений могут установить одну и ту же комбинацию;
о нажатии такой комбинации будут извещаться все такие приложения.
 
------ Подфункция 5 - удалить установленную "горячую клавишу". -------
Параметры:
* eax = 66 - номер функции
* ebx = 5 - номер подфункции
* cl = сканкод клавиши и edx = 0xXYZ такие же, как и в подфункции 4
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - нет такой горячей клавиши
Замечания:
* При завершении процесса/потока удаляются все установленные им
горячие клавиши.
* Вызов функции не влияет на другие приложения.
Если другое приложение определило эту же комбинацию,
оно по-прежнему будет получать уведомления.
 
------------- Подфункция 6 - заблокировать обычный ввод. -------------
Параметры:
* eax = 66 - номер функции
* ebx = 6 - номер подфункции
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Блокируется обычный ввод данных с клавиатуры для установленных
"горячих" клавиш
* Для эмуляции мыши через клавиатуру, приложение MOUSEMUL
 
--------- Подфункция 7 - разблокировать обычный ввод. ----------------
Параметры:
* eax = 66 - номер функции
* ebx = 7 - номер подфункции
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Разблокирование результатов ф. 66.6
* Для эмуляции мыши через клавиатуру, приложение MOUSEMUL
 
---------------------- Константы для регистров: ----------------------
eax - SF_KEYBOARD (66)
ebx - SSF_SET_INPUT_MODE (1), SSF_GET_INPUT_MODE (2),
SSF_GET_CONTROL_KEYS (3), SSF_SET_SYS_HOTKEY (4),
SSF_DEL_SYS_HOTKEY (5), SSF_LOCK_INPUT (6), SSF_UNLOCK_INPUT (7)
======================================================================
============ Функция 67 - изменить положение/размеры окна. ===========
======================================================================
Параметры:
* eax = 67 - номер функции
* ebx = новая x-координата окна
* ecx = новая y-координата окна
* edx = новый x-размер окна
* esi = новый y-размер окна
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Значение -1 для параметра означает "не изменять"; например, для
перемещения окна без изменения размеров можно указать edx=esi=-1.
* Предварительно окно должно быть определено функцией 0.
Она же задаёт начальные координаты и размеры окна.
* Размеры окна понимаются в смысле функции 0, т.е.
на один пиксель меньше, чем реальные размеры.
* Вызов функции для максимизированных окон просто игнорируется.
* Для окон соответствующих стилей положение и/или размеры могут быть
изменены пользователем; текущие положение и размеры могут быть
получены вызовом функции 9.
* Функция посылает окну событие перерисовки (с кодом 1).
 
---------------------- Константы для регистров: ----------------------
eax - SF_CHANGE_WINDOW (67)
======================================================================
=== Функция 68, подфункция 0 - получить счётчик переключений задач. ==
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 0 - номер подфункции
Возвращаемое значение:
* eax = число переключений задач с момента загрузки системы
(по модулю 2^32)
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_GET_TASK_SWITCH_COUNT (0)
======================================================================
====================== Функция 68, подфункция 1 ======================
============ Переключиться на следующий поток выполнения. ============
======================================================================
Функция завершает текущий квант времени, выделенный потоку,
и переключается на следующий.
(Какой поток какого процесса будет следующим, предсказать нельзя).
Позднее, когда до текущего потока дойдёт очередь,
выполнение возобновится.
Параметры:
* eax = 68 - номер функции
* ebx = 1 - номер подфункции
Возвращаемое значение:
* функция не возвращает значения
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_SWITCH_TASK (1)
======================================================================
=============== Функция 68, подфункция 2 - кэш + rdpmc. ==============
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 2 - номер подфункции
* ecx = требуемое действие:
* ecx = 0 - разрешить выполнение инструкции rdpmc
(ReaD Performance-Monitoring Counters)
* ecx = 1 - узнать, включён/выключен кэш
* ecx = 2 - включить кэш
* ecx = 3 - выключить кэш
Возвращаемое значение:
* для ecx=0:
* eax = значение cr4
* для ecx=1:
* eax = (cr0 and 0x60000000):
* eax = 0 - кэш включён
* eax <> 0 - кэш выключен
* для ecx=2 и ecx=3:
* функция не возвращает значения
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_PERFORMANCE (2)
ecx - SSSF_ALLOW_RDPMC (0), SSSF_CACHE_STATUS (1),
SSSF_CACHE_ON (2), SSSF_CACHE_OFF (3)
======================================================================
========== Функция 68, подфункция 3 - прочитать MSR-регистр. =========
======================================================================
MSR = Model Specific Register; полный список MSR-регистров процессора
содержится в документации по процессору (например, IA-32 Intel
Architecture Software Developer's Manual, Volume 3, Appendix B);
каждое семейство процессоров имеет своё подмножество MSR-регистров.
Параметры:
* eax = 68 - номер функции
* ebx = 3 - номер подфункции
* ecx игнорируется
* edx = адрес MSR
Возвращаемое значение:
* ebx:eax = старший:младший dword результата
Замечания:
* Указание в ecx несуществующего или нереализованного для данного
процессора MSR повлечёт исключение в ядре, которое прибьёт поток.
* Предварительно следует определить, поддерживаются ли MSR в целом,
командой cpuid. Иначе возникнет уже другое исключение в ядре,
которое всё равно прибьёт поток.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_READ_MSR (3)
======================================================================
========= Функция 68, подфункция 4 - записать в MSR-регистр. =========
======================================================================
MSR = Model Specific Register; полный список MSR-регистров процессора
содержится в документации по процессору (например, IA-32 Intel
Architecture Software Developer's Manual, Volume 3, Appendix B);
каждое семейство процессоров имеет своё подмножество MSR-регистров.
Параметры:
* eax = 68 - номер функции
* ebx = 4 - номер подфункции
* ecx игнорируется
* edx = адрес MSR
* esi:edi = старший:младший dword
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Указание в ecx несуществующего или нереализованного для данного
процессора MSR повлечёт исключение в ядре, которое прибьёт поток.
* Предварительно следует определить, поддерживаются ли MSR в целом,
командой cpuid. Иначе возникнет уже другое исключение в ядре,
которое всё равно прибьёт поток.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_WRITE_MSR (4)
======================================================================
===== Функция 68, подфункция 11 - инициализировать кучу процесса. ====
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 11 - номер подфункции
Возвращаемое значение:
* eax = 0 - неуспех
* иначе размер созданной кучи
Замечания:
* Вызов функции инициализирует кучу, из которой впоследствии можно
выделять и освобождать блоки памяти подфункциями 12, 13 и 20.
* Если куча уже создана, функция вернёт размер существующей кучи.
Размер кучи равен размеру всей свободной памяти приложения.
* После создания кучи вызовы функции 64 игнорируются.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_HEAP_INIT (11)
======================================================================
========== Функция 68, подфункция 12 - выделить блок памяти. =========
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 12 - номер подфункции
* ecx = требуемый размер в байтах
Возвращаемое значение:
* eax = указатель на выделенный блок
Замечания:
* Функция выделяет целое число страниц (4 Кб) так, что фактический
размер выделенного блока больше или равен запрошенному.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_ALLOC (12)
======================================================================
========= Функция 68, подфункция 13 - освободить блок памяти. ========
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 13 - номер подфункции
* ecx = указатель на блок памяти
Возвращаемое значение:
* eax = 1 - успешно
* eax = 0 - неудача
Замечания:
* Блок памяти должен быть ранее выделен подфункцией 12
или подфункцией 20.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_FREE (13)
======================================================================
====================== Функция 68, подфункция 14 =====================
====== Ожидать получения сигнала от других приложений/драйверов. =====
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 14 - номер подфункции
* ecx = указатель на буфер для информации (24 байта)
Возвращаемое значение:
* eax разрушается
* буфер, на который указывает ecx, содержит следующую информацию:
* +0: dword: идентификатор последующих данных сигнала
* +4: данные принятого сигнала (20 байт), формат которых
определяется первым dword-ом
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_WAIT_SIGNAL (14)
======================================================================
=========== Функция 68, подфункция 16 - загрузить драйвер. ===========
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 16 - номер подфункции
* ecx = указатель на ASCIIZ-строку с именем драйвера
Возвращаемое значение:
* eax = 0 - неудача
* иначе eax = хэндл драйвера
Замечания:
* Если драйвер ещё не загружен, он загружается;
если драйвер уже загружен, ничего не меняется.
* Имя драйвера чувствительно к регистру символов.
Максимальная длина имени - 16 символов, включая завершающий
нулевой символ, остальные символы игнорируются.
* Драйвер с именем ABC загружается из файла /rd/1/drivers/ABC.sys.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_LOAD_DRIVER (16)
======================================================================
========== Функция 68, подфункция 17 - управление драйвером. =========
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 17 - номер подфункции
* ecx = указатель на управляющую структуру:
* +0: dword: хэндл драйвера
* +4: dword: код функции драйвера
* +8: dword: указатель на входные данные
* +12 = +0xC: dword: размер входных данных
* +16 = +0x10: dword: указатель на выходные данные
* +20 = +0x14: dword: размер выходных данных
Возвращаемое значение:
* eax = определяется драйвером
Замечания:
* Коды функций и структура входных/выходных данных
определяются драйвером.
* Предварительно должен быть получен хэндл драйвера подфункцией 16.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_CONTROL_DRIVER (17)
======================================================================
== Функция 68, подфункция 18 - загрузить DLL с указанием кодировки. ==
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 18 - номер подфункции
* ecx = указатель на строку с путём к DLL
* edx = кодировка строки, подробности указаны в описании функции 80.
Возвращаемое значение:
* eax = 0 - неудача
* иначе eax = указатель на таблицу экспорта DLL
Замечания:
* Таблица экспорта представляет собой массив структур по 2 dword'а,
заканчивающийся нулём. Первый dword в структуре является
указателем на имя функции, второй содержит адрес функции.
 
======================================================================
============= Функция 68, подфункция 19 - загрузить DLL. =============
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 19 - номер подфункции
* ecx = указатель на строку с путём к DLL,
правила формирования строки указаны в описании функции 70.
Возвращаемое значение:
* eax = 0 - неудача
* иначе eax = указатель на таблицу экспорта DLL
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_LOAD_DLL (19)
======================================================================
====== Функция 68, подфункция 20 - перераспределить блок памяти. =====
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 20 - номер подфункции
* ecx = новый размер в байтах
* edx = указатель на уже выделенный блок памяти
Возвращаемое значение:
* eax = указатель на перераспределённый блок, 0 при ошибке
Замечания:
* Предварительно следует инициализировать кучу процесса вызовом
подфункции 11.
* Функция выделяет целое число страниц (4 Кб) так, что фактический
размер выделенного блока больше или равен запрошенному.
* Если edx=0, то вызов функции эквивалентен выделению памяти
подфункцией 12. В противном случае блок памяти по адресу edx
должен быть ранее выделен подфункцией 12 или
описываемой подфункцией.
* Если ecx=0, то функция освобождает блок памяти по адресу edx и
возвращает 0.
* Содержимое памяти вплоть до наименьшего из старого и нового
размеров сохраняется.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_REALLOC (20)
======================================================================
========= Функция 68, подфункция 21 - загрузить драйвер PE. ==========
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 21 - номер подфункции
* ecx = указатель на ASCIIZ-строку с именем драйвера
* edx = указатель на командную строку
Возвращаемое значение:
* eax = 0 - неудача
* иначе eax = хэндл драйвера
Замечания:
* Если драйвер ещё не загружен, он загружается;
если драйвер уже загружен, ничего не меняется.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_LOAD_DRIVER_PE (21)
======================================================================
=== Функция 68, подфункция 22 - открыть именованную область памяти. ==
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 22 - номер подфункции
* ecx = имя области. Максимум 31 символ, включая завершающий ноль
* edx = размер области в байтах для SHM_CREATE и SHM_OPEN_ALWAYS
* esi = флаги открытия и доступа:
* SHM_OPEN = 0x00 - открыть существующую область памяти.
Если область с таким именем не существует,
функция вернёт код ошибки 5.
* SHM_OPEN_ALWAYS = 0x04 - открыть существующую или создать новую
область памяти.
* SHM_CREATE = 0x08 - создать новую область памяти.
Если область с таким именем уже существует,
функция вернёт код ошибки 10.
* SHM_READ = 0x00 - доступ только на чтение
* SHM_WRITE = 0x01 - доступ на чтение и запись
Возвращаемое значение:
* eax = указатель на область памяти, 0 при ошибке
* при создании новой области (SHM_CREATE или SHM_OPEN_ALWAYS):
edx = 0 - успех, иначе - код ошибки
* при открытии существующей области (SHM_OPEN или SHM_OPEN_ALWAYS):
edx = код ошибки (при eax=0) или размер области в байтах
Коды ошибок:
* E_NOTFOUND = 5
* E_ACCESS = 10
* E_NOMEM = 30
* E_PARAM = 33
Замечания:
* Предварительно следует инициализировать кучу процесса вызовом
подфункции 11.
* Если создаётся новая область, то флаги доступа устанавливают
максимальные права доступа для остальных процессов. Попытка
открытия другим потоком с неразрешёнными правами провалится
с кодом ошибки E_ACCESS.
* Процесс, создавший область, всегда имеет доступ на запись.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_OPEN (22)
======================================================================
=== Функция 68, подфункция 23 - закрыть именованную область памяти. ==
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 23 - номер подфункции
* ecx = имя области. Максимум 31 символ, включая завершающий ноль
Возвращаемое значение:
* eax разрушается
Замечания:
* Область памяти физически освобождается (с забыванием всех данных
и высвобождением физической памяти), когда её закроют
все открывшие потоки.
* При завершении потока освобождаются все открытые им
области памяти.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_CLOSE (23)
======================================================================
==== Функция 68, подфункция 24 - установить обработчик исключений. ===
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 24 - номер подфункции
* ecx = адрес нового обработчика исключений
* edx = маска обрабатываемых исключений
Возвращаемое значение:
* eax = адрес старого обработчика исключений (0, если не установлен)
* ebx = маска старого обработчика исключений
Замечания:
* Номер бита в маске исключений соответствует номеру исключения по
спецификации на процессор (Intel-PC). Так, например, исключения
FPU имеют номер 16 (#MF), а SSE - 19 (#XF).
* В данной реализации игнорируется запрос на перехват исключения 7
- система обрабатывает #NM самостоятельно.
* Пользовательский обработчик получает номер исключения параметром
в стеке. Поэтому правильный выход из обработчика: RET 4. Возврат
при этом производится на команду, вызвавшую исключение.
* При передаче управления обработчику исключений сбрасывается
соответствующий бит в маске исключений. Возникновение этого же
исключения впоследствии приведёт к умолчальной обработке такового.
А именно: к завершению работы приложения в отсутствии отладчика,
приостановка с уведомлением отлаживающего приложения иначе.
* После завершения критических действий в обработчике пользователя
восстановление бита маски данного исключения можно сделать
подфункцией 25. Сброс флагов исключений в модулях FPU и XMM также
возлагается на обработчик пользователя.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_SET_EXCEPTION_HANDLER (24)
======================================================================
= Функция 68, подфункция 25 - изменить состояние активности сигнала. =
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 25 - номер подфункции
* ecx = номер сигнала
* edx = значение устанавливаемой активности (0/1)
Возвращаемое значение:
* eax = -1 - задан неверный номер сигнала
* иначе eax = старое значение активности сигнала (0/1)
Замечания:
* В текущей реализации изменяется только маска пользовательского
обработчика исключений, установленного подфункцией 24. При этом
номер сигнала соответствует номеру исключения.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_SET_EXCEPTION_STATE (25)
======================================================================
======= Функция 68, подфункция 26 - освободить страницы памяти =======
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 26 - номер подфункции
* ecx = указатель на блок памяти выделенный подфункцией 12
* edx = смещение от начала блока
* esi = размер высвобождаемого блока памяти, в байтах
Примечания:
* функция освобождает страницы с ecx+edx по ecx+edx+esi
и устанавливает виртуальную память в зарезервированное состояние.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_FREE_EXT (26)
======================================================================
============= Функция 68, подфункция 27 - загрузить файл =============
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 27 - номер подфункции
* ecx = указатель на строку с путём к файлу,
правила формирования строки указаны в описании функции 70.
Возвращаемое значение:
* eax = указатель на загруженный файл или 0
* edx = размер загруженного файла или 0
Примечания:
* функция загружает и, при необходимости, распаковывает файл (kunpack)
* Предварительно следует инициализировать кучу процесса вызовом
подфункции 11.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_LOAD_FILE (27)
======================================================================
== Функция 68, подфункция 28 - загрузить файл с указанием кодировки ==
======================================================================
Параметры:
* eax = 68 - номер функции
* ebx = 28 - номер подфункции
* ecx = указатель на строку с путём к файлу
* edx = кодировка строки, подробности указаны в описании функции 80.
Возвращаемое значение:
* eax = указатель на загруженный файл или 0
* edx = размер загруженного файла или 0
Примечания:
* функция загружает и, при необходимости, распаковывает файл (kunpack)
 
======================================================================
======================== Функция 69 - отладка. =======================
======================================================================
Процесс может загрузить другой процесс как отлаживаемый установкой
соответствующего бита при вызове подфункции 7 функции 70.
У процесса может быть только один отладчик; один процесс может
отлаживать несколько разных. Система уведомляет отладчик о событиях,
происходящих с отлаживаемым процессом. Сообщения записываются в буфер,
определённый подфункцией 0.
Формат сообщения:
* +0: dword: код сообщения
* +4: dword: PID отлаживаемого процесса
* +8: могут присутствовать дополнительные данные,
определяемые кодом сообщения
Коды сообщений:
* 1 = исключение
* дополнительно передаётся dword-номер исключения
* процесс приостановлен
* 2 = процесс завершился
* приходит при любом завершении: как через системную функцию -1,
так и при "убийстве" любым другим процессом
(в том числе самим отладчиком)
* 3 = отладочное исключение int 1 = #DB
* дополнительно передаётся dword-образ регистра DR6:
* биты 0-3: выполнено условие соответствующей точки останова
(установленной подфункцией 9)
* бит 14: исключение произошло из-за режима
пошаговой трассировки (установлен флаг TF)
* процесс приостановлен
При завершении отладчика прибиваются все отлаживаемые процессы.
Если отладчик этого не хочет, он должен предварительно отключиться
подфункцией 3.
 
Все подфункции применимы только к процессам/потокам, запущенным
из текущего функцией 70 с установленным флагом отладки.
Отладка многопоточных программ пока не поддерживается.
Полный список подфункций:
* подфункция 0 - определить область данных для отладочных сообщений
* подфункция 1 - получить состояние регистров отлаживаемого потока
* подфункция 2 - установить состояние регистров отлаживаемого потока
* подфункция 3 - отключиться от отлаживаемого процесса
* подфункция 4 - приостановить отлаживаемый поток
* подфункция 5 - возобновить выполнение отлаживаемого потока
* подфункция 6 - прочитать из памяти отлаживаемого процесса
* подфункция 7 - записать в память отлаживаемого процесса
* подфункция 8 - завершить отлаживаемый поток
* подфункция 9 - установить/снять аппаратную точку останова
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_SET_MESSAGE_AREA (0), SSF_GET_REGISTERS (1),
SSF_SET_REGISTERS (2), SSF_DETACH (3), SSF_SUSPEND (4),
SSF_RESUME (5), SSF_READ_MEMORY (6), SSF_WRITE_MEMORY (7),
SSF_TERMINATE (8), SSF_DEFINE_BREAKPOINT (9)
======================================================================
====================== Функция 69, подфункция 0 ======================
========= Определить область данных для отладочных сообщений. ========
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 0 - номер подфункции
* ecx = указатель
Формат области данных:
* +0: dword: N = размер буфера (не считая этого заголовка)
* +4: dword: занято в буфере
* +8: N*byte: буфер
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Если поле размера отрицательно, буфер считается заблокированным
и при поступлении нового сообщения система будет ждать.
Для синхронизации обрамляйте всю работу с буфером операциями
блокировки/разблокировки
neg [bufsize]
* Данные в буфере трактуются как массив элементов переменной длины -
сообщений. Формат сообщения указан в общем описании.
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_SET_MESSAGE_AREA (0)
======================================================================
====================== Функция 69, подфункция 1 ======================
========= Получить состояние регистров отлаживаемого потока. =========
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 1 - номер подфункции
* ecx = идентификатор потока
* edx = длина структуры контекста, должно быть 0x28=40 байт
* esi = указатель на структуру контекста
Возвращаемое значение:
* функция не возвращает значения
Формат структуры контекста: (FPU пока не поддерживается)
* +0: dword: eip
* +4: dword: eflags
* +8: dword: eax
* +12 = +0xC: dword: ecx
* +16 = +0x10: dword: edx
* +20 = +0x14: dword: ebx
* +24 = +0x18: dword: esp
* +28 = +0x1C: dword: ebp
* +32 = +0x20: dword: esi
* +36 = +0x24: dword: edi
Замечания:
* Если поток выполняет код 0-кольца, возвращается
состояние регистров 3-кольца.
* Процесс должен быть загружен для отладки (как указано в
общем описании).
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_GET_REGISTERS (1)
======================================================================
====================== Функция 69, подфункция 2 ======================
======== Установить состояние регистров отлаживаемого потока. ========
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 2 - номер подфункции
* ecx = идентификатор потока
* edx = длина структуры контекста, должно быть 0x28=40 байт
* esi = указатель на структуру контекста
Возвращаемое значение:
* функция не возвращает значения
Формат структуры контекста указан в описании подфункции 1.
Замечания:
* Если поток выполняет код 0-кольца, устанавливается
состояние регистров 3-кольца.
* Процесс должен быть загружен для отладки (как указано в
общем описании).
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_SET_REGISTERS (2)
======================================================================
== Функция 69, подфункция 3 - отключиться от отлаживаемого процесса. =
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 3 - номер подфункции
* ecx = идентификатор
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Если процесс был приостановлен, он возобновляет выполнение.
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_DETACH (3)
======================================================================
==== Функция 69, подфункция 4 - приостановить отлаживаемый поток. ====
======================================================================
Параметры:
* eax = 69 - номер процесса
* ebx = 4 - номер подфункции
* ecx = идентификатор
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Процесс должен быть загружен для отладки (как указано в
общем описании).
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_SUSPEND (4)
======================================================================
====================== Функция 69, подфункция 5 ======================
============ Возобновить выполнение отлаживаемого потока. ============
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 5 - номер подфункции
* ecx = идентификатор
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Процесс должен быть загружен для отладки (как указано в
общем описании).
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_RESUME (5)
======================================================================
====================== Функция 69, подфункция 6 ======================
============= Прочитать из памяти отлаживаемого процесса. ============
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 6 - номер подфункции
* ecx = идентификатор
* edx = сколько байт читать
* esi = адрес памяти отлаживаемого процесса
* edi = указатель на буфер для данных
Возвращаемое значение:
* eax = -1 при ошибке (неверный PID или буфер)
* иначе eax = число прочитанных байт (возможно, 0,
если в esi слишком большое значение)
Замечания:
* Процесс должен быть загружен для отладки (как указано в
общем описании).
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_READ_MEMORY (6)
======================================================================
Функция 69, подфункция 7 - записать в память отлаживаемого процесса.
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 7 - номер подфункции
* ecx = идентификатор
* edx = сколько байт писать
* esi = адрес памяти в отлаживаемом процессе
* edi = указатель на данные
Возвращаемое значение:
* eax = -1 при ошибке (неверный PID или буфер)
* иначе eax = число записанных байт (возможно, 0,
если в esi слишком большое значение)
Замечания:
* Процесс должен быть загружен для отладки (как указано в
общем описании).
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_WRITE_MEMORY (7)
======================================================================
====== Функция 69, подфункция 8 - завершить отлаживаемый поток. ======
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 8 - номер подфункции
* ecx = идентификатор
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Процесс должен быть загружен для отладки (как указано в
общем описании).
* Функция аналогична подфункции 2 функции 18 с двумя отличиями:
требуется выполнение первого замечания и принимается PID,
а не номер слота.
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_TERMINATE (8)
======================================================================
====================== Функция 69, подфункция 9 ======================
============= Установить/снять аппаратную точку останова. ============
======================================================================
Параметры:
* eax = 69 - номер функции
* ebx = 9 - номер подфункции
* ecx = идентификатор потока
* dl = индекс точки останова, от 0 до 3 включительно
* dh = флаги:
* если старший бит сброшен - установить точку останова:
* биты 0-1 - условие:
* 00 = точка останова на выполнение
* 01 = точка останова на запись
* 11 = точка останова на чтение/запись
* биты 2-3 - длина; для точек останова на исполнение должно быть
00, в противном случае одно из
* 00 = байт
* 01 = слово
* 11 = двойное слово
* esi = адрес точки останова; должен быть выровнен
соответственно длине (т.е. должен быть чётным для
точек останова на слово, кратен 4 для двойного слова)
* если старший бит установлен - сбросить точку останова
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - ошибка во входных данных
* eax = 2 - (зарезервировано, никогда не возвращается
в текущей реализации) с этим индексом уже установлена
глобальная точка останова
Замечания:
* Процесс должен быть загружен для отладки (как указано в
общем описании).
* Аппаратные точки останова реализуются через DRx-регистры
процессора, отсюда все ограничения.
* Функция может переустановить ранее установленную ей же
точку останова (никак не сообщая об этом).
Ведите список установленных точек останова в отладчике.
* Срабатывание точки останова заключается в генерировании
отладочного исключения #DB, о котором система сообщает отладчику.
* Точка останова на запись и чтение/запись срабатывает после
выполнения вызвавшей её инструкции.
 
---------------------- Константы для регистров: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_DEFINE_BREAKPOINT (9)
======================================================================
= Функция 70 - работа с файловой системой с поддержкой длинных имён. =
======================================================================
Параметры:
* eax = 70
* ebx = указатель на информационную структуру
Возвращаемое значение:
* eax = 0 - успешно; иначе код ошибки файловой системы
* в зависимости от подфункции может возвращаться значение и
в других регистрах
Общий формат информационной структуры:
* +0: dword: номер подфункции
* +4: dword: смещение в файле или папке
* +8: dword: старшая часть смещения или поле флагов
* +12 = +0xC: dword: размер данных
* +16 = +0x10: dword: указатель на данные
* +20 = +0x14: ?: текстовая строка - путь к файлу, заканчивается нулём
или
* +20 = +0x14: byte: 0
* +21 = +0x15: dword: указатель на строку
Чувствительность к регистру букв зависит от файловой системы.
Если путь начинается не с '/', то он считается относительным.
Получить или установить текущую папку можно с помощью сисфункции 30.
'../' в пути означает подъём на одну папку относительно текущей.
Можно указать кодировку строки, поместив в её начале байт со значениями:
* 1 = cp866
* 2 = UTF-16LE
* 3 = UTF-8
иначе будет использоваться кодировка cp866. В абсолютном пути можно
поместить этот байт после '/' или добавить дополнительный '/' перед ним.
Также, можно использовать сисфункцию 80.
Формат абсолютного пути:
/base/number/dir1/dir2/.../dirn/file,
где base/number идентифицирует устройство, на котором ищется файл:
* RD/1 = рамдиск
* FD/1 = первый флоппи-дисковод,
FD/2 = второй флоппи-дисковод
* HD0/x, HD1/x, HD2/x, HD3/x = жёсткие диски соответственно на
IDE0 (Primary Master), IDE1 (Primary Slave),
IDE2 (Secondary Master), IDE3 (Secondary Slave);
x - номер раздела на выбранном винчестере, начиная с 1
* CD0/1, CD1/1, CD2/1, CD3/1 = аналогично для cd
* SYS - системная папка (является ключом, не зависит от кодировки),
второй ключ может быть установлен сисфункцией 30.3.
Примеры:
* '/sys/example.asm',0
* '/rd/1/example.asm',0
* '/HD0/1/folder/file.txt',0
* '/hd2/2/pics/tanzania.bmp',0
* 2,'/',0,'sys','/',0,'F',0,'I',0,'L',0,'E',0,0,0
 
Доступные подфункции:
* подфункция 0 - чтение файла
* подфункция 1 - чтение папки
* подфункция 2 - создание/перезапись файла
* подфункция 3 - запись в существующий файл
* подфункция 4 - установка размера файла
* подфункция 5 - получение атрибутов файла/папки
* подфункция 6 - установка атрибутов файла/папки
* подфункция 7 - запуск программы
* подфункция 8 - удаление файла/папки
* подфункция 9 - создание папки
Для CD-приводов в связи с аппаратными ограничениями доступны
только подфункции 0,1,5 и 7, вызов других подфункций завершится
ошибкой с кодом 2.
При первом обращении подфункций 0,1,5,7 к устройствам ATAPI
(CD и DVD) производится блокировка ручного управления механизмом
лотка. Это связано с кэшированием данных, полученных от привода.
Разблокировка осуществляется при обращении подфункции 4 функции 24
к соответствующему устройству.
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_FILE (0), SSF_READ_FOLDER (1), SSF_CREATE_FILE (2),
SSF_WRITE_FILE (3), SSF_SET_END (4), SSF_GET_INFO (5),
SSF_SET_INFO (6), SSF_START_APP (7), SSF_DELETE (8),
SSF_CREATE_FOLDER (9)
======================================================================
= Функция 70, подфункция 0 - чтение файла с поддержкой длинных имён. =
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 0 = номер подфункции
* +4: dword: позиция в файле (в байтах)
* +8: dword: 0 (зарезервировано под старший dword позиции)
* +12 = +0xC: dword: сколько байт читать
* +16 = +0x10: dword: указатель на буфер, куда будут записаны данные
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx = число прочитанных байт
Замечания:
* Если файл кончился раньше, чем был прочитан последний запрошенный
блок, то функция прочитает, сколько сможет, после чего вернёт
eax=6 (EOF).
* Функция не позволяет читать папки
(вернётся eax=10, access denied).
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_FILE (0)
======================================================================
= Функция 70, подфункция 1 - чтение папки с поддержкой длинных имён. =
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 1 = номер подфункции
* +4: dword: индекс начального блока (считая с 0)
* +8: dword: в какой кодировке возвращать имена:
0 = по умолчанию
1 = cp866
2 = UTF-16LE
3 = UTF-8
* +12 = +0xC: dword: сколько блоков читать
* +16 = +0x10: dword: указатель на буфер, куда будут записаны данные.
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx = число файлов, информация о которых была записана в буфер
Структура буфера:
* заголовок (32 байта)
* блок с информацией о файле 1
* блок с информацией о файле 2
* ...
Структура заголовка:
* +0: dword: версия структуры (текущая версия = 1)
* +4: dword: количество размещённых блоков; не больше, чем запрошено
в поле +12 информационной структуры; может быть меньше,
если в папке кончились файлы (то же самое, что и в ebx)
* +8: dword: общее число файлов в папке
* +12 = +0xC: 20*byte: зарезервировано (нули)
Структура блока данных входа каталога (БДВК):
* +0: dword: атрибуты файла:
* бит 0 (маска 1): файл только для чтения
* бит 1 (маска 2): файл является скрытым
* бит 2 (маска 4): файл является системным
* бит 3 (маска 8): это метка тома (возвращается подфункцией 5)
* бит 4 (маска 0x10): это папка
* бит 5 (маска 0x20): файл не архивировался - многие программы
архивации имеют опцию, по которой архивируются только файлы
с установленным этим битом, после чего этот бит сбрасывается -
это может быть полезно для автоматического создания
backup-архивов, ибо при записи бит обычно устанавливается
(не в Kolibri, правда)
* +4: dword: кодировка имени, соответствует полю +8 информационной структуры
* +8: 4*byte: время создания файла
* +12 = +0xC: 4*byte: дата создания файла
* +16 = +0x10: 4*byte: время последнего доступа (чтение или запись)
* +20 = +0x14: 4*byte: дата последнего доступа
* +24 = +0x18: 4*byte: время последней модификации
* +28 = +0x1C: 4*byte: дата последней модификации
* +32 = +0x20: qword: размер файла в байтах (до 16777216 Тб)
* +40 = +0x28: имя, размер в cp866 составляет 264 байта, иначе - 520 байт.
Формат времени:
* +0: byte: секунды
* +1: byte: минуты
* +2: byte: часы
* +3: byte: зарезервировано (0)
* например, 23.59.59 записывается как (в hex) 3B 3B 17 00
Формат даты:
* +0: byte: день
* +1: byte: месяц
* +2: word: год
* например, 25.11.1979 записывается как (в hex) 19 0B BB 07
Замечания:
* Если БДВК содержит имя в cp866, то длина БДВК составляет
304 байта, иначе - 560 байт.
* Строка имени заканчивается нулём, дальнейшие данные содержат мусор.
* Если файлы в папке кончились раньше, чем было прочитано
запрошенное количество, то функция прочитает, сколько сможет,
после чего вернёт eax=6 (EOF).
* Любая папка на диске, кроме корневой, содержит два специальных
входа "." и "..", идентифицирующих соответственно саму папку и
родительскую папку.
* Функция позволяет также читать виртуальные папки "/", "/rd",
"/fd", "/hd[n]", при этом атрибуты подпапок полагаются равными
0x10, а времена и даты обнулены.
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_FOLDER (1)
======================================================================
====================== Функция 70, подфункция 2 ======================
======== Создание/перезапись файла с поддержкой длинных имён. ========
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 2 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: сколько байт писать
* +16 = +0x10: dword: указатель на данные
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx = число записанных байт (возможно, 0)
Замечания:
* Если файл с таким именем не существовал, он создаётся; если
существовал, то перезаписывается.
* Если свободного места на диске недостаточно, то функция запишет,
сколько сможет, после чего вернёт код ошибки 8.
* Функция не поддерживается для CD (вернётся код ошибки 2).
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_CREATE_FILE (2)
======================================================================
====================== Функция 70, подфункция 3 ======================
======== Запись в существующий файл с поддержкой длинных имён. =======
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 3 = номер подфункции
* +4: dword: позиция в файле (в байтах)
* +8: dword: старший dword позиции (должен быть 0 для FAT)
* +12 = +0xC: dword: сколько байт писать
* +16 = +0x10: dword: указатель на данные
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx = число записанных байт (возможно, 0)
Замечания:
* Файл должен уже существовать, иначе вернётся eax=5.
* Единственным результатом записи 0 байт является установка в
атрибутах файла даты/времени модификации и доступа в текущую.
* Если начальная и/или конечная позиция выходит за пределы файла
(за исключением предыдущего случая), файл расширяется до
необходимого размера нулевыми символами.
* Функция не поддерживается для CD (вернётся код ошибки 2).
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_WRITE_FILE (3)
======================================================================
========= Функция 70, подфункция 4 - установка размера файла. ========
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 4 = номер подфункции
* +4: dword: младший dword нового размера файла
* +8: dword: старший dword нового размера файла
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: 0 (зарезервировано)
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx разрушается
Замечания:
* Если новый размер файла меньше старого, файл усекается.
Если новый размер больше старого, файл расширяется, и если
разница в размере не больше 16 МБ, новое место очищается нулями.
* Если свободного места на диске недостаточно для расширения файла,
то функция расширит насколько возможно, после чего вернёт
код ошибки 8.
* Функция не поддерживается для CD (вернётся код ошибки 2).
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_SET_END (4)
======================================================================
=== Функция 70, подфункция 5 - получение информации о файле/папке. ===
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 5 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 или флаги (для корневого каталога)
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: указатель на буфер, куда будут записаны данные
(40 байт)
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx разрушается
Информация о файле возвращается в формате БДВК
(блока данных входа каталога), указанном в описании подфункции 1,
но без имени файла, за исключением корневого каталога.
Замечания:
* Для корневого каталога возвращается размер раздела,
а при указании кодировки (не ноль), также его имя.
* Для устройства возвращается только размер.
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_GET_INFO (5)
======================================================================
===== Функция 70, подфункция 6 - установка атрибутов файла/папки. ====
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 6 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: указатель на буфер с атрибутами (32 байта)
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx разрушается
Атрибуты файла - первые 32 байта в БДВК (блоке данных входа каталога),
формат которого указан в описании подфункции 1
(то есть без имени и размера файла). Атрибут файл/папка/метка тома
(биты 3,4 в dword'е +0) не меняется.
Байт +4 (формат имени) игнорируется.
Замечания:
* Функция не поддерживает виртуальные папки типа /, /rd и
корневые папки типа /rd/1.
* Функция не поддерживается для CD (вернётся код ошибки 2).
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_SET_INFO (6)
======================================================================
============ Функция 70, подфункция 7 - запуск программы. ============
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 7 = номер подфункции
* +4: dword: поле флагов:
* бит 0: запустить процесс как отлаживаемый
* остальные биты зарезервированы и должны быть установлены в 0
* +8: dword: 0 или указатель на ASCIIZ-строку с параметрами
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: 0 (зарезервировано)
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax > 0 - программа загружена, eax содержит PID
* eax < 0 - произошла ошибка, -eax содержит
код ошибки файловой системы
* ebx разрушается
Замечания:
* Командная строка должна заканчиваться символом с кодом 0
(ASCIIZ-строка); учитываются либо все символы до завершающего нуля
включительно, либо первые 256 символов, в зависимости от того,
что меньше.
* Если процесс запускается как отлаживаемый, он создаётся
в замороженном состоянии; для запуска используйте
подфункцию 5 функции 69.
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_START_APP (7)
======================================================================
========== Функция 70, подфункция 8 - удаление файла/папки. ==========
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 8 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: 0 (зарезервировано)
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx разрушается
Замечания:
* Функция не поддерживается для CD (вернётся код ошибки 2).
* Можно удалять только пустые папки (попытка удаления непустой папки
приведёт к ошибке с кодом 10, "доступ запрещён").
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_DELETE (8)
======================================================================
============= Функция 70, подфункция 9 - создание папки. =============
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 9 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: 0 (зарезервировано)
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx разрушается
Замечания:
* Функция не поддерживается для CD (вернётся код ошибки 2).
* Родительская папка должна уже существовать.
* Если папка уже существует, функция завершится успешно (eax=0).
 
---------------------- Константы для регистров: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_CREATE_FOLDER (9)
======================================================================
======= Функция 70, подфункция 10 - переименование/перемещение =======
======================================================================
Параметры:
* eax = 70 - номер функции
* ebx = указатель на информационную структуру
Формат информационной структуры:
* +0: dword: 10 = номер подфункции
* +4: dword: 0 (зарезервировано)
* +8: dword: 0 (зарезервировано)
* +12 = +0xC: dword: 0 (зарезервировано)
* +16 = +0x10: dword: указатель на строку с новым именем/путём
* +20 = +0x14: путь, правила формирования имён указаны в общем описании
Возвращаемое значение:
* eax = 0 - успешно, иначе код ошибки файловой системы
* ebx разрушается
Замечания:
* Формирование нового пути отличается от общих правил:
относительный путь относится к папке целевого файла (или папки),
абсолютный путь считается от корня раздела.
======================================================================
========== Функция 71 - установить заголовок окна программы ==========
======================================================================
Параметры:
* eax = 71 - номер функции
* ebx = 1
* ecx = адрес строки заголовка,
строка может начинаться с байта кодировки:
1 = cp866
2 = UTF-16LE
3 = UTF-8
или:
* ebx = 2
* ecx = адрес строки заголовка
* dl = кодировка строки
Возвращаемое значение:
* функция не возвращает значения
Замечания:
* Строка заголовка должна заканчиваться нулём.
* Чтобы убрать заголовок, передайте NULL в ecx.
 
---------------------- Константы для регистров: ----------------------
eax - SF_SET_CAPTION (71)
======================================================================
================ Функция 72 - послать сообщение окну. ================
======================================================================
 
--- Подфункция 1 - послать сообщение с параметром активному окну. ----
Параметры:
* eax = 72 - номер функции
* ebx = 1 - номер подфункции
* ecx = код события: 2 или 3
* edx = код клавиши для ecx=2, идентификатор кнопки для ecx=3
Возвращаемое значение:
* eax = 0 - успешно
* eax = 1 - буфер заполнен
 
---------------------- Константы для регистров: ----------------------
eax - SF_SEND_MESSAGE (72)
======================================================================
===================== Функция 73 - blit bitmap =====================
======================================================================
блит - копирование битового массив
 
Параметры:
* eax = 73 - номер функции
 
* ebx = ROP и опциональные флаги
31 30 29 28 6 5 4 3 0
[reserved][CR][reserved][T][B][ROP]
ROP - код растровых операций
0: копировать
1-15: Зарезервировано
B - блит на фоновую поверхность
T - блит с прозрачностью
CR - относительно клиентской области окна
 
* ecx = указатель на параметры функции
смещение цели и отсечение
+0 signed dword: смещение по X окна, для целевого прямоугольника
верхний левый угол
+4 signed dword: смещение по Y окна, для целевого прямоугольника
верхний левый угол
+8 dword: ширина целевого прямоугольника
+12 dword: высота целевого прямоугольника
 
смещение исходника и отсечение
+16 signed dword: смещение по X bitmap, для исходного прямоугольника
верхний левый угол
+20 signed dword: смещение по Y bitmap, для исходного прямоугольника
верхний левый угол
+24 dword: ширина исходного прямоугольника
+28 dword: высота исходного прямоугольника
 
+32: dword: данные bitmap - должны быть 32bpp
+36: dword: размер строки bitmap в байтах
 
Возвращаемое значение:
* функция не возвращает значения
 
---------------------- Константы для регистров: ----------------------
eax - SF_BLITTER (73)
======================================================================
=================== Функция 74, подфункция -1 ========================
=========== Получить количество активных сетевых устройств. ==========
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = -1 - номер подфункции
Возвращаемое значение:
* eax = количество активных сетевых устройств
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_DEVICE_COUNT (255)
======================================================================
==== Функция 74, подфункция 0, Получить тип сетевого устройства. =====
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 0 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = тип устройства
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_DEVICE_TYPE (0)
======================================================================
==== Функция 74, подфункция 1, Получить имя сетевого устройства. =====
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 1 - номер подфункции
* bh = номер устройства
* ecx = указатель на буфера - 64 байт
Возвращаемое значение:
* eax = -1 для ошибки
* В случае успеха в буфер записывается имя сетевого устройства
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_DEVICE_NAME (1)
======================================================================
======= Функция 74, подфункция 2, Сброс сетевого устройства. =========
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 2 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = -1 для ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RESET_DEVICE (2)
======================================================================
====== Функция 74, подфункция 3, Остановить сетевое устройство. ======
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 3 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = -1 для ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_STOP_DEVICE (3)
======================================================================
===== Функция 74, подфункция 4, Получить указатель на устройство =====
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 4 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = указатель, -1 для ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_DEVICE_POINTER (4)
======================================================================
=== Функция 74, подфункция 6, Получить количество посланых пакетов ===
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 6 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = количество с момента старта устройства, -1 для ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_PACKET_COUNT (6)
======================================================================
=== Функция 74, подфункция 7, Получить количество принятых пакетов ===
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 7 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = количество с момента старта устройства, -1 для ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_PACKET_COUNT (7)
======================================================================
==== Функция 74, подфункция 8, Получить количество посланых байт. ====
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 8 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = количество с момента старта устройства, -1 для ошибки
* ebx = старшая часть
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_BYTE_COUNT (8)
======================================================================
==== Функция 74, подфункция 9, Получить количество принятых байт. ====
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 9 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = количество с момента старта устройства, -1 для ошибки
* ebx = старшая часть
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_BYTE_COUNT (9)
======================================================================
======= Функция 74, подфункция 10, Получить статус соединения. =======
======================================================================
Параметры:
* eax = 74 - номер функции
* bl = 10 - номер подфункции
* bh = номер устройства
Возвращаемое значение:
* eax = статус соединения, -1 для ошибки
 
Статусы:
0 = нет соединения
1 = неизвестное соединение
4 = 10 Мбит
8 = 100 Мбит
12 = 1 Гбит
10b = флаг полного дуплекса
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_LINK_STATUS (10)
======================================================================
==== Function 74, Subfunction 11, Get TX error packets counter. ======
======================================================================
Parameters:
* eax = 74 - function number
* bl = 11 - subfunction number
* bh = device number
Returned value:
* eax = Number of erroneous packets received since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_PACKET_ERROR_COUNT (11)
======================================================================
=== Function 74, Subfunction 12, Get TX dropped packets counter. =====
======================================================================
Parameters:
* eax = 74 - function number
* bl = 12 - subfunction number
* bh = device number
Returned value:
* eax = Number of dropped packets since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_PACKET_DROP_COUNT (12)
======================================================================
==== Function 74, Subfunction 13, Get TX missed packets counter. =====
======================================================================
Parameters:
* eax = 74 - function number
* bl = 13 - subfunction number
* bh = device number
Returned value:
* eax = Number of missed packets since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_PACKET_MISS_COUNT (13)
======================================================================
==== Function 74, Subfunction 14, Get RX error packets counter. ======
======================================================================
Parameters:
* eax = 74 - function number
* bl = 14 - subfunction number
* bh = device number
Returned value:
* eax = Number of erroneous packets received since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_PACKET_ERROR_COUNT (14)
======================================================================
=== Function 74, Subfunction 15, Get RX dropped packets counter. =====
======================================================================
Parameters:
* eax = 74 - function number
* bl = 15 - subfunction number
* bh = device number
Returned value:
* eax = Number of dropped packets since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_PACKET_DROP_COUNT (12)
======================================================================
==== Function 74, Subfunction 16, Get RX missed packets counter. =====
======================================================================
Parameters:
* eax = 74 - function number
* bl = 16 - subfunction number
* bh = device number
Returned value:
* eax = Number of missed packets since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_PACKET_MISS_COUNT (16)
======================================================================
============== Функция 75, подфункция 0, Открыть сокет. ==============
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 0 - номер подфункции
* ecx = домен
* edx = тип
* esi = протокол
Возвращаемое значение:
* eax = номер сокета, -1 для ошибки
* ebx = код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_OPEN (0)
======================================================================
============== Функция 75, подфункция 1, Закрыть сокет. ==============
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 1 - номер подфункции
* ecx = номер сокета
Возвращаемое значение:
* eax = -1 для ошибки
* ebx = код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_CLOSE (1)
======================================================================
============= Функция 75, подфункция 2, Bind (Привязка). =============
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 2 - номер подфункции
* ecx = номер сокета
* edx = указатель на структуру sockaddr
* esi = длина структуры sockaddr
Формат структуры SockAddr:
* +0: Word: Family
* +2: 14*Byte: Data
Возвращаемое значение:
* eax = -1 для ошибки
* ebx = код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_BIND (2)
======================================================================
============ Функция 75, подфункция 3, Listen (Слушать). =============
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 3 - номер подфункции
* ecx = номер сокета
* edx = backlog (возвращаемый лог)
Возвращаемое значение:
* eax = -1 для ошибки
* ebx = код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_LISTEN (3)
======================================================================
========== Функция 75, подфункция 4, Connect (Соединение). ===========
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 4 - номер подфункции
* ecx = номер сокета
* edx = указатель на структуру sockaddr
* esi = длина структуры sockaddr
Формат структуры SockAddr:
* +0: Word: Family
* +2: 14*Byte: Data
Возвращаемое значение:
* eax = -1 для ошибки
* ebx = код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_CONNECT (4)
======================================================================
=========== Функция 75, подфункция 5, Accept (Соглашение). ===========
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 5 - номер подфункции
* ecx = номер сокета
* edx = указатель на структуру sockaddr
* esi = длина структуры sockaddr
Формат структуры SockAddr:
* +0: Word: Family
* +2: 14*Byte: Data
Возвращаемое значение:
* eax = номер сокета из принятого сокета, -1 для ошибки
* ebx = код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_ACCEPT (5)
======================================================================
============= Функция 75, подфункция 6, Send (Послать). ==============
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 6 - номер подфункции
* ecx = номер сокета
* edx = указатель на буфер
* esi = длина буфера
* edi = флаги
Возвращаемое значение:
* eax = количество скопированных байтов, -1 для ошибки
* ebx = код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_SEND (6)
======================================================================
============ Функция 75, подфункция 7, Receive (Получить). ===========
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 7 - номер подфункции
* ecx = номер сокета
* edx = указатель на буфер
* esi = длина буфера
* edi = флаги
Возвращаемое значение:
* eax = количество скопированных байтов, -1 для ошибки
* ebx = код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_RECEIVE (7)
======================================================================
=========== Функция 75, подфункция 8, Задать опции сокета. ===========
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 8 - номер подфункции
* ecx = номер сокета
* edx = указатель на optstruct
Возвращаемое значение:
* eax = -1 для ошибки
* ebx = код ошибки
Замечания:
 
Optstruct: dd level
dd optionname
dd optlength
db options...
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_SET_OPTIONS (8)
======================================================================
========== Функция 75, подфункция 9, Получить опции сокета. ==========
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 9 - номер подфункции
* ecx = номер сокета
* edx = указатель на optstruct
Возвращаемое значение:
* eax = -1 для ошибки
* ebx = код ошибки
Замечания:
 
Optstruct: dd level
dd optionname
dd optlength
db options...
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_GET_OPTIONS (9)
======================================================================
========== Функция 75, подфункция 10, Получить парный сокет ==========
======================================================================
Параметры:
* eax = 75 - номер функции
* bl = 10 - номер подфункции
Возвращаемое значение:
* eax = номер первого сокета / -1 для ошибки
* ebx = номер второго сокета / код ошибки
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_GET_PAIR (10)
======================================================================
=============== Функция 76, Сетевые опции и статистика. ==============
======================================================================
Параметры:
* eax = 76 - номер функции
* верхняя часть ebx = номер протокола
* bh = номер устройства
* bl = номер подфункции
 
Протоколы и подфункции:
 
0 - Ethernet:
0 - Read MAC
 
общие подфункции:
0 - пакетов послано
1 - пакетов принято
 
1 - IPv4:
2 - Read IP
3 - Write IP
4 - Read DNS
5 - Write DNS
6 - Read subnet
7 - Write subnet
8 - Read gateway
9 - Write gateway
 
2 - ICMP:
3 - enable/disable ICMP echo reply
 
3 - UDP
4 - TCP
 
5 - ARP:
2 - Read # ARP entry's
3 - Read ARP entry
4 - Add static ARP entry
5 - Remove ARP entry (-1 = remove all)
6 - Send ARP announce on specified interface
7 - Read # ARP conflicts (IP address conflicts)
 
---------------------- Константы для регистров: ----------------------
eax - SF_NETWORK_PROTOCOL (76)
======================================================================
============= Функция 77, подфункция 0, Создать фьютекс. =============
======================================================================
Параметры:
* eax = 77 - номер функции
* ebx = 0 - номер подфункции
* ecx = указатель на контрольное значение фьютекса (dword)
Возвращаемое значение:
* eax = дескриптор фьютекса, 0 при ошибке
 
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_CREATE (0)
======================================================================
============= Функция 77, подфункция 1, Удалить фьютекс. =============
======================================================================
Параметры:
* eax = 77 - номер функции
* ebx = 1 - номер подфункции
* ecx = дескриптор фьютекса
Возвращаемое значение:
* eax = 0 - успешно, -1 при ошибке
Замечания:
* Ядро автоматически удаляет фьютексы при завершении процесса.
 
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_DESTROY (1)
======================================================================
================= Функция 77, подфункция 2, Ожидать. =================
======================================================================
Параметры:
* eax = 77 - номер функции
* ebx = 2 - номер подфункции
* ecx = дескриптор фьютекса
* edx = контрольное значение
* esi = таймаут в сотых секунды, 0 - ждать бесконечно
Возвращаемое значение:
* eax = 0 - успешно, -1 - таймаут,
-2 - контрольное значение не соответствует
 
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_WAIT (2)
======================================================================
================ Функция 77, подфункция 3, Разбудить. ================
======================================================================
Параметры:
* eax = 77 - номер функции
* ebx = 3 - номер подфункции
* ecx = дескриптор фьютекса
* edx = сколько ожидающих будить (максимум)
Возвращаемое значение:
* eax = количество разбуженых
 
---------------------- Константы для регистров: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_WAKE (3)
======================================================================
========== Функция -1 - завершить выполнение потока/процесса =========
======================================================================
Параметры:
* eax = -1 - номер функции
Возвращаемое значение:
* функция не возвращает ни значения, ни управления
Замечания:
* Если процесс явно не создавал потоков, то у него есть только
один поток, завершение которого приводит к завершению процесса.
* Если текущий поток - последний в процессе, то его завершение
также приводит к завершению процесса.
* Эта функция завершает текущий поток. Другой поток можно прибить
вызовом подфункции 2 функции 18.
 
---------------------- Константы для регистров: ----------------------
eax - SF_TERMINATE_PROCESS (-1)
======================================================================
=== Функция 80 - работа с файловой системой с указанием кодировки. ===
======================================================================
Параметры:
* eax = 80
* ebx = указатель на информационную структуру
Возвращаемое значение:
* eax = 0 - успешно; иначе код ошибки файловой системы
* в зависимости от подфункции может возвращаться значение и
в других регистрах
Общий формат информационной структуры:
* +0: dword: номер подфункции
* +4: dword: смещение в файле или папке
* +8: dword: старшая часть смещения или поле флагов
* +12 = +0xC: dword: размер данных
* +16 = +0x10: dword: указатель на данные
* +20 = +0x14: dword: кодировка строки:
1 = cp866
2 = UTF-16LE
3 = UTF-8
0 = по умолчанию (поддерживает байт кодировки в начале строки)
* +24 = +0x18: dword: указатель на строку пути (заканчивается нулём)
 
В остальном полностью соответствует функции 70.
 
======================================================================
=========================== Список событий ===========================
======================================================================
Очередное событие можно получить вызовом одной из функций 10
(ожидать события), 11 (проверить без ожидания), 23
(ожидать в течение заданного времени).
Эти функции возвращают только те события, которые входят в маску,
устанавливаемую функцией 40. По умолчанию это первые три, чего
вполне достаточно для многих приложений.
Коды событий:
* 1 = сообщение о перерисовке (сбрасывается при вызове функции 0)
* 2 = нажата клавиша на клавиатуре (поступает, только когда окно
активно) или нажата "горячая клавиша";
сбрасывается, когда все клавиши из буфера считаны функцией 2
* 3 = нажата кнопка, определённая ранее функцией 8 (или кнопка
закрытия, созданная неявно функцией 0; кнопка минимизации
обрабатывается системой и о ней сообщения не приходит;
поступает, только когда окно активно; сбрасывается, когда все
кнопки из буфера считаны функцией 17)
* 4 = зарезервировано (в текущей реализации никогда не приходит даже
при размаскировке функцией 40)
* 5 = завершилась перерисовка фона рабочего стола
* 6 = событие от мыши (что-то случилось - нажатие на кнопку мыши
или перемещение; сбрасывается при прочтении)
* 7 = произошло событие IPC (смотри функцию 60 - Inter Process
Communication; сбрасывается при прочтении)
* 8 = произошло сетевое событие (сбрасывается при прочтении;
смотри работу с сетью)
* 9 = произошло отладочное событие (сбрасывается при прочтении;
смотри отладочную подсистему)
* 16..31 = произошло событие с соответствующим IRQ
(16=IRQ0, 31=IRQ15) (сбрасывается при считывании всех данных IRQ)
 
======================================================================
==================== Коды ошибок файловой системы ====================
======================================================================
* 0 = успешно
* 2 = функция не поддерживается для данной файловой системы
* 3 = неизвестная файловая система
* 5 = файл не найден
* 6 = файл закончился
* 7 = указатель вне памяти приложения
* 8 = диск заполнен
* 9 = ошибка файловой системы
* 10 = доступ запрещён
* 11 = ошибка устройства
* 12 = файловой системе недостаточно оперативной памяти
 
При запуске программы возможны также следующие коды ошибок:
* 30 = 0x1E = недостаточно памяти
* 31 = 0x1F = файл не является исполнимым
* 32 = 0x20 = слишком много процессов
/kernel/branches/kolibrios-pe-clevermouse/docs/sysfuncs.txt
0,0 → 1,5334
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
SYSTEM FUNCTIONS of OS Kolibri 0.7.7.0
 
Number of the function is located in the register eax.
The call of the system function is executed by "int 0x40" command.
All registers except explicitly declared in the returned value,
including eflags, are preserved.
 
 
======================================================================
============== Function 0 - define and draw the window. ==============
======================================================================
Defines an application window. Draws a frame of the window, header and
working area. For skinned windows defines standard close and minimize
buttons.
Parameters:
* eax = 0 - function number
* ebx = [coordinate on axis x]*65536 + [size on axis x]
* ecx = [coordinate on axis y]*65536 + [size on axis y]
* edx = 0xXYRRGGBB, where:
* Y = style of the window:
* Y=1 - only define window area, draw nothing
* Y=3 - skinned window
* Y=4 - skinned fixed-size window
* Y=0,2 window types are outdated and should not be used anymore,
they are retained for compatibility with old programs.
* other possible values (from 5 to 15) are reserved,
function call with such Y is ignored
* RR, GG, BB = accordingly red, green, blue components of a color
of the working area of the window (are ignored for style Y=1)
* X = DCBA (bits)
* A = 1 - window has caption
* B = 1 - coordinates of all graphics primitives are relative to
window client area
* C = 1 - don't fill working area on window draw
* D = 0 - normal filling of the working area, 1 - gradient
The following parameters are intended for windows
of a type I and II, and ignored for styles Y=1,3:
* esi = 0xXYRRGGBB - color of the header
* RR, GG, BB define color
* Y=0 - usual window, Y=1 - unmovable window (works for all window styles)
* X not used, other values of Y are reserved
* edi = caption string for styles Y=3,4 (also can be set by func 71.1)
Returned value:
* function does not return value
Remarks:
* Position and sizes of the window are installed by the first
call of this function and are ignored at subsequent; to change
position and/or sizes of already created window use function 67.
* For windows with styles Y=3,4 and caption (A=1) caption string
is set by the first call of this function and is ignored
at subsequent (strictly speaking, is ignored after a call to
subfunction 2 of function 12 - end redraw); to change caption of
already created window use subfunction 1 of function 71.
* If the window has appropriate styles, position and/or sizes can be
changed by user. Current position and sizes can be obtained
by function 9.
* The window must fit on the screen. If the transferred
coordinates and sizes do not satisfy to this condition,
appropriate coordinate (or, probably, both) is considered as zero,
and if it does not help too, the appropriate size
(or, probably, both) is installed in a size of the screen.
 
Further let us designate xpos,ypos,xsize,ysize - values passed
in ebx,ecx. The coordinates are resulted concerning
the left upper corner of the window, which, thus, is set as (0,0),
coordinates of the right lower corner essence (xsize,ysize).
* The sizes of the window are understood in sense of coordinates
of the right lower corner. This concerns all other functions too.
It means, that the real sizes are on 1 pixel more.
* The window of style Y=1 looks as follows:
* completely defined by the application
* The skinned window Y=3,4 looks as follows:
* draw external frame of width 1 pixel
with color 'outer' from the skin
* draw intermediate frame of width 3 pixel
with color 'frame' from the skin
* draw internal frame of width 1 pixel
with color 'inner' from the skin
* draw header (on bitmaps from the skin) in a rectangle
(0,0) - (xsize,_skinh-1)
* if ysize>=26, fill the working area of the window -
rectangle with the left upper corner (5,_skinh) and right lower
(xsize-5,ysize-5) with color indicated in edx
(taking a gradient into account)
* define two standard buttons: close and minimize
(see function 8)
* if A=1 and edi contains (nonzero) pointer to caption string,
it is drawn in place in header defined in the skin
* value _skinh is accessible as the result of call
subfunction 4 of function 48
 
---------------------- Constants for registers: ----------------------
eax - SF_CREATE_WINDOW (0)
======================================================================
================ Function 1 - put pixel in the window. ===============
======================================================================
Parameters:
* eax = 1 - function number
* ebx = x-coordinate (relative to the window)
* ecx = y-coordinate (relative to the window)
* edx = 0x00RRGGBB - color of a pixel
edx = 0x01xxxxxx - invert color of a pixel
(low 24 bits are ignored)
Returned value:
* function does not return value
 
---------------------- Constants for registers: ----------------------
eax - SF_PUT_PIXEL (1)
======================================================================
============ Function 2 - get the code of the pressed key. ===========
======================================================================
Takes away the code of the pressed key from the buffer.
Parameters:
* eax = 2 - function number
Returned value:
* if the buffer is empty, function returns eax=1
* if the buffer is not empty, function returns al=0,
ah=code of the pressed key,
bits 16-23 = contain scancode for pressed key in ASCII mode,
in the scancodes mode this bits cleared.
bits 23-31 = zero
* if there is "hotkey", function returns al=2,
ah=scancode of the pressed key (0 for control keys),
high word of eax contains a status of control keys at the moment
of pressing a hotkey
Remarks:
* There is a common system buffer of the pressed keys
by a size of 120 bytes, organized as queue.
* There is one more common system buffer on 120 "hotkeys".
* If the application with the inactive window calls this function,
the buffer of the pressed keys is considered to be empty.
* By default this function returns ASCII-codes; to switch
to the scancodes mode (and back) use function 66.
However, hotkeys are always notificated as scancodes.
* To find out, what keys correspond to what codes, start
the application keyascii and scancode.
* Scancodes come directly from keyboard and are fixed;
ASCII-codes turn out with usage of the conversion tables,
which can be set by subfunction 2 of function 21
and get by subfunction 2 of function 26.
* As a consequence, ASCII-codes take into account current
keyboard layout (rus/en) as opposed to scancodes.
* This function notifies only about those hotkeys, which were
defined by this thread by subfunction 4 of function 66.
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_KEY (2)
======================================================================
==================== Function 3 - get system time. ===================
======================================================================
Parameters:
* eax = 3 - function number
Returned value:
* eax = 0x00SSMMHH, where HH:MM:SS = Hours:Minutes:Seconds
* each item is BCD-number, for example,
for time 23:59:59 function returns 0x00595923
Remarks:
* See also subfunction 9 of function 26 - get time from
the moment of start of the system; it is more convenient, because
returns simply DWORD-value of the time counter.
* System time can be set by function 22.
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_SYS_TIME (3)
======================================================================
=================== Function 4 - draw text string. ===================
======================================================================
Parameters:
* eax = 4 - function number
* ebx = X*65536+Y, coordinates in the window or buffer
* ecx = 0xXXRRGGBB, where
* RR, GG, BB specify text color
* XX = ABFFCSSS (bits):
* A=1 - output zero terminated string
* B=1 - fill background (color = edi)
* FF specifies the font and encoding:
0 = 6x9 cp866
1 = 8x16 cp866
2 = 8x16 UTF-16LE
3 = 8x16 UTF-8
* C=0 - draw to the window,
C=1 - draw to the user buffer (edi)
* SSS = (size multiplier)-1, so 0 = x1, 7 = x8
* edx = pointer to the beginning of the string
* esi = for A=0 length of the string, for A=1 is ignored
* edi = for B=1 color to fill background,
for C=1 pointer to user buffer
 
Returned value:
* function does not return value
Remarks:
* You can not use B=1 and C=1 at the same time, since both use edi.
* When SSS=0, font may be smoothed, depending on system setting.
* User buffer structure:
Xsize dd
Ysize dd
picture rb Xsize*Ysize*4 ; 32 bpp
 
---------------------- Constants for registers: ----------------------
eax - SF_DRAW_TEXT (4)
======================================================================
========================= Function 5 - delay. ========================
======================================================================
Delays execution of the program on the given time.
Parameters:
* eax = 5 - function number
* ebx = time in the 1/100 of second
Returned value:
* function does not return value
Remarks:
* Passing ebx=0 does not transfer control to the next process
and does not make any operations at all. If it is really required
to transfer control to the next process (to complete a current
time slice), use subfunction 1 of function 68.
 
---------------------- Constants for registers: ----------------------
eax - SF_SLEEP (5)
======================================================================
=============== Function 7 - draw image in the window. ===============
======================================================================
Paramters:
* eax = 7 - function number
* ebx = pointer to the image in the format BBGGRRBBGGRR...
* ecx = [size on axis x]*65536 + [size on axis y]
* edx = [coordinate on axis x]*65536 + [coordinate on axis y]
Returned value:
* function does not return value
Remarks:
* Coordinates of the image are coordinates of the upper left corner
of the image relative to the window.
* Size of the image in bytes is 3*xsize*ysize.
 
---------------------- Constants for registers: ----------------------
eax - SF_PUT_IMAGE (7)
======================================================================
=============== Function 8 - define/delete the button. ===============
======================================================================
Parameters for button definition:
* eax = 8 - function number
* ebx = [coordinate on axis x]*65536 + [size on axis x]
* ecx = [coordinate on axis y]*65536 + [size on axis y]
* edx = 0xXYnnnnnn, where:
* nnnnnn = identifier of the button
* high (31st) bit of edx is cleared
* if 30th bit of edx is set - do not draw the button
* if 29th bit of edx is set - do not draw a frame
at pressing the button
* esi = 0x00RRGGBB - color of the button
Parameters for button deleting:
* eax = 8 - function number
* edx = 0x80nnnnnn, where nnnnnn - identifier of the button
Returned value:
* function does not return value
Remarks:
* Sizes of the button must be more than 0 and less than 0x8000.
* For skinned windows definition of the window
(call of 0th function) creates two standard buttons -
for close of the window with identifier 1 and
for minimize of the window with identifier 0xffff.
* The creation of two buttons with same identifiers is admitted.
* The button with the identifier 0xffff at pressing is interpreted
by the system as the button of minimization, the system handles
such pressing independently, not accessing to the application.
In rest it is usual button.
* Total number of buttons for all applications is limited to 4095.
 
---------------------- Constants for registers: ----------------------
eax - SF_DEFINE_BUTTON (8)
======================================================================
============ Function 9 - information on execution thread. ===========
======================================================================
Parameters:
* eax = 9 - function number
* ebx = pointer to 1-Kb buffer
* ecx = number of the slot of the thread
ecx = -1 - get information on the current thread
Returned value:
* eax = maximum number of the slot of a thread
but if pointer in ebx is illegal, for example,
[ebx, ebx + 0x4C) region intersects with kernel memory,
then function returns -1
* buffer pointed to by ebx contains the following information:
* +0: dword: usage of the processor (how many time units
per second leaves on execution of this thread)
* +4: word: position of the window of thread in the window stack
* +6: word: (has no relation to the specified thread)
number of the thread slot, which window has in the window stack
position ecx
* +8: word: reserved
* +10 = +0xA: 11 bytes: name of the process
(name of the started file - executable file without extension)
* +21 = +0x15: byte: reserved, this byte is not changed
* +22 = +0x16: dword: address of the process in memory
* +26 = +0x1A: dword: size of used memory - 1
* +30 = +0x1E: dword: identifier (PID/TID)
* +34 = +0x22: dword: coordinate of the thread window on axis x
* +38 = +0x26: dword: coordinate of the thread window on axis y
* +42 = +0x2A: dword: size of the thread window on axis x
* +46 = +0x2E: dword: size of the thread window on axis y
* +50 = +0x32: word: status of the thread slot:
* 0 = thread is running
* 1 = thread is suspended
* 2 = thread is suspended while waiting for event
* 3 = thread is terminating as a result of call to function -1
or under duress as a result of call to subfunction 2
of function 18 or termination of the system
* 4 = thread is terminating as a result of exception
* 5 = thread waits for event
* 9 = requested slot is free, all other information on the slot
is not meaningful
* +52 = +0x34: word: reserved, this word is not changed
* +54 = +0x36: dword: coordinate of the client area on axis x
* +58 = +0x3A: dword: coordinate of the client area on axis y
* +62 = +0x3E: dword: width of the client area
* +66 = +0x42: dword: height of the client area
* +70 = +0x46: byte: state of the window - bitfield
* bit 0 (mask 1): window is maximized
* bit 1 (mask 2): window is minimized to panel
* bit 2 (mask 4): window is rolled up
* +71 = +0x47: dword: event mask
* +75 = +0x4B: byte: keyboard mode(ASCII = 0; SCAN = 1)
Remarks:
* Slots are numbered starting from 1.
* Returned value is not a total number of threads, because there
can be free slots.
* When process is starting, system automatically creates
execution thread.
* Function gives information on the thread. Each process has
at least one thread. One process can create many threads,
in this case each thread has its own slot and the fields
+10, +22, +26 in these slots coincide.
Applications have no common way to define whether two threads
belong to one process.
* The active window - window on top of the window stack -
receives the messages on a keyboard input. For such window
the position in the window stack coincides with returned value.
* Slot 1 corresponds to special system thread, for which:
* the window is in the bottom of the window stack, the fields
+4 and +6 contain value 1
* name of the process - "OS/IDLE" (supplemented by spaces)
* address of the process in memory is 0, size of used memory is
16 Mb (0x1000000)
* PID=1
* coordinates and sizes of the window and the client area are by
convention set to 0
* status of the slot is always 0 (running)
* the execution time adds of time leaving on operations itself
and idle time in waiting for interrupt (which can be got by call
to subfunction 4 of function 18).
* Beginning from slot 2, the normal applications are placed.
* The normal applications are placed in memory at the address
0 (kernel constant 'std_application_base_address').
There is no intersection, as each process has its own page table.
* At creation of the thread it is assigned the slot
in the system table and identifier (Process/Thread IDentifier =
PID/TID), which do not vary with time for given thread.
After completion of the thread its slot can be anew used
for another thread. The thread identifier can not be assigned
to other thread even after completion of this thread.
Identifiers, assigned to new threads, grow monotonously.
* If the thread has not yet defined the window by call to
function 0, the position and the sizes
of its window are considered to be zero.
* Coordinates of the client area are relative to the window.
* At the moment only the part of the buffer by a size
76 = 0x4C bytes is used. Nevertheless it is recommended to use
1-Kb buffer for the future compatibility, in the future
some fields can be added.
 
---------------------- Constants for registers: ----------------------
eax - SF_THREAD_INFO (9)
======================================================================
==================== Function 10 - wait for event. ===================
======================================================================
If the message queue is empty, waits for appearance of the message
in queue. In this state thread does not consume CPU time.
Then reads out the message from queue.
 
Parameters:
* eax = 10 - function number
Returned value:
* eax = event (see the list of events)
Remarks:
* Those events are taken into account only which enter into
a mask set by function 40. By default it is
redraw, key and button events.
* To check, whether there is a message in queue, use function 11.
To wait for no more than given time, use function 23.
 
---------------------- Constants for registers: ----------------------
eax - SF_WAIT_EVENT (10)
======================================================================
=============== Function 11 - check for event, no wait. ==============
======================================================================
If the message queue contains event, function reads out
and return it. If the queue is empty, function returns 0.
Parameters:
* eax = 11 - function number
Returned value:
* eax = 0 - message queue is empty
* else eax = event (see the list of events)
Remarks:
* Those events are taken into account only, which enter into
a mask set by function 40. By default it is
redraw, key and button events.
* To wait for event, use function 10.
To wait for no more than given time, use function 23.
 
---------------------- Constants for registers: ----------------------
eax - SF_CHECK_EVENT (11)
======================================================================
=============== Function 12 - begin/end window redraw. ===============
======================================================================
 
---------------- Subfunction 1 - begin window redraw. ----------------
Parameters:
* eax = 12 - function number
* ebx = 1 - subfunction number
Returned value:
* function does not return value
 
----------------- Subfunction 2 - end window redraw. -----------------
Parameters:
* eax = 12 - function number
* ebx = 2 - subfunction number
Returned value:
* function does not return value
Remarks:
* Subfunction 1 deletes all buttons defined with
function 8, they must be defined again.
 
---------------------- Constants for registers: ----------------------
eax - SF_REDRAW (12)
ebx - SSF_BEGIN_DRAW (1), SSF_END_DRAW (2)
======================================================================
============ Function 13 - draw a rectangle in the window. ===========
======================================================================
Parameters:
* eax = 13 - function number
* ebx = [coordinate on axis x]*65536 + [size on axis x]
* ecx = [coordinate on axis y]*65536 + [size on axis y]
* edx = color 0xRRGGBB or 0x80RRGGBB for gradient fill
Returned value:
* function does not return value
Remarks:
* Coordinates are understood as coordinates of the left upper corner
of a rectangle relative to the window.
 
---------------------- Constants for registers: ----------------------
eax - SF_DRAW_RECT (13)
======================================================================
=================== Function 14 - get screen size. ===================
======================================================================
Parameters:
* eax = 14 - function number
Returned value:
* eax = [xsize]*65536 + [ysize], where
* xsize = x-coordinate of the right lower corner of the screen =
horizontal size - 1
* ysize = y-coordinate of the right lower corner of the screen =
vertical size - 1
Remarks:
* See also subfunction 5 of function 48 - get sizes of
working area of the screen.
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_SCREEN_SIZE (14)
======================================================================
== Function 15, subfunction 1 - set a size of the background image. ==
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 1 - subfunction number
* ecx = width of the image
* edx = height of the image
Returned value:
* function does not return value
Remarks:
* Before calling subfunctions 2 and 5 you should call this function
to set image size!
* For update of the screen (after completion of a series of commands
working with a background) call subfunction 3.
* There is a pair function for get size of the background image -
subfunction 1 of function 39.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_SIZE_BG (1)
======================================================================
=== Function 15, subfunction 2 - put pixel on the background image. ==
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 2 - subfunction number
* ecx = offset
* edx = color of a pixel 0xRRGGBB
Returned value:
* function does not return value
Remarks:
* Offset for a pixel with coordinates (x,y) is calculated as
(x+y*xsize)*3.
* If the given offset exceeds size set by subfunction 1,
the call is ignored.
* For update of the screen (after completion of a series of commands
working with a background) call subfunction 3.
* There is a pair function for get pixel on the background image -
subfunction 2 of function 39.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_PIXEL_BG (2)
======================================================================
=========== Function 15, subfunction 3 - redraw background. ==========
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 3 - subfunction number
Returned value:
* function does not return value
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_REDRAW_BG (3)
======================================================================
== Function 15, subfunction 4 - set drawing mode for the background. =
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 4 - subfunction number
* ecx = drawing mode:
* 1 = tile
* 2 = stretch
Returned value:
* function does not return value
Remarks:
* For update of the screen (after completion of a series of commands
working with a background) call subfunction 3.
* There is a pair function for get drawing mode of the background -
subfunction 4 of function 39.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_MODE_BG (4)
======================================================================
===================== Function 15, subfunction 5 =====================
============ Put block of pixels on the background image. ============
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 5 - subfunction number
* ecx = pointer to the data in the format BBGGRRBBGGRR...
* edx = offset in data of the background image
* esi = size of data in bytes = 3 * number of pixels
Returned value:
* function does not return value
Remarks:
* Offset and size are not checked for correctness.
* Color of each pixel is stored as 3-bytes value BBGGRR.
* Pixels of the background image are written sequentially
from left to right, from up to down.
* Offset of pixel with coordinates (x,y) is (x+y*xsize)*3.
* For update of the screen (after completion of a series of commands
working with a background) call subfunction 3.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_IMAGE_BG (5)
======================================================================
===================== Function 15, subfunction 6 =====================
======== Map background data to the address space of process. ========
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 6 - subfunction number
Returned value:
* eax = pointer to background data, 0 if error
Remarks:
* Mapped data are available for read and write.
* Size of background data is 3*xsize*ysize. The system blocks
changes of background sizes while process works with mapped data.
* Color of each pixel is stored as 3-bytes value BBGGRR.
* Pixels of the background image are written sequentially
from left to right, from up to down.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_MAP_BG (6)
======================================================================
===== Function 15, subfunction 7 - close mapped background data. =====
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 7 - subfunction number
* ecx = pointer to mapped data
Returned value:
* eax = 1 - success, 0 - error
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_UNMAP_BG (7)
======================================================================
===================== Function 15, subfunction 8 =====================
============= Get coordinates of last draw the background ============
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 8 - subfunction number
Returned value:
* eax = [left]*65536 + [right]
* ebx = [top]*65536 + [bottom]
Remarks:
* (left,top) are coordinates of the left upper corner,
(right,bottom) are coordinates of the right lower one.
* For receiving more reliable information, call the function
immediately after the event:
5 = kernel finished redrawing of the desktop background
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_LAST_DRAW (8)
======================================================================
===================== Function 15, subfunction 9 =====================
============= Redraws a rectangular part of the background ===========
======================================================================
Parameters:
* eax = 15 - function number
* ebx = 9 - subfunction number
* ecx = [left]*65536 + [right]
* edx = [top]*65536 + [bottom]
Returned value:
* function does not return value
Remarks:
* (left,top) are coordinates of the left upper corner,
(right,bottom) are coordinates of the right lower one.
* If parameters are set incorrectly then background is not redrawn.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_SET (15)
ebx - SSF_REDRAW_RECT (9)
======================================================================
=============== Function 16 - save ramdisk on a floppy. ==============
======================================================================
Parameters:
* eax = 16 - function number
* ebx = 1 or ebx = 2 - on which floppy save
Returned value:
* eax = 0 - success
* eax = 1 - error
 
---------------------- Constants for registers: ----------------------
eax - SF_RD_TO_FLOPPY (16)
======================================================================
======= Function 17 - get the identifier of the pressed button. ======
======================================================================
Takes away the code of the pressed button from the buffer.
Parameters:
* eax = 17 - function number
Returned value:
* if the buffer is empty, function returns eax=1
* if the buffer is not empty:
* high 24 bits of eax contain button identifier (in particular,
ah contains low byte of the identifier; if all buttons have
the identifier less than 256, ah is enough to distinguish)
* al = 0 - the button was pressed with left mouse button
* al = bit corresponding to used mouse button otherwise
Remarks:
* "Buffer" keeps only one button, at pressing the new button the
information about old is lost.
* The call of this function by an application with inactive window
will return answer "buffer is empty".
* Returned value for al corresponds to the state of mouse buttons
as in subfunction 2 of function 37 at the beginning
of button press, excluding lower bit, which is cleared.
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_BUTTON (17)
======================================================================
===================== Function 18, subfunction 1 =====================
============= Make deactive the window of the given thread. ==========
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 1 - subfunction number
* ecx = number of the thread slot
Returned value:
* function does not return value
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_UNFOCUS_WINDOW (1)
======================================================================
= Function 18, subfunction 2 - terminate process/thread by the slot. =
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 2 - subfunction number
* ecx = number of the slot of process/thread
Returned value:
* function does not return value
Remarks:
* It is impossible to terminate system thread OS/IDLE (with
number of the slot 1),
it is possible to terminate any normal process/thread.
* See also subfunction 18 - terminate
process/thread by the identifier.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_TERMINATE_THREAD (2)
======================================================================
===================== Function 18, subfunction 3 =====================
============= Make active the window of the given thread. ============
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 3 - subfunction number
* ecx = number of the thread slot
Returned value:
* function does not return value
Remarks:
* If correct, but nonexistent slot is given,
some window is made active.
* To find out, which window is active, use subfunction 7.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_FOCUS_WINDOW (3)
======================================================================
===================== Function 18, subfunction 4 =====================
=========== Get counter of idle time units per one second. ===========
======================================================================
Idle time units are units, in which the processor stands idle
in waiting for interrupt (in the command 'hlt').
 
Parameters:
* eax = 18 - function number
* ebx = 4 - subfunction number
Returned value:
* eax = value of the counter of idle time units per one second
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_IDLE_COUNT (4)
======================================================================
========== Function 18, subfunction 5 - get CPU clock rate. ==========
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 5 - subfunction number
Returned value:
* eax = clock rate (modulo 2^32 clock ticks = 4GHz)
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_CPU_FREQUENCY (5)
======================================================================
Function 18, subfunction 6 - save ramdisk to the file on hard drive.
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 6 - subfunction number
* ecx = pointer to the full path to file
(for example, "/hd0/1/kolibri/kolibri.img")
Returned value:
* eax = 0 - success
* else eax = error code of the file system
Remarks:
* All folders in the given path must exist, otherwise function
returns value 5, "file not found".
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_RD_TO_HDD (6)
======================================================================
=========== Function 18, subfunction 7 - get active window. ==========
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 7 - subfunction number
Returned value:
* eax = number of the active window
(number of the slot of the thread with active window)
Remarks:
* Active window is at the top of the window stack and receives
messages on all keyboard input.
* To make a window active, use subfunction 3.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_ACTIVE_WINDOW (7)
======================================================================
== Function 18, subfunction 8 - disable/enable the internal speaker. =
======================================================================
If speaker sound is disabled, all calls to subfunction 55 of
function 55 are ignored. If speaker sound is enabled,
they are routed on builtin speaker.
 
------------------- Subsubfunction 1 - get status. -------------------
Parameters:
* eax = 18 - function number
* ebx = 8 - subfunction number
* ecx = 1 - number of the subsubfunction
Returned value:
* eax = 0 - speaker sound is enabled; 1 - disabled
 
----------------- Subsubfunction 2 - toggle status. ------------------
Toggles states of disable/enable.
Parameters:
* eax = 18 - function number
* ebx = 8 - subfunction number
* ecx = 2 - number of the subsubfunction
Returned value:
* function does not return value
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_SPEAKER (8)
ecx - SSSF_GET_STATE (1), SSSF_TOGGLE (2)
======================================================================
== Function 18, subfunction 9 - system shutdown with the parameter. ==
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 9 - subfunction number
* ecx = parameter:
* 2 = turn off computer
* 3 = reboot computer
* 4 = restart the kernel from the file 'kernel.mnt' on ramdisk
Returned value:
* at incorrect ecx the registers do not change (i.e. eax=18)
* by correct call function always returns eax=0
as the tag of success
Remarks:
* Do not rely on returned value by incorrect call, it can be
changed in future versions of the kernel.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_SHUTDOWN (9)
======================================================================
======= Function 18, subfunction 10 - minimize topmost window. =======
======================================================================
Minimizes the topmost (active) window.
Parameters:
* eax = 18 - function number
* ebx = 10 - subfunction number
Returned value:
* function does not return value
Remarks:
* The minimized window from the point of view of function 9
keeps position and sizes.
* Restoring of an application window occurs at its activation by
subfunction 3.
* Usually there is no necessity to minimize/restore a window
explicitly: minimization of a window is carried out by the system
at pressing the minimization button (for skinned windows
it is defined automatically by function 0,
for other windows it can be defined manually by function 8),
restore of a window is done by the application '@taskbar'.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_MINIMIZE_WINDOW (10)
======================================================================
Function 18, subfunction 11 - get information on the disk subsystem.
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 11 - subfunction number
* ecx = type of the table:
* 1 = short version, 16 bytes
* edx = pointer to the buffer (in the application) for the table
Returned value:
* function does not return value
Format of the table: short version:
* +0: byte: information about FDD's (drives for floppies),
AAAABBBB, where AAAA gives type of the first drive, BBBB -
of the second regarding to the following list:
* 0 = there is no drive
* 1 = 360Kb, 5.25''
* 2 = 1.2Mb, 5.25''
* 3 = 720Kb, 3.5''
* 4 = 1.44Mb, 3.5''
* 5 = 2.88Mb, 3.5'' (such drives are not used anymore)
For example, for the standard configuration from one 1.44-drive
here will be 40h, and for the case 1.2Mb on A: and 1.44Mb on B:
the value is 24h.
 
First IDE controller:
* +1: byte: information about hard disks and CD-drives, AABBCCDD,
where AA corresponds to the controller IDE0, ..., DD - IDE3:
* 0 = device not found
* 1 = hard drive
* 2 = CD-drive
For example, in the case HD on IDE0 and CD on IDE2
this field contains 48h.
* +2: 4 db: number of the retrieved partitions on hard disks
at accordingly IDE0,...,IDE3.
 
Second IDE controller:
* +6: byte: information about hard disks and CD-drives, AABBCCDD,
where AA corresponds to the controller IDE4, ..., DD - IDE7:
* 0 = device not found
* 1 = hard drive
* 2 = CD-drive
For example, in the case HD on IDE4 and CD on IDE6
this field contains 48h.
* +7: 4 db: number of the retrieved partitions on hard disks
at accordingly IDE4,...,IDE7.
 
Third IDE controller:
* +11: byte: information about hard disks and CD-drives, AABBCCDD,
where AA corresponds to the controller IDE8, ..., DD - IDE11:
* 0 = device not found
* 1 = hard drive
* 2 = CD-drive
For example, in the case HD on IDE8 and CD on IDE10
this field contains 48h.
* +12: 4 db: number of the retrieved partitions on hard disks
at accordingly IDE8,...,IDE11.
 
If the hard disk on IDEx is absent, appropriate byte is zero,
otherwise it shows number of the recognized partitions, which
can be not presented (if the drive is not formatted or if
the file system is not supported). Current version of the kernel
supports only FAT12/16/32, NTFS, ext2/3/4 and XFS for hard disks.
 
Remarks:
* The table can be used for obtaining the information about
available devices.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_INFO_DISC_SYS (11)
======================================================================
========== Function 18, subfunction 13 - get kernel version. =========
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 13 - subfunction number
* ecx = pointer to the buffer (not less than 16 bytes), where
the information will be placed
Returned value:
* function does not return value
but if pointer in ecx is illegal, for example,
[ecx, ecx + 9) region intersects with kernel memory,
then function returns -1
Remarks:
* At the moment only the part of the buffer by a size
9 bytes is used. Nevertheless it is recommended to use
16 byte buffer for the future compatibility, in the future
some fields can be added.
Structure of the buffer:
db a,b,c,d for version a.b.c.d
db 0: reserved
dd REV - kernel SVN revision number
For Kolibri 0.7.7.0+ kernel:
db 0,7,7,0
db 0
dd 1675
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_KERNEL_VERSION (13)
======================================================================
======= Function 18, subfunction 14 - wait for screen retrace. =======
======================================================================
Waits for the beginning of retrace of the scanning ray of the screen
monitor.
Parameters:
* eax = 18 - function number
* ebx = 14 - subfunction number
Returned value:
* eax = 0 as the tag of success
Remarks:
* Function is intended only for active high-efficiency graphics
applications; is used for smooth output of a graphics.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_WAIT_RETRACE (14)
======================================================================
== Function 18, subfunction 15 - center mouse cursor on the screen. ==
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 15 - subfunction number
Returned value:
* eax = 0 as the tag of success
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_CURSOR_CENTER (15)
======================================================================
========= Function 18, subfunction 16 - get size of free RAM. ========
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 16 - subfunction number
Returned value:
* eax = size of free memory in kilobytes
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_FREE_RAM (16)
======================================================================
======== Function 18, subfunction 17 - get full amount of RAM. =======
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 17 - subfunction number
Returned value:
* eax = total size of existing memory in kilobytes
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_TOTAL_RAM (17)
======================================================================
===================== Function 18, subfunction 18 ====================
============= Terminate process/thread by the identifier. ============
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 18 - subfunction number
* ecx = identifier of process/thread (PID/TID)
Returned value:
* eax = 0 - success
* eax = -1 - error (process is not found or is system)
Remarks:
* It is impossible to terminate system thread OS/IDLE (identifier
1), it is possible to terminate any normal process/thread.
* See also subfunction 2 - terminate
process/thread by given slot.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_TERMINATE_THREAD_ID (18)
======================================================================
======== Function 18, subfunction 19 - get/set mouse features. =======
======================================================================
 
---------------- Subsubfunction 0 - get mouse speed. -----------------
Parameters:
* eax = 18 - function number
* ebx = 19 - subfunction number
* ecx = 0 - subsubfunction number
Returned value:
* eax = current speed divider
 
---------------- Subsubfunction 1 - set mouse speed. -----------------
Parameters:
* eax = 18 - function number
* ebx = 19 - subfunction number
* ecx = 1 - subsubfunction number
* edx = new value for speed divider
Returned value:
* function does not return value
 
Remark: recommended speed divider = 4
 
-------------- Subsubfunction 2 - get mouse sensitivity --------------
Parameters:
* eax = 18 - function number
* ebx = 19 - subfunction number
* ecx = 2 - subsubfunction number
Returned value:
* eax = current sensitivity
 
-------------- Subsubfunction 3 - set mouse sensitivity --------------
Parameters:
* eax = 18 - function number
* ebx = 19 - subfunction number
* ecx = 3 - subsubfunction number
* edx = new value for sensitivity
Returned value:
* function does not return value
 
Remark: recommended sensitivity = 3
 
----------- Subsubfunction 4 - set mouse pointer position. -----------
Parameters:
* eax = 18 - function number
* ebx = 19 - subfunction number
* ecx = 4 - subsubfunction number
* edx = [coordinate on axis x]*65536 + [coordinate on axis y]
Returned value:
* function does not return value
 
-------- Subsubfunction 5 - simulate state of mouse buttons. ---------
Parameters:
* eax = 18 - function number
* ebx = 19 - subfunction number
* ecx = 5 - subsubfunction number
* edx = information about emulated state of mouse buttons:
(same as return value in subfunction 2 of function 37)
* bit 0 is set = left button is pressed
* bit 1 is set = right button is pressed
* bit 2 is set = middle button is pressed
* bit 3 is set = 4th button is pressed
* bit 4 is set = 5th button is pressed
Returned value:
* function does not return value
 
-------------- Subsubfunction 6 - get doubleclick delay. -------------
Parameters:
* eax = 18 - function number
* ebx = 19 - subfunction number
* ecx = 6 - subsubfunction number
Returned value:
* eax = current doubleclick delay (100 = 1 second)
 
-------------- Subsubfunction 7 - set doubleclick delay. -------------
Parameters:
* eax = 18 - function number
* ebx = 19 - subfunction number
* ecx = 7 - subsubfunction number
* dl = new value for doubleclick delay (100 = 1 second)
Returned value:
* function does not return value
 
Remark: mouse settings can be modified in the application mouse_cfg.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_MOUSE_SETTINGS (19)
ecx - SSSF_GET_SPEED (0), SSSF_SET_SPEED (1), SSSF_GET_SPEEDUP (2),
SSSF_SET_SPEEDUP (3), SSSF_SET_POS (4), SSSF_SET_BUTTON (5),
SSSF_GET_DOUBLE_CLICK_DELAY (6), SSSF_SET_DOUBLE_CLICK_DELAY (7)
======================================================================
======== Function 18, subfunction 20 - get information on RAM. =======
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 20 - subfunction number
* ecx = pointer to the buffer for information (36 bytes)
Returned value:
* eax = total size of existing RAM in pages
or -1 if error has occurred
* buffer pointed to by ecx contains the following information:
* +0: dword: total size of existing RAM in pages
* +4: dword: size of free RAM in pages
* +8: dword: number of page faults (exceptions #PF)
in applications
* +12: dword: size of kernel heap in bytes
* +16: dword: free in kernel heap in bytes
* +20: dword: total number of memory blocks in kernel heap
* +24: dword: number of free memory blocks in kernel heap
* +28: dword: size of maximum free block in kernel heap
(reserved)
* +32: dword: size of maximum allocated block in kernel heap
(reserved)
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_RAM_INFO (20)
======================================================================
===================== Function 18, subfunction 21 ====================
======== Get slot number of process/thread by the identifier. ========
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 21 - subfunction number
* ecx = identifier of process/thread (PID/TID)
Returned value:
* eax = 0 - error (invalid identifier)
* otherwise eax = slot number
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_GET_THREAD_SLOT (21)
======================================================================
===================== Function 18, subfunction 22 ====================
============== Operations with window of another thread. =============
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 22 - subfunction number
* ecx = operation type:
* 0 = minimize window of the thread with given slot number
* 1 = minimize window of the thread with given identifier
* 2 = restore window of the thread with given slot number
* 3 = restore window of the thread with given identifier
* edx = parameter (slot number or PID/TID)
Returned value:
* eax = 0 - success
* eax = -1 - error (invalid identifier)
Remarks:
* The thread can minimize its window with subfunction 10.
* One can restore and activate window simultaneously with
subfunction 3 (which requires slot number).
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_FOREIGN_WINDOW (22)
ecx - SSSF_MINIMIZE (0), SSSF_MINIMIZE_ID (1), SSSF_RESTORE (2),
SSSF_RESTORE_ID (3)
======================================================================
======== Function 18, subfunction 23 - minimize all windows. ==========
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 23 - subfunction number
Returned value:
* eax = 0 - all windows have been minimized before a function call
* eax = N - number of windows minimized from function
Remarks:
* Window of special thread (name begin to symbol @) is not minimize.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_MINIMIZE_ALL (23)
======================================================================
======= Function 18, subfunction 24 - set limits of screen. ==========
======================================================================
Parameters:
* eax = 18 - function number
* ebx = 24 - subfunction number
* ecx = new X size
* edx = new Y size
Returned value:
* function does not return value
Remarks:
* The function does not change the physical size of the video mode.
It is designed for non-standard displays which display the image
partially.
* The sizes specified in the function should not exceed the sizes
of the current video mode, otherwise the function will not change
anything.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_SET_SCREEN_LIMITS (24)
======================================================================
===================== Function 18, subfunction 25 ====================
===== Control position of the window relative to other windows. ======
======================================================================
 
------------- Subsubfunction 1 - get position -----------------------
Parameters:
* eax = 18 - function number
* ebx = 25 - subfunction number
* ecx = 1 - subsubfunction number
* edx = -1(for current window) or PID application
Returned value:
* eax = one of the constants window position
 
------------- Subsubfunction 2 - set position -----------------------
Parameters:
* eax = 18 - function number
* ebx = 25 - subfunction number
* ecx = 2 - subsubfunction number
* edx = -1(for current window) or PID application
* esi = new window position (one of the constants below)
Returned value:
* eax = 0 - error
* eax = 1 - success
 
Constant position of the window relative to other windows:
ZPOS_DESKTOP = -2 - on the background
ZPOS_ALWAYS_BACK = -1 - behind all the windows
ZPOS_NORMAL = 0 - normal
ZPOS_ALWAYS_TOP = 1 - on top of all windows
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM (18)
ebx - SSF_WINDOW_BEHAVIOR (25)
ecx - SSSF_GET_WB (1), SSSF_SET_WB (2)
======================================================================
==================== Function 20 - MIDI interface. ===================
======================================================================
 
----------------------- Subfunction 1 - reset ------------------------
Parameters:
* eax = 20 - function number
* ebx = 1 - subfunction number
 
-------------------- Subfunction 2 - output byte ---------------------
Parameters:
* eax = 20 - function number
* ebx = 2 - subfunction number
* cl = byte for output
Returned value (is the same for both subfunctions):
* eax = 0 - success
* eax = 1 - base port is not defined
Remarks:
* Previously the base port must be defined by
subfunction 1 of function 21.
 
---------------------- Constants for registers: ----------------------
eax - SF_MIDI (20)
ebx - SSF_RESET (1), SSF_OUTPUT (2)
======================================================================
======== Function 21, subfunction 1 - set MPU MIDI base port. ========
======================================================================
Parameters:
* eax = 21 - function number
* ebx = 1 - subfunction number
* ecx = number of base port
Returned value
* eax = 0 - success
* eax = -1 - erratic number of a port
Remarks:
* Number of a port must satisfy to conditions 0x100<=ecx<=0xFFFF.
* The installation of base is necessary for function 20.
* To get base port use subfunction 1 of function 26.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_MPU_MIDI_BASE (1)
======================================================================
========== Function 21, subfunction 2 - set keyboard layout. =========
======================================================================
Keyboard layout is used to convert keyboard scancodes to ASCII-codes,
which will be read by function 2.
Parameters:
* eax = 21 - function number
* ebx = 2 - subfunction number
* ecx = which layout to set:
* 1 = normal layout
* 2 = layout at pressed Shift
* 3 = layout at pressed Alt
* edx = pointer to layout - table of length 128 bytes
Or:
* ecx = 9
* dx = country identifier (1=eng, 2=fi, 3=ger, 4=rus)
Returned value:
* eax = 0 - success
* eax = 1 - incorrect parameter
Remarks:
* If Alt is pressed, the layout with Alt is used;
if Alt is not pressed, but Shift is pressed,
the layout with Shift is used;
if Alt and Shift are not pressed, but Ctrl is pressed, the normal
layout is used and then from the code is subtracted 0x60;
if no control key is pressed, the normal layout is used.
* To get layout and country identifier use
subfunction 2 of function 26.
* Country identifier is global system variable, which is not used
by the kernel itself; however the application '@taskbar' displays
the corresponding icon.
* The application @taskbar switches layouts on user request.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_KEYBOARD_LAYOUT (2)
======================================================================
========== Function 21, subfunction 5 - set system language. =========
======================================================================
Parameters:
* eax = 21 - function number
* ebx = 5 - subfunction number
* ecx = system language (1=eng, 2=fi, 3=ger, 4=rus)
Returned value:
* eax = 0
Remarks:
* System language is global system variable and is not used
by the kernel itself, however application @taskbar draws the
appropriate icon.
* Function does not check for correctness, as the kernel does not
use this variable.
* To get system language use subfunction 5 of function 26.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_SYS_LANG (5)
======================================================================
Function 21, subfunction 11 - enable/disable low-level access to HD.
======================================================================
Parameters:
* eax = 21 - function number
* ebx = 11 - subfunction number
* ecx = 0/1 - disable/enable
Returned value:
* eax = 0
Remarks:
* Is used in LBA-read (subfunction 8 of function 58).
* The current implementation uses only low bit of ecx.
* To get current status use subfunction 11 of function 26.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_ACCESS_HD_LBA (11)
======================================================================
Function 21, subfunction 12 - enable/disable low-level access to PCI.
======================================================================
Parameters:
* eax = 21 - function number
* ebx = 12 - subfunction number
* ecx = 0/1 - disable/enable
Returned value:
* eax = 0
Remarks:
* Is used in operations with PCI bus (function 62).
* The current implementation uses only low bit of ecx.
* To get current status use subfunction 12 of function 26.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_SET (21)
ebx - SSF_ACCESS_PCI (12)
======================================================================
================= Function 22 - set system date/time. ================
======================================================================
Parameters:
* eax = 22 - function number
* ebx = 0 - set time
* ecx = 0x00SSMMHH - time in the binary-decimal code (BCD):
* HH=hour 00..23
* MM=minute 00..59
* SS=second 00..59
* ebx = 1 - set date
* ecx = 0x00DDMMYY - date in the binary-decimal code (BCD):
* DD=day 01..31
* MM=month 01..12
* YY=year 00..99
* ebx = 2 - set day of week
* ecx = 1 for Sunday, ..., 7 for Saturday
* ebx = 3 - set alarm clock
* ecx = 0x00SSMMHH
Returned value:
* eax = 0 - success
* eax = 1 - incorrect parameter
* eax = 2 - CMOS-battery was unloaded
Remarks:
* Value of installation of day of week seems to be doubtful,
as it a little where is used
(day of week can be calculated by date).
* Alarm clock can be set on operation in the given time every day.
But there is no existing system function to disable it.
* Operation of alarm clock consists in generation IRQ8.
* Generally CMOS supports for alarm clock set of value 0xFF
as one of parameters and it means that the appropriate parameter
is ignored. But current implementation does not allow this
(will return 1).
* Alarm clock is a global system resource; the set of
an alarm clock cancels automatically the previous set.
However, at moment no program uses it.
 
---------------------- Constants for registers: ----------------------
eax - SF_SET_TIME_DATE (22)
======================================================================
============= Function 23 - wait for event with timeout. =============
======================================================================
If the message queue is empty, waits for new message in the queue,
but no more than given time. Then reads out a message from the queue.
 
Parameters:
* eax = 23 - function number
* ebx = timeout (in 1/100 of second)
Returned value:
* eax = 0 - the message queue is empty
* otherwise eax = event (see the list of events)
Remarks:
* Only those events are taken into account, which enter into
the mask set by function 40. By default it is
redraw, key and button events.
* To check for presence of a message in the queue use function 11.
To wait without timeout use function 10.
* Transmission ebx=0 results in immediate returning eax=0.
* Current implementation returns immediately with eax=0,
if the addition of ebx with the current value of time counter
makes 32-bit overflow.
 
---------------------- Constants for registers: ----------------------
eax - SF_WAIT_EVENT_TIMEOUT (23)
======================================================================
======= Function 24, subfunction 4 - eject tray of disk drive. =======
======================================================================
Parameters:
* eax = 24 - function number
* ebx = 4 - subfunction number
* ecx = position of CD/DVD-drive
from 0=Primary Master to 3=Secondary Slave for first IDE contr.
from 4=Primary Master to 7=Secondary Slave for second IDE contr.
from 8=Primary Master to 11=Secondary Slave for third IDE contr.
Returned value:
* function does not return value
Remarks:
* The function is supported only for ATAPI devices (CD and DVD).
* When the tray is being ejected,
manual control of tray is unlocked.
* When the tray is being ejected, the code clears the cache for
corresponding device.
* An example of usage of the function is the application CD_tray.
 
---------------------- Constants for registers: ----------------------
eax - SF_CD (24)
ebx - SSF_EJECT_TRAY (4), SSF_INSERT_TRAY (5)
======================================================================
======== Function 24, subfunction 5 - load tray of disk drive. =======
======================================================================
Parameters:
* eax = 24 - function number
* ebx = 5 - subfunction number
* ecx = position of CD/DVD-drive
from 0=Primary Master to 3=Secondary Slave for first IDE contr.
from 4=Primary Master to 7=Secondary Slave for second IDE contr.
from 8=Primary Master to 11=Secondary Slave for third IDE contr.
Returned value:
* function does not return value
Remarks:
* The function is supported only for ATAPI devices (CD and DVD).
* An example of usage of the function is the application CD_tray.
 
---------------------- Constants for registers: ----------------------
eax - SF_CD (24)
ebx - SSF_EJECT_TRAY (4), SSF_INSERT_TRAY (5)
======================================================================
======= Function 25 - put image area on the background layer. ========
======================================================================
Parameters:
* eax = 25 - function number
* ebx = pointer to the previously allocated memory area,
where placed the source images in a format BBGGRRTTBBGGRRTT...
* ecx = [size on axis x]*65536 + [size on axis y]
* edx = [coordinate on axis x]*65536 + [coordinate on axis y]
Returned value:
* function does not return value
Remarks:
* Coordinates of the image are coordinates of the upper left corner
of the image relative to the screen.
* Size of the image in bytes is 4*xsize*ysize
* TT - byte pointer of transparency, at current version:
1 to FF - opaque, 0 - transparent.
* The function places the image directly to LFB. It is not for
background image f.15. Options f.15 to f.25 does not make sense.
 
---------------------- Constants for registers: ----------------------
eax - SF_SCREEN_PUT_IMAGE (25)
======================================================================
======== Function 26, subfunction 1 - get MPU MIDI base port. ========
======================================================================
Parameters:
* eax = 26 - function number
* ebx = 1 - subfunction number
Returned value:
* eax = port number
Parameters:
* To set base port use subfunction 1 of function 21.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_MPU_MIDI_BASE (1)
======================================================================
========== Function 26, subfunction 2 - get keyboard layout. =========
======================================================================
The keyboard layout is used to convert keyboard scancodes to
ASCII-codes for function 2.
Parameters:
* eax = 26 - function number
* ebx = 2 - subfunction number
* ecx = what layout to get:
* 1 = normal layout
* 2 = layout with pressed Shift
* 3 = layout with pressed Alt
* edx = pointer to the 128-bytes buffer, where the layout will be
copied
Returned value:
* function does not return value
but if pointer in edx is illegal, for example,
[edx, edx + 128) region intersects with kernel memory,
then function returns -1
Or:
* eax = 26 - function number
* ebx = 2 - subfunction number
* ecx = 9
Returned value:
* eax = country identifier (1=eng, 2=fi, 3=ger, 4=rus)
Remarks:
* If Alt is pressed, the layout with Alt is used;
if Alt is not pressed, but Shift is pressed,
the layout with Shift is used;
if Alt and Shift are not pressed, but Ctrl is pressed, the normal
layout is used and then from the code is subtracted 0x60;
if no control key is pressed, the normal layout is used.
* To set layout and country identifier use
subfunction 2 of function 21.
* Country identifier is global system variable, which is not used
by the kernel itself; however the application '@taskbar' displays
the corresponding icon (using this function).
* The application @taskbar switches layouts on user request.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_KEYBOARD_LAYOUT (2)
======================================================================
========== Function 26, subfunction 5 - get system language. =========
======================================================================
Parameters:
* eax = 26 - function number
* ebx = 5 - subfunction number
Returned value:
* eax = system language (1=eng, 2=fi, 3=ger, 4=rus)
Remarks:
* System language is global system variable and is not used
by the kernel itself, however application @taskbar draws the
appropriate icon (using this function).
* To set system language use subfunction 5 of function 21.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_SYS_LANG (5)
======================================================================
=== Function 26, subfunction 9 - get the value of the time counter. ==
======================================================================
Parameters:
* eax = 26 - function number
* ebx = 9 - subfunction number
Returned value:
* eax = number of 1/100s of second, past from the system boot time
Remarks:
* Counter takes modulo 2^32, that correspond to a little more
than 497 days.
* To get system time use function 3.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_TIME_COUNT (9)
======================================================================
===================== Function 26, subfunction 10 ====================
========== Get the value of the high precision time counter. =========
======================================================================
Parameters:
* eax = 26 - function number
* ebx = 10 - subfunction number
Returned value:
* eax = number of nanoseconds since system boot time (lower DWORD)
* edx = number of nanoseconds since system boot time (high DWORD)
Remarks:
* The counter is based on HPET, if HPET is not available, resolution
will be reduced to 10 000 000 nanoseconds.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_TIME_COUNT_PRO (10)
======================================================================
===================== Function 26, subfunction 11 ====================
========== Find out whether low-level HD access is enabled. ==========
======================================================================
Parameters:
* eax = 26 - function number
* ebx = 11 - subfunction number
Returned value:
* eax = 0/1 - disabled/enabled
Remarks:
* Is used in LBA read (subfunction 8 of function 58).
* To set current state use subfunction 11 of function 21.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_ACCESS_HD_LBA (11)
======================================================================
===================== Function 26, subfunction 12 ====================
========== Find out whether low-level PCI access is enabled. =========
======================================================================
Parameters:
* eax = 26 - function number
* ebx = 12 - subfunction number
Returned value:
* eax = 0/1 - disabled/enabled
Remarks:
* Is used by operations with PCI bus (function 62).
* The current implementation uses only low bit of ecx.
* To set the current state use subfunction 12 of function 21.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYSTEM_GET (26)
ebx - SSF_ACCESS_PCI (12)
======================================================================
=================== Function 29 - get system date. ===================
======================================================================
Parameters:
* eax = 29 - function number
Returned value:
* eax = 0x00DDMMYY, where
(binary-decimal coding, BCD, is used)
* YY = two low digits of year (00..99)
* MM = month (01..12)
* DD = day (01..31)
Remarks:
* To set system date use function 22.
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_SYS_DATE (29)
======================================================================
============= Function 30 - work with the current folder. ============
======================================================================
--------- Subfunction 1 - set current folder for the thread. ---------
Parameters:
* eax = 30 - function number
* ebx = 1 - subfunction number
* ecx = pointer to string with the path to new current folder,
rules of path forming can be found in function 70 description.
Returned value:
* function does not return value
----------------------------------------------------------------------
--------- Subfunction 2 - get current folder for the thread. ---------
Parameters:
* eax = 30 - function number
* ebx = 2 - subfunction number
* ecx = pointer to buffer
* edx = size of buffer
Returned value:
* eax = size of the string (including terminating 0)
Remarks:
* If the buffer is too small to hold all path, only part of the string
will be copied and terminated with 0.
* By default, current folder for the thread is "/sys".
* At process/thread creation the current folder will be inherited
from the parent.
----------------------------------------------------------------------
--- Subfunction 3 - install the add.system directory for the kernel --
Parameters:
* eax = 30 - function number
* ebx = 3 - subfunction number
* ecx = pointer to a block of data:
key rb 64
path rb 64
Example:
align 64
key db 'kolibrios',0 ; key must be in lower case
align 64
path db 'HD0/1',0
 
Returned value:
* function does not return value
Remarks:
* The function can be called only 1 time for 1 session of the OS.
* On input the symbolic key is not changing by encoding.
----------------------------------------------------------------------
---- Subfunction 4 - set current folder, specifying the encoding. ----
Parameters:
* eax = 30 - function number
* ebx = 4 - subfunction number
* ecx = pointer to string with the path to new current folder
* edx = string encoding, details can be found in function 80 description.
Returned value:
* function does not return value
----------------------------------------------------------------------
---- Subfunction 5 - get current folder, specifying the encoding. ----
Parameters:
* eax = 30 - function number
* ebx = 5 - subfunction number
* ecx = pointer to buffer
* edx = size of buffer
* esi = string encoding
Returned value:
* eax = size of the string in bytes (including terminating 0)
Remarks:
* If the buffer is too small to hold all path, only part of the string
will be copied and terminated with 0.
* By default, current folder for the thread is "/sys".
* At process/thread creation the current folder will be inherited
from the parent.
 
---------------------- Constants for registers: ----------------------
eax - SF_CURRENT_FOLDER (30)
ebx - SSF_SET_CF (1), SSF_GET_CF (2), SSF_ADD_SYS_FOLDER (3)
======================================================================
========= Function 34 - who owner the pixel on the screen. ===========
======================================================================
Parameters:
* eax = 34 - function number
* ebx = x-coordinate (relative to the display)
* ecx = y-coordinate (relative to the display)
 
Returned value:
* eax = 0x000000XX - owner of pixel the slot window N
If incorrect values ebx and ecx then function returns 0
* The function takes the value from the area [_WinMapAddress]
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_PIXEL_OWNER (34)
======================================================================
======= Function 35 - read the color of a pixel on the screen. =======
======================================================================
Parameters:
* eax = 35
* ebx = y*xsize+x, where
* (x,y) = coordinates of a pixel (beginning from 0)
* xsize = horizontal screen size
Returned value:
* eax = color 0x00RRGGBB
Remarks:
* To get screen sizes use function 14. Pay attention,
that it subtracts 1 from both sizes.
* There is also direct access (without any system calls)
to videomemory through the selector gs. To get parameters of
the current videomode, use function 61.
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_PIXEL (35)
======================================================================
=================== Function 36 - read screen area. ==================
======================================================================
Paramters:
* eax = 36 - function number
* ebx = pointer to the previously allocated memory area,
where will be placed the image in the format BBGGRRBBGGRR...
* ecx = [size on axis x]*65536 + [size on axis y]
* edx = [coordinate on axis x]*65536 + [coordinate on axis y]
Returned value:
* function does not return value
Remarks:
* Coordinates of the image are coordinates of the upper left corner
of the image relative to the screen.
* Size of the image in bytes is 3*xsize*ysize.
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_IMAGE (36)
======================================================================
=================== Function 37 - work with mouse. ===================
======================================================================
 
---------- Subfunction 0 - screen coordinates of the mouse -----------
Parameters:
* eax = 37 - function number
* ebx = 0 - subfunction number
Returned value:
* eax = x*65536 + y, (x,y)=coordinates of the mouse pointer
(beginning from 0)
 
-- Subfunction 1 - coordinates of the mouse relative to the window ---
Parameters:
* eax = 37 - function number
* ebx = 1 - subfunction number
Returned value:
* eax = x*65536 + y, (x,y)=coordinates of the mouse pointer
relative to the application window (beginning from 0)
Remarks:
* The value is calculated by formula (x-xwnd)*65536 + (y-ywnd).
If y>=ywnd, the low word is non-negative and contains
relative y-coordinate, and the high word - relative x-coordinate
(with correct sign). Otherwise the low word is negative and still
contains relative y-coordinate, and to the high word
1 should be added.
 
------------- Subfunction 2 - states of the mouse buttons ------------
Parameters:
* eax = 37 - function number
* ebx = 2 - subfunction number
Returned value:
* eax = bits 0-4 equal to subfunction 3
 
------- Subfunction 3 - states and events of the mouse buttons -------
Parameters:
* eax = 37 - function number
* ebx = 3 - subfunction number
Returned value:
* eax contains next information:
 
states:
* bit 0 is set = left button is held
* bit 1 is set = right button is held
* bit 2 is set = middle button is held
* bit 3 is set = 4th button is held
* bit 4 is set = 5th button is held
 
events:
* bit 8 is set = left button is pressed
* bit 9 is set = right button is pressed
* bit 10 is set = middle button is pressed
 
* bit 15 is set = vertical scroll is used
 
* bit 16 is set = left button is released
* bit 17 is set = right button is released
* bit 18 is set = middle button is released
 
* bit 23 is set = horizontal scroll is used
 
* bit 24 is set = doubleclick by left button
 
-------------------- Subfunction 4 - load cursor ---------------------
Parameters:
* eax = 37 - function number
* ebx = 4 - subfunction number
* dx = data source:
* dx = LOAD_FROM_FILE = 0 - data in a file
* ecx = pointer to full path to the cursor file
* the file must be in the format .cur, which is standard for
MS Windows, at that of the size 32*32 pixels
* dx = LOAD_FROM_MEM = 1 - data of file are already loaded in memory
* ecx = pointer to data of the cursor file
* the data format is the same as in the previous case
* dx = LOAD_INDIRECT = 2 - data in memory
* ecx = pointer to cursor image in the format ARGB 32*32 pixels
* edx = 0xXXYY0002, where
* XX = x-coordinate of cursor hotspot
* YY = y-coordinate
* 0 <= XX, YY <= 31
Returned value:
* eax = 0 - failed
* otherwise eax = cursor handle
 
--------------------- Subfunction 5 - set cursor ---------------------
Sets new cursor for the window of the current thread.
Parameters:
* eax = 37 - function number
* ebx = 5 - subfunction number
* ecx = cursor handle
Returned value:
* eax = handle of previous cursor
Remarks:
* If the handle is incorrect, the function restores the default
cursor (standard arrow). In particular, ecx=0 restores it.
 
------------------- Subfunction 6 - delete cursor --------------------
Parameters:
* eax = 37 - function number
* ebx = 6 - subfunction number
* ecx = cursor handle
Returned value:
* eax destroyed
Remarks:
* The cursor must be loaded previously by the current thread
(with the call to subfunction 4). The function does not delete
system cursors and cursors, loaded by another applications.
* If the active cursor (set by subfunction 5) is deleted,
the system restores the default cursor (standard arrow).
 
------------------ Subfunction 7 - get scroll data -------------------
Parameters:
* eax = 37 - function number
* ebx = 7 - subfunction number
Returned value:
* eax = [horizontal offset]*65536 + [vertical offset]
Remarks:
* Scroll data is available for active window only.
* Values are zeroed after reading.
* Values are signed.
 
-------- Subfunction 8 - load cursor, specifying the encoding --------
Parameters:
* eax = 37 - function number
* ebx = 8 - subfunction number
* ecx = pointer to the cursor file path string
* edx = string encoding, details can be found in function 80 description.
Returned value:
* eax = cursor handle, 0 - failed
 
---------------------- Constants for registers: ----------------------
eax - SF_MOUSE_GET (37)
ebx - SSF_SCREEN_POSITION (0), SSF_WINDOW_POSITION (1),
SSF_BUTTON (2), SSF_BUTTON_EXT (3), SSF_LOAD_CURSOR (4),
SSF_SET_CURSOR (5), SSF_DEL_CURSOR (6), SSF_SCROLL_DATA (7)
======================================================================
====================== Function 38 - draw line. ======================
======================================================================
Parameters:
* eax = 38 - function number
* ebx = [start coordinate on axis x]*65536 +
[end coordinate on axis x]
* ecx = [start coordinate on axis y]*65536 +
[end coordinate on axis y]
* edx = 0x00RRGGBB - color
edx = 0x01xxxxxx - draw inversed line
(low 24 bits are ignored)
Returned value:
* function does not return value
Remarks:
* Coordinates are relative to the window.
* End point is also drawn.
 
---------------------- Constants for registers: ----------------------
eax - SF_DRAW_LINE (38)
======================================================================
== Function 39, subfunction 1 - get a size of the background image. ==
======================================================================
Parameters:
* eax = 39 - function number
* ebx = 1 - subfunction number
Returned value:
* eax = [width]*65536 + [height]
Remarks:
* There is a pair function to set sizes of background image -
subfunction 1 of function 15. After which it is necessary,
of course, anew to define image.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_GET (39)
======================================================================
== Function 39, subfunction 2 - get pixel from the background image. =
======================================================================
Parameters:
* eax = 39 - function number
* ebx = 2 - subfunction number
* ecx = offset
Returned value:
* eax = 0x00RRGGBB - pixel color, if offset is valid
(less than 0x160000-16)
* eax = 2 otherwise
Remarks:
* Do not rely on returned value for invalid offsets, it may be
changed in future kernel versions.
* Offset for pixel with coordinates (x,y)
is calculated as (x+y*xsize)*3.
* There is a pair function to set pixel on the background image -
subfunction 2 of function 15.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_GET (39)
======================================================================
== Function 39, subfunction 4 - get drawing mode for the background. =
======================================================================
Parameters:
* eax = 39 - function number
* ebx = 4 - subfunction number
Returned value:
* eax = 1 - tile
* eax = 2 - stretch
Remarks:
* There is a pair function to set drawing mode -
subfunction 4 of function 15.
 
---------------------- Constants for registers: ----------------------
eax - SF_BACKGROUND_GET (39)
======================================================================
=========== Function 40 - set the mask for expected events. ==========
======================================================================
The mask for expected events affects function working with events
10, 11, 23 - they notify only about events allowed by this mask.
Parameters:
* eax = 40 - function number
* ebx = mask: bit i corresponds to event i+1 (see list of events)
(set bit permits notice on event)
bit 31: mouse active/inactive filter
bit 31 = 0 - inactive window receive mouse events
bit 31 = 1 - inactive window does not receive mouse events
bit 30: cursor position filter
bit 30 = 0 = the window receive mouse events if cursor
outside window
bit 30 = 1 - the window does not receive mouse events if cursor
outside window
Returned value:
* eax = previous value of mask
Remarks:
* Default mask (7=111b) enables notices about redraw,
keys and buttons. This is enough for many applications.
* Events prohibited in the mask are saved anyway, when come;
they are simply not informed with event functions.
* Event functions take into account the mask on moment of
function call, not on moment of event arrival.
 
---------------------- Constants for registers: ----------------------
eax - SF_SET_EVENTS_MASK (40)
======================================================================
================ Function 43 - input/output to a port. ===============
======================================================================
 
------------------------ Output data to port -------------------------
Parameters:
* eax = 43 - function number
* bl = byte for output
* ecx = port number 0xnnnn (from 0 to 0xFFFF)
Returned value:
* eax = 0 - success
* eax = 1 - the thread has not reserved the selected port
 
------------------------ Input data from port ------------------------
Parameters:
* eax = 43 - function number
* ebx is ignored
* ecx = 0x8000nnnn, where nnnn = port number (from 0 to 0xFFFF)
Returned value:
* eax = 0 - success, thus ebx = entered byte
* eax = 1 - the thread has not reserved the selected port
Remarks:
* Previously the thread must reserve the selected port
for itself by function 46.
* Instead of call to this function it is better to use
processor instructions in/out - this is much
faster and a bit shorter and easier.
 
---------------------- Constants for registers: ----------------------
eax - SF_PORT_IN_OUT (43)
======================================================================
====== Function 46 - reserve/free a group of input/output ports. =====
======================================================================
To work with reserved ports an application can access directly by
commands in/out (recommended way) and can use function 43
(not recommended way).
Parameters:
* eax = 46 - function number
* ebx = 0 - reserve, 1 - free
* ecx = start port number
* edx = end port number (inclusive)
Returned value:
* eax = 0 - success
* eax = 1 - error
Remarks:
* For ports reservation: an error occurs if and only if
one from the following condition satisfies:
* start port is more than end port;
* the selected range contains incorrect port number
(correct are from 0 to 0xFFFF);
* limit for the total number of reserved areas is exceeded
(maximum 255 are allowed);
* the selected range intersects with any of earlier reserved
* For ports free: an error is an attempt to free range,
that was not earlier reserved by this function
(with same ecx,edx).
* If an error occurs (for both cases) function performs no action.
* At booting the system reserves for itself ports
0..0x2d, 0x30..0x4d, 0x50..0xdf, 0xe5..0xff (inclusively).
* When a thread terminates, all reserved by it ports
are freed automatically.
 
---------------------- Constants for registers: ----------------------
eax - SF_SET_PORTS (46)
======================================================================
============= Function 47 - draw a number in the window. =============
======================================================================
Parameters:
* eax = 47 - function number
* ebx = parameters of conversion number to text:
* bl = 0 - ecx contains number
* bl = 1 - ecx contains pointer to dword/qword-number
* bh = 0 - display in decimal number system
* bh = 1 - display in hexadecimal system
* bh = 2 - display in binary system
* bits 16-21 = how many digits to display
* bits 22-29 reserved and must be set to 0
* bit 30 set = display qword (64-bit) number (must be bl=1)
* bit 31 set = do not display leading zeroes of the number
* ecx = number (if bl=0) or pointer (if bl=1)
* edx = [coordinate on axis x]*65536 + [coordinate on axis y]
* esi = 0xXXRRGGBB, where
* RR, GG, BB specify text color
* XX = 0B0FCSSS (bits):
* B=1 - fill background (color = edi)
* F specifies the font:
0 = 6x9
1 = 8x16
* C=0 - draw to the window,
C=1 - draw to the user buffer (edi)
* SSS = (size multiplier)-1, so 0 = x1, 7 = x8
Returned value:
* function does not return value
Remarks:
* The given length must not exceed 60.
* The exactly given amount of digits is output. If number is small
and can be written by smaller amount of digits, it is supplemented
by leading zeroes; if the number is big and can not be written by
given amount of digits, extra digits are not drawn.
 
---------------------- Constants for registers: ----------------------
eax - SF_DRAW_NUMBER (47)
======================================================================
========= Function 48, subfunction 0 - apply screen settings. ========
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 0 - subfunction number
* ecx = 0 - reserved
Returned value:
* function does not return value
Remarks:
* Function redraws the screen after parameters change by
subfunctions 1 and 2.
* Function call without prior call to one of indicated subfunctions
is ignored.
* Function call with nonzero ecx is ignored.
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_APPLY (0)
======================================================================
=========== Function 48, subfunction 1 - set button style. ===========
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 1 - subfunction number
* ecx = button style:
* 0 = flat
* 1 = 3d
Returned value:
* function does not return value
Remarks:
* After call to this function one should redraw the screen by
subfunction 0.
* Button style influences only to their draw of function 8.
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_BUTTON_STYLE (1)
======================================================================
====== Function 48, subfunction 2 - set standard window colors. ======
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 2 - subfunction number
* ecx = pointer to the color table
* edx = size of the color table
(must be 40 bytes for future compatibility)
Format of the color table is shown in description of subfunction 3.
Returned value:
* function does not return value
Remarks:
* After call to this function one should redraw the screen by
subfunction 0.
* Table of standard colors influences only to applications,
which receive this table obviously (by subfunction 3)
and use it (specifying colors from it to drawing functions).
* Table of standard colors is included in skin and is installed
anew with skin installation (by subfunction 8).
* Color table can be viewed/changed interactively with
the application 'desktop'.
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_COLORS (2)
======================================================================
====== Function 48, subfunction 3 - get standard window colors. ======
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 3 - subfunction number
* ecx = pointer to the buffer with size edx bytes,
where table will be written
* edx = size of color table
(must be 40 bytes for future compatibility)
Returned value:
* function does not return value
Format of the color table:
each item is dword-value for color 0x00RRGGBB
* +0: dword: frames - color of frame
* +4: dword: grab - color of header
* +8: dword: grab_button - color of button on header bar
* +12 = +0xC: dword: grab_button_text - color of text on button
on header bar
* +16 = +0x10: dword: grab_text - color of text on header
* +20 = +0x14: dword: work - color of working area
* +24 = +0x18: dword: work_button - color of button in working area
* +28 = +0x1C: dword: work_button_text - color of text on button
in working area
* +32 = +0x20: dword: work_text - color of text in working area
* +36 = +0x24: dword: work_graph - color of graphics in working area
Remarks:
* Structure of the color table is described in the standard
include file 'macros.inc' as 'system_colors'; for example,
it is possible to write:
sc system_colors ; variable declaration
... ; somewhere one must call
; this function with ecx=sc
mov ecx, [sc.work_button_text] ; read text color on
; button in working area
* A program itself decides to use or not to use color table.
For usage program must simply at calls to drawing functions select
color taken from the table.
* At change of the table of standard colors (by subfunction 2 with
the subsequent application of changes by subfunction 0 or
at skin set by subfunction 8) the system sends to all windows
redraw message (the event with code 1).
* Color table can be viewed/changed interactively with
the application 'desktop'.
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_COLORS (3)
======================================================================
============ Function 48, subfunction 4 - get skin height. ===========
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 4 - subfunction number
Returned value:
* eax = skin height
Remarks:
* Skin height is defined as the height of a header
of skinned windows.
* See also general structure of window in the description
of function 0.
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_SKIN_HEIGHT (4)
======================================================================
======== Function 48, subfunction 5 - get screen working area. =======
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 5 - subfunction number
Returned value:
* eax = [left]*65536 + [right]
* ebx = [top]*65536 + [bottom]
Remarks:
* The screen working area defines position and coordinates of
a maximized window.
* The screen working area in view of normal work is all screen
without taskbar ('@taskbar' application).
* (left,top) are coordinates of the left upper corner,
(right,bottom) are coordinates of the right lower one.
Thus the size of working area on x axis can be calculated by
formula right-left+1, on y axis - by formula bottom-top+1.
* See also function 14,
to get sizes of all screen.
* There is a pair function to set working area - subfunction 6.
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_SCREEN_AREA (5)
======================================================================
======== Function 48, subfunction 6 - set screen working area. =======
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 6 - subfunction number
* ecx = [left]*65536 + [right]
* edx = [top]*65536 + [bottom]
Returned value:
* function does not return value
Remarks:
* The screen working area defines position and coordinates of
a maximized window.
* This function is used only by the application '@taskbar',
which set working area to all screen without taskbar.
* (left,top) are coordinates of the left upper corner,
(right,bottom) are coordinates of the right lower one.
Thus the size of working area on x axis can be calculated by
formula right-left+1, on y axis - by formula bottom-right+1.
* If 'left'>='right', x-coordinate of working area is not changed.
If 'left'<0, 'left' will not be set. If 'right' is greater than or
equal to screen width, 'right' will not be set.
Similarly on y axis.
* See also function 14,
to get sizes of all screen.
* There is a pair function to get working area - subfunction 5.
* This function redraws the screen automatically,
updating coordinates and sizes of maximized windows.
The system sends to all windows redraw message (the event 1).
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_SCREEN_AREA (6)
======================================================================
=========== Function 48, subfunction 7 - get skin margins. ===========
======================================================================
Returns the area of a header of a skinned window, intended for
a text of a header.
Parameters:
* eax = 48 - function number
* ebx = 7 - subfunction number
Returned value:
* eax = [left]*65536 + [right]
* ebx = [top]*65536 + [bottom]
Remarks:
* An application decides itself to use or not to use this function.
* It is recommended to take into account returned value
of this function for choice of a place for drawing header text
(by function 4) or a substitute of header text
(at the discretion of an application).
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_SKIN_MARGINS (7)
======================================================================
============= Function 48, subfunction 8 - set used skin. ============
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 8 - subfunction number
* ecx = pointer to filename of the skin
Returned value:
* eax = 0 - success
* otherwise eax = file system error code; if file does not
contain valid skin, function returns error 3
(unknown file system).
Remarks:
* After successful skin loading the system sends to all windows
redraw message (the event 1).
* At booting the system reads skin from file 'default.skn'
on ramdisk.
* User can change the skin statically by creating hisself
'default.skn' or dynamically with the application 'desktop'.
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_SKIN (8)
======================================================================
====== Function 48, subfunction 9 - get font smoothing setting. ======
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 9 - subfunction number
Returned value:
* eax = 2 - subpixel, 1 - anti-aliasing, 0 - off
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_FONT_SMOOTH (9)
======================================================================
========== Function 48, subfunction 10 - set font smoothing. =========
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 10 - subfunction number
* cl = 2 - subpixel, 1 - anti-aliasing, 0 - off
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_FONT_SMOOTH (10)
======================================================================
============ Function 48, subfunction 11 - get font size. ============
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 11 - subfunction number
Returned value:
* eax = current font height in pixels
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_GET_FONT_SIZE (11)
======================================================================
============ Function 48, subfunction 12 - set font size. ============
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 12 - subfunction number
* cl = new font height in pixels
 
---------------------- Constants for registers: ----------------------
eax - SF_STYLE_SETTINGS (48)
ebx - SSF_SET_FONT_SIZE (12)
======================================================================
== Function 48, subfunction 13 - set skin, specifying the encoding. ==
======================================================================
Parameters:
* eax = 48 - function number
* ebx = 13 - subfunction number
* ecx = pointer to the skin file path string
* edx = string encoding, details can be found in function 80 description.
Returned value:
* eax = 0 - success
* otherwise eax = file system error code; if file does not
contain valid skin, function returns error 3
(unknown file system).
Remarks:
* After successful skin loading the system sends to all windows
redraw message (the event 1).
* At booting the system reads skin from file 'default.skn'
on ramdisk.
* User can change the skin statically by creating hisself
'default.skn' or dynamically with the application 'desktop'.
 
======================================================================
=========== Function 49 - Advanced Power Management (APM). ===========
======================================================================
Parameters:
* eax = 49 - function number
* dx = number of the APM function
(analogue of ax in APM specification)
* bx, cx = parameters of the APM function
Returned value:
* 16-bit registers ax, bx, cx, dx, si, di and carry flag CF
are set according to the APM specification
* high halves of 32-bit registers eax, ebx, ecx,
edx, esi, edi are destroyed
Remarks:
* APM 1.2 specification is described in the document
"Advanced Power Management (APM) BIOS Specification"
(Revision 1.2), available at
http://www.microsoft.com/whdc/archive/amp_12.mspx;
besides it is included in famous Interrupt List by Ralf Brown
(http://www.pobox.com/~ralf/files.html,
ftp://ftp.cs.cmu.edu/afs/cs/user/ralf/pub/).
 
---------------------- Constants for registers: ----------------------
eax - SF_APM (49)
======================================================================
=================== Function 50 - set window shape. ==================
======================================================================
Normal windows have rectangular shape. This function can give to
a window any shape. The shape is given by a set of points inside
the base rectangle belonging to a window. Position and coordinates
of the base rectangle are set by function 0
and changed by function 67.
 
--------------------------- Set shape data ---------------------------
Parameters:
* eax = 50 - function number
* ebx = 0 - subfunction number
* ecx = pointer to shape data (array of bytes 0/1)
Returned value:
* function does not return value
 
-------------------------- Set shape scale ---------------------------
Parameters:
* eax = 50 - function number
* ebx = 1 - subfunction number
* ecx sets a scale: each byte of data defines
(2^scale)*(2^scale) pixels
Returned value:
* function does not return value
Remarks:
* Default scale is 0 (scale factor is 1). If in the shape data
one byte corresponds to one pixel, there is no necessity
to set scale.
* Let's designate xsize = window width (in pixels), ysize = height;
pay attention, that they are one pixel more than defined by
functions 0, 67.
* On definition of scale xsize and ysize must be divisible
on 2^scale.
* Byte of data on offset 'a' must be 0/1 and defines belonging
to a window of square with the side 2^scale (if scale=0,
this is one pixel) and coordinates of the left upper corner
(a mod (xsize shr scale), a div (xsize shr scale))
* Data size: (xsize shr scale)*(ysize shr scale).
* Data must be presented in the memory and not change
after set of shape.
* The system views the shape data at every window redraw by
function 0.
* The call of subfunction 0 with NULL pointer results in return
to the rectangular shape.
 
---------------------- Constants for registers: ----------------------
eax - SF_SET_WINDOW_SHAPE (50)
======================================================================
==================== Function 51 - create thread. ====================
======================================================================
Parameters:
* eax = 51 - function number
* ebx = 1 - unique subfunction
* ecx = address of thread entry point (starting eip)
* edx = pointer to thread stack (starting esp)
Returned value:
* eax = -1 - error (there is too many threads)
* otherwise eax = TID - thread identifier
 
---------------------- Constants for registers: ----------------------
eax - SF_CREATE_THREAD (51)
======================================================================
==================== Function 54, subfunction 0 ======================
============== Get the number of slots in the clipboard. =============
======================================================================
Parameters:
* eax = 54 - function number
* ebx = 0 - subfunction number
Returned value:
* eax = slots in the clipboard
* eax = -1 - main list area not found
 
---------------------- Constants for registers: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_GET_SLOT_COUNT (0)
======================================================================
==================== Function 54, subfunction 1 ======================
================= Read the data from the clipboard. ==================
======================================================================
Parameters:
* eax = 54 - function number
* ebx = 1 - subfunction number
* eсx = slot number
Returned value:
* eax = if successful - pointer to a memory with data
* eax = 1 - error
* eax = -1 - main list area not found
Remarks:
* The function must be used in conjunction with 68.11. The
application must pre-initialize the local heap by calling 68.11.
 
---------------------- Constants for registers: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_READ_CB (1)
======================================================================
==================== Function 54, subfunction 2 ======================
================= Write the data to the clipboard. ===================
======================================================================
Parameters:
* eax = 54 - function number
* ebx = 2 - subfunction number
* eсx = the number of bytes to be copied
* edx = a pointer to a buffer for data to be copied
Returned value:
* eax = 0 - success
* eax = 1 - error
* eax = -1 - main list area not found
 
---------------------- Constants for registers: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_WRITE_CB (2)
======================================================================
===================== Function 54, subfunction 3 =====================
================ Delete the last slot in the clipboard ===============
======================================================================
Parameters:
* eax = 54 - function number
* ebx = 3 - subfunction number
Returned value:
* eax = 0 - success
* eax = 1 - error
* eax = -1 - main list area not found
 
---------------------- Constants for registers: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_DEL_SLOT (3)
======================================================================
===================== Function 54, subfunction 4 =====================
===================== Alarm reset the lock buffer ====================
======================================================================
Parameters:
* eax = 54 - function number
* ebx = 4 - subfunction number
Returned value:
* eax = 0 - success
* eax = -1 - main list area not found or no blocking
Remarks:
* Used in exceptional cases, where no responsible or killed
application blocked the clipboard operations.
 
---------------------- Constants for registers: ----------------------
eax - SF_CLIPBOARD (54)
ebx - SSF_UNLOCK_BUFFER (4)
======================================================================
Function 55, subfunction 55 - begin to play data on built-in speaker.
======================================================================
Parameters:
* eax = 55 - function number
* ebx = 55 - subfunction number
* esi = pointer to data
Returned value:
* eax = 0 - success
* eax = 55 - error (speaker is off or busy)
Data is an array of items with variable length.
Format of each item is defined by first byte:
* 0 = end of data
* 1..0x80 = sets sound duration on 1/100 of second; sound note
is defined by immediate value of frequency
* following word (2 bytes) contains frequency divider;
frequency is defined as 1193180/divider
* 0x81 = invalid
* 0x82..0xFF = note is defined by octave and number:
* duration in 1/100 of second = (first byte)-0x81
* there is one more byte;
* (second byte)=0xFF - delay
* otherwise it looks like a*0x10+b, where b=number of the note in
an octave from 1 to 12, a=number of octave (beginning from 0)
Remarks:
* Speaker play can be disabled/enabled by
subfunction 8 of function 18.
* Function returns control, having informed the system
an information on request. Play itself goes independently from
the program.
* The data must be kept in the memory at least up to the end
of play.
 
---------------------- Constants for registers: ----------------------
eax - SF_SPEAKER_PLAY (55)
======================================================================
======================= Function 57 - PCI BIOS. ======================
======================================================================
Parameters:
* eax = 57 - function number
* ebp corresponds to al in PCI BIOS specification
* other registers are set according to PCI BIOS specification
Returned value:
* CF is undefined
* other registers are set according to PCI BIOS specification
Remarks:
* Many effects of this function can be also achieved with
corresponding subfunctions of function 62.
* The function calls PCI32 BIOS extension, documented e.g. in
http://alpha1.dyns.net/files/PCI/bios21.pdf.
* If BIOS does not support this extension, its behavior is emulated
(through kernel-mode analogues of subfunctions of function 62).
 
---------------------- Constants for registers: ----------------------
eax - SF_PCI_BIOS (57)
======================================================================
========== Function 60 - Inter Process Communication (IPC). ==========
======================================================================
IPC is used for message dispatching from one process/thread to
another. Previously it is necessary to agree how to interpret
the concrete message.
 
----------- Subfunction 1 - set the area for IPC receiving -----------
Is called by process-receiver.
Parameters:
* eax = 60 - function number
* ebx = 1 - subfunction number
* ecx = pointer to the buffer
* edx = size of the buffer
Returned value:
* eax = 0 - always success
Format of IPC-buffer:
* +0: dword: if nonzero, buffer is considered locked;
lock/unlock the buffer, when you work with it and need that
buffer data are not changed from outside (no new messages)
* +4: dword: occupied place in the buffer (in bytes)
* +8: first message
* +8+n: second message
* ...
Format of a message:
* +0: dword: PID of sender
* +4: dword: message length (not including this header)
* +8: n*byte: message data
 
------------------ Subfunction 2 - send IPC message ------------------
Is called by process-sender.
Parameters:
* eax = 60 - function number
* ebx = 2 - subfunction number
* ecx = PID of receiver
* edx = pointer to the message data
* esi = message length (in bytes)
Returned value:
* eax = 0 - success
* eax = 1 - the receiver has not defined buffer for IPC messages
(can be, still have no time,
and can be, this is not right process)
* eax = 2 - the receiver has blocked IPC-buffer; try to wait a bit
* eax = 3 - overflow of IPC-buffer of the receiver
* eax = 4 - process/thread with such PID does not exist
Remarks:
* Immediately after writing of IPC-message to the buffer the system
sends to the receiver the event with code 7 (see event codes).
 
---------------------- Constants for registers: ----------------------
eax - SF_IPC (60)
ebx - SSF_SET_AREA (1), SSF_SEND_MESSAGE (2)
======================================================================
==== Function 61 - get parameters for the direct graphics access. ====
======================================================================
The data of the graphics screen (the memory area which displays
screen contents) are accessible to a program directly, without
any system calls, through the selector gs:
mov eax, [gs:0]
places in eax the first dword of the buffer, which contains
information on color of the left upper point (and, possibly, colors
of several following).
mov [gs:0], eax
by work in VESA modes with LFB sets color of the left upper point
(and, possibly, colors of several following).
To interpret the data of graphics screen program needs to know
some parameters, returning by this function.
Remarks:
* Graphics parameters changes very seldom at work.
* At videomode change the system redraws all windows (event
with code 1) and redraws the background (event 5).
Same events occur in other cases too, which meet much more often,
than videomode change.
* By operation in videomodes with LFB the selector gs points to
LFB itself, so reading/writing on gs result directly in
change of screen contents. By operation in videomodes without
LFB gs points to some data area in the kernel, and all functions
of screen output fulfil honesty double operation on writing
directly to the screen and writing to this buffer. In result
at reading contents of this buffer the results correspond to
screen contents (with, generally speaking, large color
resolution), and writing is ignored.
One exception is the mode 320*200, for which main loop of the
system thread updates the screen according to mouse movements.
 
------------------------- Screen resolution --------------------------
Parameters:
* eax = 61 - function number
* ebx = 1 - subfunction number
Returned value:
* eax = [resolution on x axis]*65536 + [resolution on y axis]
Remarks:
* One can use function 14 paying attention that
it returns sizes on 1 pixel less. It is fully equivalent way.
 
---------------------- Number of bits per pixel ----------------------
Parameters:
* eax = 61 - function number
* ebx = 2 - subfunction number
Returned value:
* eax = number of bits per pixel (24 or 32)
 
-------------------- Number of bytes per scanline --------------------
Parameters:
* eax = 61 - function number
* ebx = 3 - subfunction number
Returned value:
* eax = number of bytes occupied by one scanline
(horizontal line on the screen)
 
---------------------- Constants for registers: ----------------------
eax - SF_GET_GRAPHICAL_PARAMS (61)
ebx - SSF_SCREEN_SIZE (1), SSF_BITS_PER_PIXEL (2),
SSF_BYTES_PER_LINE (3)
======================================================================
===== Function 62, subfunction 0 - get version of PCI-interface. =====
======================================================================
Parameters:
* eax = 62 - function number
* bl = 0 - subfunction number
Returned value:
* eax = -1 - PCI access is disabled; otherwise
* ah.al = version of PCI-interface (ah=version, al=subversion)
* high word of eax is zeroed
Remarks:
* Previously low-level access to PCI for applications must be
enabled by subfunction 12 of function 21.
* If PCI BIOS is not supported, the value of ax is undefined.
 
---------------------- Constants for registers: ----------------------
eax - SF_PCI (62)
ebx - SSF_GET_VERSION (0)
======================================================================
==== Function 62, subfunction 1 - get number of the last PCI-bus. ====
======================================================================
Parameters:
* eax = 62 - function number
* bl = 1 - subfunction number
Returned value:
* eax = -1 - access to PCI is disabled; otherwise
* al = number of the last PCI-bus; other bytes of eax are destroyed
Remarks:
* Previously low-level access to PCI for applications must be
enabled by subfunction 12 of function 21.
* If PCI BIOS is not supported, the value of ax is undefined.
 
---------------------- Constants for registers: ----------------------
eax - SF_PCI (62)
ebx - SSF_GET_LAST_BUS (1)
======================================================================
===================== Function 62, subfunction 2 =====================
===== Get mechanism of addressing to the PCI configuration space. ====
======================================================================
Parameters:
* eax = 62 - function number
* bl = 2 - subfunction number
Returned value:
* eax = -1 - access to PCI is disabled; otherwise
* al = mechanism (1 or 2); other bytes of eax are destroyed
Remarks:
* Previously low-level access to PCI for applications must be
enabled by subfunction 12 of function 21.
* Addressing mechanism is selected depending on
equipment characteristics.
* Subfunctions of read and write work automatically
with the selected mechanism.
 
---------------------- Constants for registers: ----------------------
eax - SF_PCI (62)
ebx - SSF_GET_ADRR_MODE (2)
======================================================================
======== Function 62, subfunctions 4,5,6 - read PCI-register. ========
======================================================================
Parameters:
* eax = 62 - function number
* bl = 4 - read byte
* bl = 5 - read word
* bl = 6 - read dword
* bh = number of PCI-bus
* ch = dddddfff, where ddddd = number of the device on the bus,
fff = function number of device
* cl = number of register (must be even for bl=5,
divisible by 4 for bl=6)
Returned value:
* eax = -1 - error (access to PCI is disabled or parameters
are not supported); otherwise
* al/ax/eax (depending on requested size) contains the data;
the other part of register eax is destroyed
Remarks:
* Previously low-level access to PCI for applications must be
enabled by subfunction 12 of function 21.
* Access mechanism 2 supports only 16 devices on a bus and ignores
function number. To get access mechanism use subfunction 2.
* Some registers are standard and exist for all devices, some are
defined by the concrete device. The list of registers of the
first type can be found e.g. in famous
Interrupt List by Ralf Brown
(http://www.pobox.com/~ralf/files.html,
ftp://ftp.cs.cmu.edu/afs/cs/user/ralf/pub/);
registers of the second type must be listed
in the device documentation.
 
---------------------- Constants for registers: ----------------------
eax - SF_PCI (62)
ebx - SSF_READ_BYTE (4), SSF_READ_WORD (5), SSF_READ_DWORD (6)
======================================================================
====== Function 62, subfunctions 8,9,10 - write to PCI-register. =====
======================================================================
Parameters:
* eax = 62 - function number
* bl = 8 - write byte
* bl = 9 - write word
* bl = 10 - write dword
* bh = number of PCI-bus
* ch = dddddfff, where ddddd = number of the device on the bus,
fff = function number of device
* cl = number of register (must be even for bl=9,
divisible by 4 for bl=10)
* dl/dx/edx (depending on requested size) contains
the data to write
Returned value:
* eax = -1 - error (access to PCI is disabled or parameters
are not supported)
* eax = 0 - success
Remarks:
* Previously low-level access to PCI for applications must be
enabled by subfunction 12 of function 21.
* Access mechanism 2 supports only 16 devices on a bus and ignores
function number. To get access mechanism use subfunction 2.
* Some registers are standard and exist for all devices, some are
defined by the concrete device. The list of registers of the
first type can be found e.g. in famous Interrupt List by
Ralf Brown; registers of the second type must be listed
in the device documentation.
 
---------------------- Constants for registers: ----------------------
eax - SF_PCI (62)
ebx - SSF_WRITE_BYTE (8), SSF_WRITE_WORD (9), SSF_WRITE_DWORD (10)
======================================================================
============== Function 63 - work with the debug board. ==============
======================================================================
The debug board is the global system buffer (with the size
1024 bytes), to which any program can write (generally speaking,
arbitrary) data and from which other program can read these data.
By the agreement written data are text strings interpreted as
debug messages on a course of program execution. The kernel in
some situations also writes to the debug board information on
execution of some functions; by the agreement kernel messages
begins from the prefix "K : ".
For view of the debug board the application 'board' was created,
which reads data from the buffer and displays them in its window.
'board' interpretes the sequence of codes 13,10 as newline.
A character with null code in an end of line is not necessary,
but also does not prevent.
Because debugger has been written, the value of the debug board
has decreased, as debugger allows to inspect completely a course of
program execution without any efforts from the direction of program
itself. Nevertheless in some cases the debug board is still useful.
 
----------------------------- Write byte -----------------------------
Parameters:
* eax = 63 - function number
* ebx = 1 - subfunction number
* cl = data byte
Returned value:
* function does not return value
Remarks:
* Byte is written to the buffer. Buffer size is 512 bytes.
At buffer overflow all obtained data are lost.
* For output to the debug board of more complicated objects
(strings, numbers) it is enough to call this function in cycle.
It is possible not to write the appropriate code manually and use
file 'debug.inc', which is included into the distributive.
 
----------------------------- Read byte ------------------------------
Takes away byte from the buffer.
Parameters:
* eax = 63 - function number
* ebx = 2 - subfunction number
Returned value:
* eax = ebx = 0 - the buffer is empty
* eax = byte, ebx = 1 - byte was successfully read
 
---------------------- Constants for registers: ----------------------
eax - SF_BOARD (63)
ebx - SSF_DEBUG_WRITE (1), SSF_DEBUG_READ (2)
======================================================================
============== Function 64 - resize application memory. ==============
======================================================================
Parameters:
* eax = 64 - function number
* ebx = 1 - unique subfunction
* ecx = new memory size
Returned value:
* eax = 0 - success
* eax = 1 - not enough memory
Remarks:
* There is another way to dynamically allocate/free memory -
subfunctions 12, 13 and 20 of function 68, but after creation
of the process heap 64 function call will be ignored.
* The function cannot be used together with 68.11, 68.12, 68.13.
The function call will be ignored after creation of process heap
with function 68.11.
---------------------- Constants for registers: ----------------------
eax - SF_MEMORY_RESIZE (64)
======================================================================
======== Function 65 - draw image with palette in the window. ========
======================================================================
Parameters:
* eax = 65 - function number
* ebx = pointer to the image
* ecx = [size on axis x]*65536 + [size on axis y]
* edx = [coordinate on axis x]*65536 + [coordinate on axis y]
* esi = number of bits per pixel, must be 1,2,4,8,9,15,16,24 or 32;
* edi = pointer to palette (2 to the power esi colors 0x00RRGGBB);
ignored when esi > 8
* ebp = offset of next row data relative to previous row data
Returned value:
* function does not return value
Remarks:
* Coordinates of the image are coordinates of the upper left corner
of the image relative to the window.
* Format of image with 1 bit per pixel: each byte of image
(possibly excluding last bytes in rows), contains information on
the color of 8 pixels, MSB corresponds to first pixel.
* Format of image with 2 bits per pixel: each byte of image
(possibly excluding last bytes in rows), contains information on
the color of 4 pixels, two MSBs correspond to first pixel.
* Format of image with 4 bits per pixel: each byte of image
excluding last bytes in rows (if width is odd) contains
information on the color of 2 pixels, high-order tetrad
corresponds to first pixel.
* Format of image with 8 bits per pixel: each byte of image is
index in the palette.
* Format of image with 9 bits per pixel: array of one byte values;
each byte (8 bit) represents the intensity of gray for one pixel;
this format is equal to 8bpp without palette.
* Format of image with 15 bits per pixel: the color of each pixel
is coded as (bit representation) 0RRRRRGGGGGBBBBB - 5 bits per
each color.
* Format of image with 16 bits per pixel: the color of each pixel
is coded as RRRRRGGGGGGBBBBB (5+6+5).
* Format of image with 24 bits per pixel: the color of each pixel
is coded as 3 bytes - sequentially blue, green, red components.
* Format of image with 32 bits per pixel: similar to 24, but
one additional ignored byte is present. It's format is BGRX,
where X is the ignored byte.
* The call to function 7 is equivalent to call to this function
with esi=24, ebp=0.
 
---------------------- Constants for registers: ----------------------
eax - SF_PUT_IMAGE_EXT (65)
======================================================================
================== Function 66 - work with keyboard. =================
======================================================================
The input mode influences results of reading keys by function 2.
When a program loads, ASCII input mode is set for it.
 
-------------- Subfunction 1 - set keyboard input mode. --------------
Parameters:
* eax = 66 - function number
* ebx = 1 - subfunction number
* ecx = mode:
* 0 = normal (ASCII-characters)
* 1 = scancodes
Returned value:
* function does not return value
 
-------------- Subfunction 2 - get keyboard input mode. --------------
Parameters:
* eax = 66 - function number
* ebx = 2 - subfunction number
Returned value:
* eax = current mode
 
------------ Subfunction 3 - get status of control keys. -------------
Parameters:
* eax = 66 - function number
* ebx = 3 - subfunction number
Returned value:
* eax = bit mask:
* bit 0 (mask 1): left Shift is pressed
* bit 1 (mask 2): right Shift is pressed
* bit 2 (mask 4): left Ctrl is pressed
* bit 3 (mask 8): right Ctrl is pressed
* bit 4 (mask 0x10): left Alt is pressed
* bit 5 (mask 0x20): right Alt is pressed
* bit 6 (mask 0x40): CapsLock is on
* bit 7 (mask 0x80): NumLock is on
* bit 8 (mask 0x100): ScrollLock is on
* bit 9 (mask 0x200): left Win is pressed
* bit 10 (mask 0x400): right Win is pressed
* other bits are cleared
 
-------------- Subfunction 4 - set system-wide hotkey. ---------------
When hotkey is pressed, the system notifies only those applications,
which have installed it; the active application (which receives
all normal input) does not receive such keys.
The notification consists in sending event with the code 2.
Reading hotkey is the same as reading normal key - by function 2.
Parameters:
* eax = 66 - function number
* ebx = 4 - subfunction number
* cl determines key scancode;
use cl=0 to give combinations such as Ctrl+Shift
* edx = 0xXYZ determines possible states of control keys:
* Z (low 4 bits) determines state of LShift and RShift:
* 0 = no key must be pressed;
* 1 = exactly one key must be pressed;
* 2 = both keys must be pressed;
* 3 = must be pressed LShift, but not RShift;
* 4 = must be pressed RShift, but not LShift
* Y - similar for LCtrl and RCtrl;
* X - similar for LAlt and RAlt
Returned value:
* eax=0 - success
* eax=1 - too many hotkeys (maximum 256 are allowed)
Remarks:
* Hotkey can work either at pressing or at release. Release
scancode of a key is more on 128 than pressing scancode
(i.e. high bit is set).
* Several applications can set the same combination;
all such applications will be informed on pressing
such combination.
 
-------------- Subfunction 5 - delete installed hotkey. --------------
Parameters:
* eax = 66 - function number
* ebx = 5 - subfunction number
* cl = scancode of key and edx = 0xXYZ the same as in subfunction 4
Returned value:
* eax = 0 - success
* eax = 1 - there is no such hotkey
Remarks:
* When a process/thread terminates, all hotkey installed by it are
deleted.
* The call to this subfunction does not affect other applications.
If other application has defined the same combination, it will
still receive notices.
 
--------------- Subfunction 6 - block the normal input. --------------
Parameters:
* eax = 66 - function number
* ebx = 6 - subfunction number
Returned value:
* function does not return value
Remarks:
* Blocking the normal keyboard input for installed hotkeys
* To emulate a mouse via the keyboard, the application MOUSEMUL
 
------------ Subfunction 7 - unlock the normal input. ----------------
Parameters:
* eax = 66 - function number
* ebx = 7 - subfunction number
Returned value:
* function does not return value
Remarks:
* Unlocking the results of the f. 66.6
* To emulate a mouse via the keyboard, the application MOUSEMUL
 
---------------------- Constants for registers: ----------------------
eax - SF_KEYBOARD (66)
ebx - SSF_SET_INPUT_MODE (1), SSF_GET_INPUT_MODE (2),
SSF_GET_CONTROL_KEYS (3), SSF_SET_SYS_HOTKEY (4),
SSF_DEL_SYS_HOTKEY (5), SSF_LOCK_INPUT (6), SSF_UNLOCK_INPUT (7)
======================================================================
========= Function 67 - change position/sizes of the window. =========
======================================================================
Parameters:
* eax = 67 - function number
* ebx = new x-coordinate of the window
* ecx = new y-coordinate of the window
* edx = new x-size of the window
* esi = new y-size of the window
Returned value:
* function does not return value
Remarks:
* The value -1 for a parameter means "do not change"; e.g. to move
the window without resizing it is possible to specify edx=esi=-1.
* Previously the window must be defined by function 0.
It sets initial coordinates and sizes of the window.
* Sizes of the window are understood in sense of function 0,
that is one pixel less than real sizes.
* The function call for maximized windows is simply ignored.
* For windows of appropriate styles position and/or sizes can be
changed by user; current position and sizes can be obtained by
call to function 9.
* The function sends to the window redraw event (with the code 1).
 
---------------------- Constants for registers: ----------------------
eax - SF_CHANGE_WINDOW (67)
======================================================================
====== Function 68, subfunction 0 - get the task switch counter. =====
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 0 - subfunction number
Returned value:
* eax = number of task switches from the system booting
(modulo 2^32)
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_GET_TASK_SWITCH_COUNT (0)
======================================================================
======= Function 68, subfunction 1 - switch to the next thread. ======
======================================================================
The function completes the current time slice allocated to the
thread and switches to the next. (Which thread in which process
will be next, is unpredictable). Later, when execution queue
will reach the current thread, execution will be continued.
Parameters:
* eax = 68 - function number
* ebx = 1 - subfunction number
Returned value:
* function does not return value
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_SWITCH_TASK (1)
======================================================================
============= Function 68, subfunction 2 - cache + rdpmc. ============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 2 - subfunction number
* ecx = required action:
* ecx = 0 - enable instruction 'rdpmc'
(ReaD Performance-Monitoring Counters) for applications
* ecx = 1 - find out whether cache is disabled/enabled
* ecx = 2 - enable cache
* ecx = 3 - disable cache
Returned value:
* for ecx=0:
* eax = the value of cr4
* for ecx=1:
* eax = (cr0 and 0x60000000):
* eax = 0 - cache is on
* eax <> 0 - cache is off
* for ecx=2 and ecx=3:
* function does not return value
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_PERFORMANCE (2)
ecx - SSSF_ALLOW_RDPMC (0), SSSF_CACHE_STATUS (1),
SSSF_CACHE_ON (2), SSSF_CACHE_OFF (3)
======================================================================
=========== Function 68, subfunction 3 - read MSR-register. ==========
======================================================================
MSR = Model Specific Register; the complete list of MSR-registers
of a processor is included to the documentation on it (for example,
IA-32 Intel Architecture Software Developer's Manual,
Volume 3, Appendix B); each processor family has its own subset
of the MSR-registers.
Parameters:
* eax = 68 - function number
* ebx = 3 - subfunction number
* ecx is ignored
* edx = MSR address
Returned value:
* ebx:eax = high:low dword of the result
Remarks:
* If ecx contains nonexistent or not implemented for this processor
MSR, processor will generate an exception in the kernel, which
will kill the thread.
* Previously it is necessary to check, whether MSRs are supported
as a whole, with the instruction 'cpuid'. Otherwise processor
will generate other exception in the kernel, which will anyway
kill the thread.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_READ_MSR (3)
======================================================================
========= Function 68, subfunction 4 - write to MSR-register. ========
======================================================================
MSR = Model Specific Register; the complete list of MSR-registers
of a processor is included to the documentation on it (for example,
IA-32 Intel Architecture Software Developer's Manual,
Volume 3, Appendix B); each processor family has its own subset
of the MSR-registers.
Parameters:
* eax = 68 - function number
* ebx = 4 - subfunction number
* ecx is ignored
* edx = MSR address
* esi:edi = high:low dword
Returned value:
* function does not return value
Remarks:
* If ecx contains nonexistent or not implemented for this processor
MSR, processor will generate an exception in the kernel, which
will kill the thread.
* Previously it is necessary to check, whether MSRs are supported
as a whole, with the instruction 'cpuid'. Otherwise processor
will generate other exception in the kernel, which will anyway
kill the thread.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_WRITE_MSR (4)
======================================================================
=== Function 68, subfunction 11 - initialize process heap ============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 11 - subfunction number
Returned value:
* eax = 0 - failed
* otherwise size of created heap
Remarks:
* The function call initializes heap for subfunctions 12, 13 and 20.
* If the process heap is already created, this function will return
the size of the existing heap.
Heap size is equal to total amount of free application memory.
* After creation of the heap calls to function 64 will be ignored.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_HEAP_INIT (11)
======================================================================
======== Function 68, subfunction 12 - allocate memory block. ========
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 12 - subfunction number
* ecx = required size in bytes
Returned value:
* eax = pointer to the allocated block
Remarks:
* The function allocates an integer number of pages (4 Kb) in such
way that the real size of allocated block is more than or equal to
requested size.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_ALLOC (12)
======================================================================
========== Function 68, subfunction 13 - free memory block. ==========
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 13 - subfunction number
* ecx = pointer to the memory block
Returned value:
* eax = 1 - success
* eax = 0 - failed
Remarks:
* The memory block must have been allocated by subfunction 12
or subfunction 20.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_FREE (13)
======================================================================
===================== Function 68, subfunction 14 ====================
============ Wait for signal from another program/driver. ============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 14 - subfunction number
* ecx = pointer to the buffer for information (24 bytes)
Returned value:
* buffer pointed to by ecx contains the following information:
* +0: dword: identifier for following data of signal
* +4: dword: data of signal (20 bytes), format of which is defined
by the first dword
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_WAIT_SIGNAL (14)
======================================================================
============= Function 68, subfunction 16 - load driver. =============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 16 - subfunction number
* ecx = pointer to ASCIIZ-string with driver name
Returned value:
* eax = 0 - failed
* otherwise eax = driver handle
Remarks:
* If the driver was not loaded yet, it is loaded;
if the driver was loaded yet, nothing happens.
* Driver name is case-sensitive.
Maximum length of the name is 16 characters, including
terminating null character, the rest is ignored.
* Driver ABC is loaded from file /sys/drivers/ABC.sys.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_LOAD_DRIVER (16)
======================================================================
============ Function 68, subfunction 17 - driver control. ===========
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 17 - subfunction number
* ecx = pointer to the control structure:
* +0: dword: handle of driver
* +4: dword: code of driver function
* +8: dword: pointer to input data
* +12 = +0xC: dword: size of input data
* +16 = +0x10: dword: pointer to output data
* +20 = +0x14: dword: size of output data
Returned value:
* eax = determined by driver
Remarks:
* Function codes and the structure of input/output data
are defined by driver.
* Previously one must obtain driver handle by subfunction 16.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_CONTROL_DRIVER (17)
======================================================================
== Function 68, subfunction 18 - load DLL, specifying the encoding. ==
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 18 - subfunction number
* ecx = pointer to the string with path to DLL
* edx = string encoding, details can be found in function 80 description.
Returned value:
* eax = 0 - failed
* otherwise eax = pointer to DLL export table
Remarks:
* Export table is an array of structures of 2 dword's, terminated
by zero. The first dword in structure points to function name,
the second dword contains address of function.
 
======================================================================
=============== Function 68, subfunction 19 - load DLL. ==============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 19 - subfunction number
* ecx = pointer to the string with path to DLL,
rules of path forming can be found in function 70 description.
Returned value:
* eax = 0 - failed
* otherwise eax = pointer to DLL export table
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_LOAD_DLL (19)
======================================================================
======= Function 68, subfunction 20 - reallocate memory block. =======
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 20 - subfunction number
* ecx = new size in bytes
* edx = pointer to already allocated block
Returned value:
* eax = pointer to the reallocated block, 0 = error
Remarks:
* Before this call one must initialize process heap by call to
subfunction 11.
* The function allocates an integer number of pages (4 Kb) in such
way that the real size of allocated block is more than or equal to
requested size.
* If edx=0, the function call is equivalent to memory allocation
with subfunction 12. Otherwise the block at edx
must be allocated earlier with subfunction 12 or this subfunction.
* If ecx=0, the function frees memory block at edx and returns 0.
* The contents of the block are unchanged up to the shorter of
the new and old sizes.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_REALLOC (20)
======================================================================
=========== Function 68, subfunction 21 - load driver PE. ============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 21 - subfunction number
* ecx = pointer to ASCIIZ-string with driver name
* edx = pointer to command line
Returned value:
* eax = 0 - failed
* otherwise eax = driver handle
Remarks:
* If the driver was not loaded yet, it is loaded;
if the driver was loaded yet, nothing happens.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_LOAD_DRIVER_PE (21)
======================================================================
======== Function 68, subfunction 22 - open named memory area. =======
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 22 - subfunction number
* ecx = area name. Maximum of 31 characters with terminating zero
* edx = area size in bytes for SHM_CREATE and SHM_OPEN_ALWAYS
* esi = flags for open and access:
* SHM_OPEN = 0x00 - open existing memory area. If an area
with such name does not exist, the function
will return error code 5.
* SHM_OPEN_ALWAYS = 0x04 - open existing or create new
memory area.
* SHM_CREATE = 0x08 - create new memory area. If an area
with such name already exists, the function
will return error code 10.
* SHM_READ = 0x00 - only read access
* SHM_WRITE = 0x01 - read and write access
Returned value:
* eax = pointer to memory area, 0 if error has occurred
* if new area is created (SHM_CREATE or SHM_OPEN_ALWAYS):
edx = 0 - success, otherwise - error code
* if existing area is opened (SHM_OPEN or SHM_OPEN_ALWAYS):
edx = error code (if eax=0) or area size in bytes
Error codes:
* E_NOTFOUND = 5
* E_ACCESS = 10
* E_NOMEM = 30
* E_PARAM = 33
Remarks:
* Before this call one must initialize process heap by call to
subfunction 11.
* If a new area is created, access flags set maximal rights
for other processes. An attempt from other process to open
with denied rights will fail with error code E_ACCESS.
* The process which has created an area always has write access.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_OPEN (22)
======================================================================
======= Function 68, subfunction 23 - close named memory area. =======
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 23 - subfunction number
* ecx = area name. Maximum of 31 characters with terminating zero
Returned value:
* eax destroyed
Remarks:
* A memory area is physically freed (with deleting all data and
freeing physical memory), when all threads which have opened
this area will close it.
* When thread is terminating, all opened by it areas are closed.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_CLOSE (23)
======================================================================
======== Function 68, subfunction 24 - set exception handler. ========
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 24 - subfunction number
* ecx = address of the new exception handler
* edx = the mask of handled exceptions
Returned value:
* eax = address of the old exception handler (0, if it was not set)
* ebx = the old mask of handled exceptions
Remarks:
* Bit number in mask of exceptions corresponds to exception number
in CPU-specification (Intel-PC). For example, FPU exceptions have
number 16 (#MF), and SSE exceptions - 19 (#XF).
* The current implementation ignores the inquiry for hook of 7
exception - the system handles #NM by its own.
* The exception handler is called with exception number as first
(and only) stack parameter. So, correct exit from the handler is
RET 4. It returns to the instruction, that caused the exception,
for faults, and to the next instruction for traps (see
classification of exceptions in CPU specification).
* When user handler receives control, the corresponding bit in
the exception mask is cleared. Raising this exception
in consequence leads to default handling, that is,
terminating the application in absence of debugger or
suspend with notification of debugger otherwise.
* After user handler completes critical operations, it can set
the corresponding bit in the exception mask with subfunction 25.
Also user handler is responsible for clearing exceptions flags in
FPU and/or SSE.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_SET_EXCEPTION_HANDLER (24)
======================================================================
======== Function 68, subfunction 25 - set exception activity ========
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 25 - subfunction number
* ecx = signal number
* edx = value of activity (0/1)
Returned value:
* eax = -1 - invalid signal number
* otherwise eax = old value of activity for this signal (0/1)
Remarks:
* In current implementation only mask for user exception handler,
which has been previously set by subfunction 24,
is changed. Signal number corresponds to exception number.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_SET_EXCEPTION_STATE (25)
======================================================================
====== Function 68, subfunction 26 - release memory pages ============
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 26 - subfunction number
* ecx = pointer to the memory block, allocated by subfunction 12
* edx = offset from the block beginnings
* esi = the size of the region of memory to release, in bytes
Remarks:
* function release range of pages from ecx+edx to ecx+edx+esi
and set virtual memory into reserved state.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_FREE_EXT (26)
======================================================================
========== Function 68, subfunction 27 - load file ===================
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 27 - subfunction number
* ecx = pointer to the string with path to file,
rules of path forming can be found in function 70 description.
Returned value:
* eax = pointer to the loaded file, or zero
* edx = size of the loaded file, or zero
Remarks:
* function loads file and unpacks, if necessary
* Before this call one must initialize process heap by call to
subfunction 11.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_LOAD_FILE (27)
======================================================================
== Function 68, subfunction 28 - load file, specifying the encoding ==
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 28 - subfunction number
* ecx = pointer to the string with path to file
* edx = string encoding, details can be found in function 80 description.
Returned value:
* eax = pointer to the loaded file, or zero
* edx = size of the loaded file, or zero
Remarks:
* function loads file and unpacks, if necessary
======================================================================
======== Function 68, subfunction 29 - allocate ring memory. =========
======================================================================
Parameters:
* eax = 68 - function number
* ebx = 29 - subfunction number
* ecx = required size in bytes
Returned value:
* eax = 0 - failed
* eax = pointer to the allocated ring
Remarks:
* The requested size must be an exact multiple of pagesize (4 Kb)
* The function allocates memory in such a way that you can read and
write beyond the size of the allocated memory and will reach the
beginning of the buffer again.
 
---------------------- Constants for registers: ----------------------
eax - SF_SYS_MISC (68)
ebx - SSF_MEM_ALLOC_RING (29)
 
======================================================================
====================== Function 69 - debugging. ======================
======================================================================
A process can load other process as debugged by set of corresponding
bit by call to subfunction 7 of function 70.
A process can have only one debugger; one process can debug some
others. The system notifies debugger on events occurring with
debugged process. Messages are written to the buffer defined by
subfunction 0.
Format of a message:
* +0: dword: message code
* +4: dword: PID of debugged process
* +8: there can be additional data depending on message code
Message codes:
* 1 = exception
* in addition dword-number of the exception is given
* process is suspended
* 2 = process has terminated
* comes at any termination: both through the system function -1,
and at "murder" by any other process (including debugger itself)
* 3 = debug exception int 1 = #DB
* in addition dword-image of the register DR6 is given:
* bits 0-3: condition of the corresponding breakpoint (set by
subfunction 9) is satisfied
* bit 14: exception has occurred because of the trace mode
(flag TF is set TF)
* process is suspended
When debugger terminates, all debugged processes are killed.
If debugger does not want this, it must previously detach by
subfunction 3.
 
All subfunctions are applicable only to processes/threads started
from the current by function 70 with set debugging flag.
Debugging of multithreaded programs is not supported yet.
The full list of subfunctions:
* subfunction 0 - define data area for debug messages
* subfunction 1 - get contents of registers of debugged thread
* subfunction 2 - set contents of registers of debugged thread
* subfunction 3 - detach from debugged process
* subfunction 4 - suspend debugged thread
* subfunction 5 - resume debugged thread
* subfunction 6 - read from the memory of debugged process
* subfunction 7 - write to the memory of debugged process
* subfunction 8 - terminate debugged thread
* subfunction 9 - set/clear hardware breakpoint
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_SET_MESSAGE_AREA (0), SSF_GET_REGISTERS (1),
SSF_SET_REGISTERS (2), SSF_DETACH (3), SSF_SUSPEND (4),
SSF_RESUME (5), SSF_READ_MEMORY (6), SSF_WRITE_MEMORY (7),
SSF_TERMINATE (8), SSF_DEFINE_BREAKPOINT (9)
======================================================================
= Function 69, subfunction 0 - define data area fror debug messages. =
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 0 - subfunction number
* ecx = pointer
Format of data area:
* +0: dword: N = buffer size (not including this header)
* +4: dword: occupied place
* +8: N*byte: buffer
Returned value:
* function does not return value
Remarks:
* If the size field is negative, the buffer is considered locked
and at arrival of new message the system will wait.
For synchronization frame all work with the buffer by operations
lock/unlock
neg [bufsize]
* Data in the buffer are considered as array of items with variable
length - messages. Format of a message is explained in
general description.
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_SET_MESSAGE_AREA (0)
======================================================================
===================== Function 69, subfunction 1 =====================
============ Get contents of registers of debugged thread. ===========
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 1 - subfunction number
* ecx = thread identifier
* edx = size of context structure, must be 0x28=40 bytes
* esi = pointer to context structure
Returned value:
* function does not return value
Format of context structure: (FPU is not supported yet)
* +0: dword: eip
* +4: dword: eflags
* +8: dword: eax
* +12 = +0xC: dword: ecx
* +16 = +0x10: dword: edx
* +20 = +0x14: dword: ebx
* +24 = +0x18: dword: esp
* +28 = +0x1C: dword: ebp
* +32 = +0x20: dword: esi
* +36 = +0x24: dword: edi
Remarks:
* If the thread executes code of ring-0, the function returns
contents of registers of ring-3.
* Process must be loaded for debugging (as is shown in
general description).
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_GET_REGISTERS (1)
======================================================================
===================== Function 69, subfunction 2 =====================
============ Set contents of registers of debugged thread. ===========
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 2 - subfunction number
* ecx = thread identifier
* edx = size of context structure, must be 0x28=40 bytes
* esi -> context structure
Returned value:
* function does not return value
Format of context structure is shown in the description of
subfunction 1.
Remarks:
* If the thread executes code of ring-0, the function returns
contents of registers of ring-3.
* Process must be loaded for debugging (as is shown in
general description).
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_SET_REGISTERS (2)
======================================================================
===== Function 69, subfunction 3 - detach from debugged process. =====
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 3 - subfunction number
* ecx = identifier
Returned value:
* function does not return value
Remarks:
* If the process was suspended, it resumes execution.
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_DETACH (3)
======================================================================
======== Function 69, subfunction 4 - suspend debugged thread. =======
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 4 - subfunction number
* ecx = thread identifier
Returned value:
* function does not return value
Remarks:
* Process must be loaded for debugging (as is shown in
general description).
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_SUSPEND (4)
======================================================================
======== Function 69, subfunction 5 - resume debugged thread. ========
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 5 - subfunction number
* ecx = thread identifier
Returned value:
* function does not return value
Remarks:
* Process must be loaded for debugging (as is shown in
general description).
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_RESUME (5)
======================================================================
= Fucntion 69, subfunction 6 - read from memory of debugged process. =
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 6 - subfunction number
* ecx = identifier
* edx = number of bytes to read
* esi = address in the memory of debugged process
* edi = pointer to buffer for data
Returned value:
* eax = -1 at an error (invalid PID or buffer)
* otherwise eax = number of read bytes (possibly, 0,
if esi is too large)
Remarks:
* Process must be loaded for debugging (as is shown in
general description).
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_READ_MEMORY (6)
======================================================================
== Function 69, subfunction 7 - write to memory of debugged process. =
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 7 - subfunction number
* ecx = identifier
* edx = number of bytes to write
* esi = address of memory in debugged process
* edi = pointer to data
Returned value:
* eax = -1 at an error (invalid PID or buffer)
* otherwise eax = number of written bytes (possibly, 0,
if esi is too large)
Remarks:
* Process must be loaded for debugging (as is shown in
general description).
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_WRITE_MEMORY (7)
======================================================================
======= Function 69, subfunction 8 - terminate debugged thread. ======
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 8 - subfunction number
* ecx = identifier
Returned value:
* function does not return value
Remarks:
* Process must be loaded for debugging (as is shown in
general description).
* The function is similar to subfunction 2 of function 18
with two differences: it requires first remark and
accepts PID rather than slot number.
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_TERMINATE (8)
======================================================================
===== Function 69, subfunction 9 - set/clear hardware breakpoint. ====
======================================================================
Parameters:
* eax = 69 - function number
* ebx = 9 - subfunction number
* ecx = thread identifier
* dl = index of breakpoint, from 0 to 3 inclusively
* dh = flags:
* if high bit is cleared - set breakpoint:
* bits 0-1 - condition:
* 00 = breakpoint on execution
* 01 = breakpoint on read
* 11 = breakpoint on read/write
* bits 2-3 - length; for breakpoints on exception it must be
00, otherwise one of
* 00 = byte
* 01 = word
* 11 = dword
* esi = breakpoint address; must be aligned according to
the length (i.e. must be even for word breakpoints,
divisible by 4 for dword)
* if high bit is set - clear breakpoint
Returned value:
* eax = 0 - success
* eax = 1 - error in the input data
* eax = 2 - (reserved, is never returned in the current
implementation) a global breakpoint with that index is already set
Remarks:
* Process must be loaded for debugging (as is shown in
general description).
* Hardware breakpoints are implemented through DRx-registers of
the processor, all limitations results from this.
* The function can reinstall the breakpoint, previously set
by it (and it does not inform on this).
Carry on the list of set breakpoints in the debugger.
* Breakpoints generate debug exception #DB, on which the system
notifies debugger.
* Breakpoints on write and read/write act after
execution of the caused it instruction.
 
---------------------- Constants for registers: ----------------------
eax - SF_DEBUG (69)
ebx - SSF_DEFINE_BREAKPOINT (9)
======================================================================
==== Function 70 - work with file system with long names support. ====
======================================================================
Parameters:
* eax = 70
* ebx = pointer to the information structure
Returned value:
* eax = 0 - success; otherwise file system error code
* some subfunctions return value in other registers too
General format of the information structure:
* +0: dword: subfunction number
* +4: dword: offset in file or folder
* +8: dword: higher part of offset or flags
* +12 = +0xC: dword: size of data
* +16 = +0x10: dword: pointer to data
* +20 = +0x14: ?: path - zero terminated string
or
* +20 = +0x14: byte: 0
* +21 = +0x15: dword: pointer to string
Case sensitivity depends on filesystem.
If a path not begins with '/', it is considered a relative.
To get or set the current folder, use the sysfunction 30.
'../' in the path means a lift by one folder relatively current folder.
To set the encoding, put at the start of the string a byte with next values:
* 1 = cp866
* 2 = UTF-16LE
* 3 = UTF-8
otherwise will be used cp866. In an absolute path
you may put this byte after the '/' or put an additional '/' before it.
Also, you may use the sysfunction 80.
Format of an absolute path:
/base/number/dir1/dir2/.../dirn/file,
where base/number identifies device, on which file is located:
* RD/1 = ramdisk
* FD/1 = first floppy drive,
FD/2 = second floppy drive
* HD0/x, HD1/x, HD2/x, HD3/x = hard drives accordingly on
IDE0 (Primary Master), IDE1 (Primary Slave),
IDE2 (Secondary Master), IDE3 (Secondary Slave);
x - partition number on the selected hard drive, starts from 1
* CD0/1, CD1/1, CD2/1, CD3/1 = same for cd
* SYS = system folder (encoding inaffected key),
second key may be set by sysfunction 30.3.
Examples:
* '/sys/example.asm',0
* '/rd/1/example.asm',0
* '/HD0/1/folder/file.txt',0
* '/hd2/2/pics/tanzania.bmp',0
* 2,'/',0,'sys','/',0,'F',0,'I',0,'L',0,'E',0,0,0
 
Available subfunctions:
* subfunction 0 - read file
* subfunction 1 - read folder
* subfunction 2 - create/rewrite file
* subfunction 3 - write to existing file
* subfunction 4 - set file size
* subfunction 5 - get attributes of file/folder
* subfunction 6 - set attributes of file/folder
* subfunction 7 - start application
* subfunction 8 - delete file/folder
* subfunction 9 - create folder
For CD-drives due to hardware limitations only subfunctions
0,1,5 and 7 are available, other subfunctions return error
with code 2.
At the first call of subfunctions 0,1,5,7 to ATAPI devices
(CD and DVD) the manual control of tray is locked due to caching
drive data. Unlocking is made when subfunction 4 of function 24
is called for corresponding device.
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_FILE (0), SSF_READ_FOLDER (1), SSF_CREATE_FILE (2),
SSF_WRITE_FILE (3), SSF_SET_END (4), SSF_GET_INFO (5),
SSF_SET_INFO (6), SSF_START_APP (7), SSF_DELETE (8),
SSF_CREATE_FOLDER (9)
======================================================================
=== Function 70, subfunction 0 - read file with long names support. ==
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 0 = subfunction number
* +4: dword: file offset (in bytes)
* +8: dword: 0 (reserved for high dword of offset)
* +12 = +0xC: dword: number of bytes to read
* +16 = +0x10: dword: pointer to buffer for data
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx = number of bytes read
Remarks:
* If file was ended before last requested block was read,
the function will read as many as it can, and after that return
eax=6 (EOF).
* The function does not allow to read folder (returns eax=10,
access denied).
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_FILE (0)
======================================================================
== Function 70, subfunction 1 - read folder with long names support. =
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 1 = subfunction number
* +4: dword: index of starting block (beginning from 0)
* +8: dword: names encoding:
0 = default
1 = cp866
2 = UTF-16LE
3 = UTF-8
* +12 = +0xC: dword: number of blocks to read
* +16 = +0x10: dword: pointer to buffer for data
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx = number of file information blocks, written to the buffer
Structure of the buffer:
* header (32 bytes)
* block with information on file 1
* block with information on file 2
* ...
Structure of header:
* +0: dword: version of structure (current is 1)
* +4: dword: number of placed blocks; is not greater than requested
in the field +12 of information structure; can be less, if
there are no more files in folder (the same as in ebx)
* +8: dword: total number of files in folder
* +12 = +0xC: 20*byte: reserved (zeroed)
Structure of block of data for folder entry (BDFE):
* +0: dword: attributes of file:
* bit 0 (mask 1): file is read-only
* bit 1 (mask 2): file is hidden
* bit 2 (mask 4): file is system
* bit 3 (mask 8): this is the volume label (using by subfunction 5)
* bit 4 (mask 0x10): this is a folder
* bit 5 (mask 0x20): file was not archived - many archivation
programs have an option to archive only files with this bit set,
and after archiving this bit is cleared - it can be useful
for automatically creating of backup-archives as at writing
this bit is usually set
* +4: dword: encoding, equals to field +8 in the information structure
* +8: 4*byte: time of file creation
* +12 = +0xC: 4*byte: date of file creation
* +16 = +0x10: 4*byte: time of last access (read or write)
* +20 = +0x14: 4*byte: date of last access
* +24 = +0x18: 4*byte: time of last modification
* +28 = +0x1C: 4*byte: date of last modification
* +32 = +0x20: qword: file size in bytes (up to 16777216 Tb)
* +40 = +0x28: name, 264 bytes in cp866, otherwise - 520 bytes.
Time format:
* +0: byte: seconds
* +1: byte: minutes
* +2: byte: hours
* +3: byte: reserved (0)
* for example, 23.59.59 is written as (in hex) 3B 3B 17 00
Date format:
* +0: byte: day
* +1: byte: month
* +2: word: year
* for example, 25.11.1979 is written as (in hex) 19 0B BB 07
Remarks:
* If BDFE contains cp866 name, the length of BDFE is 304 bytes,
otherwise - 560 bytes.
* Name string is zero terminated, further data contain garbage.
* If files in folder were ended before requested number was read,
the function will read as many as it can, and after that return
eax=6 (EOF).
* Any folder on the disk, except for root, contains two special
entries "." and "..", identifying accordingly the folder itself
and the parent folder.
* The function allows also to read virtual folders "/", "/rd",
"/fd", "/hd[n]", thus attributes of subfolders are set to 0x10,
and times and dates are zeroed. An alternative way to get the
equipment information - subfunction 11 of function 18.
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_READ_FOLDER (1)
======================================================================
===================== Function 70, subfunction 2 =====================
============ Create/rewrite file with long names support. ============
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 2 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: number of bytes to write
* +16 = +0x10: dword: pointer to data
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx = number of written bytes (possibly 0)
Remarks:
* If a file with given name did not exist, it is created;
if it existed, it is rewritten.
* If there is not enough free space on disk, the function will
write as many as can and then return error code 8.
* The function is not supported for CD (returns error code 2).
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_CREATE_FILE (2)
======================================================================
===================== Function 70, subfunction 3 =====================
=========== Write to existing file with long names support. ==========
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 3 = subfunction number
* +4: dword: file offset (in bytes)
* +8: dword: high dword of offset (must be 0 for FAT)
* +12 = +0xC: dword: number of bytes to write
* +16 = +0x10: dword: pointer to data
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx = number of written bytes (possibly 0)
Remarks:
* The file must already exist, otherwise function returns eax=5.
* The only result of write 0 bytes is update in the file attributes
date/time of modification and access to the current date/time.
* If beginning and/or ending position is greater than file size
(except for the previous case), the file is expanded to needed
size with zero characters.
* The function is not supported for CD (returns error code 2).
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_WRITE_FILE (3)
======================================================================
============ Function 70, subfunction 4 - set end of file. ===========
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 4 = subfunction number
* +4: dword: low dword of new file size
* +8: dword: high dword of new file size (must be 0 for FAT)
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: 0 (reserved)
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx destroyed
Remarks:
* If new file size is less than old one, file will be truncated.
If new size is greater than old one, file will be expanded, and if
size difference is up to 16 MB, new space will be cleared with 0.
* If there is not enough free space on disk for expansion, the
function will expand to maximum possible size and then return
error code 8.
* The function is not supported for CD (returns error code 2).
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_SET_END (4)
======================================================================
==== Function 70, subfunction 5 - get information on file/folder. ====
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 5 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 or flags (for the root folder)
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: pointer to buffer for data (40 bytes)
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx destroyed
Information on file is returned in the BDFE format (block of data
for folder entry), explained in the description of subfunction 1,
but without filename, except the root folder.
Remarks:
* For the root folder returns the partition size,
and if encoding byte is non-zero, the volume label.
* For the device returns only the size.
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_GET_INFO (5)
======================================================================
===== Function 70, subfunction 6 - set attributes of file/folder. ====
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 6 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: pointer to buffer with attributes (32 bytes)
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx destroyed
File attributes are first 32 bytes in BDFE (block of data
for folder entry), explained in the description of subfunction 1
(that is, without name and size of file). Attribute
file/folder/volume label (bits 3,4 in dword +0) is not changed.
Byte +4 (name format) is ignored.
Remarks:
* The function does not support virtual folders such as /, /rd and
root folders like /rd/1.
* The function is not supported for CD (returns error code 2).
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_SET_INFO (6)
======================================================================
=========== Function 70, subfunction 7 - start application. ==========
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 7 = subfunction number
* +4: dword: flags field:
* bit 0: start process as debugged
* other bits are reserved and must be set to 0
* +8: dword: 0 or pointer to ASCIIZ-string with parameters
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: 0 (reserved)
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax > 0 - program is loaded, eax contains PID
* eax < 0 - an error has occurred, -eax contains
file system error code
* ebx destroyed
Remarks:
* Command line must be terminated by the character with the code 0
(ASCIIZ-string); function takes into account either all characters
up to terminating zero inclusively or first 256 character
regarding what is less.
* If the process is started as debugged, it is created in
the suspended state; to run use subfunction 5 of function 69.
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_START_APP (7)
======================================================================
========== Function 70, subfunction 8 - delete file/folder. ==========
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 8 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: 0 (reserved)
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx destroyed
Remarks:
* The function is not supported for CD (returns error code 2).
* The function can delete only empty folders (attempt to delete
nonempty folder results in error with code 10, "access denied").
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_DELETE (8)
======================================================================
============= Function 70, subfunction 9 - create folder. ============
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 9 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: 0 (reserved)
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx destroyed
Remarks:
* The function is not supported for CD (returns error code 2).
* The parent folder must already exist.
* If target folder already exists, function returns success (eax=0).
 
---------------------- Constants for registers: ----------------------
eax - SF_FILE (70)
[ebx] - SSF_CREATE_FOLDER (9)
======================================================================
============= Function 70, subfunction 10 - rename/move. =============
======================================================================
Parameters:
* eax = 70 - function number
* ebx = pointer to the information structure
Format of the information structure:
* +0: dword: 10 = subfunction number
* +4: dword: 0 (reserved)
* +8: dword: 0 (reserved)
* +12 = +0xC: dword: 0 (reserved)
* +16 = +0x10: dword: pointer to the new name/path string
* +20 = +0x14: path, general rules of names forming
Returned value:
* eax = 0 - success, otherwise file system error code
* ebx destroyed
Remarks:
* New path forming differs from general rules:
relative path relates to the target's parent folder,
absolute path relates to the partition's root folder.
======================================================================
================== Function 71 - set window caption ==================
======================================================================
Parameters:
* eax = 71 - function number
* ebx = 1
* ecx = pointer to zero terminated string,
the string may start with an encoding byte:
1 = cp866
2 = UTF-16LE
3 = UTF-8
or:
* ebx = 2
* ecx = pointer to zero terminated string
* dl = string encoding
Returned value:
* function does not return value
Remarks:
* Pass NULL in ecx to remove caption.
 
---------------------- Constants for registers: ----------------------
eax - SF_SET_CAPTION (71)
======================================================================
=============== Function 72 - send message to a window. ==============
======================================================================
 
- Subfunction 1 - send message with parameter to the active window. --
Parameters:
* eax = 72 - function number
* ebx = 1 - subfunction number
* ecx = event code: 2 or 3
* edx = parameter: key code for ecx=2, button identifier for ecx=3
Returned value:
* eax = 0 - success
* eax = 1 - buffer is full
 
---------------------- Constants for registers: ----------------------
eax - SF_SEND_MESSAGE (72)
======================================================================
===================== Function 73 - blit bitmap =====================
======================================================================
 
Parameters:
* eax = 73 - function number
 
* ebx = ROP and optional flags
31 30 29 28 6 5 4 3 0
[reserved][CR][reserved][T][B][ROP]
ROP - raster operation code
0: Copy
1-15: reserved
B - blit into the background surface
T - transparent blit
CR - blit client relative
 
* ecx = pointer to the function parameters
destination offset and clipping
+0 signed dword: destination rectangle X offset from the window
top-left corner
+4 signed dword: destination rectangle Y offset from the window
top-left corner
+8 dword: destination rectangle width
+12 dword: destination rectangle height
 
source offset and clipping
+16 signed dword: source rectangle X offset from the bitmap
top-left corner
+20 signed dword: source rectangle Y offset from the bitmap
top-left corner
+24 dword: source rectangle width
+28 dword: source rectangle height
 
+32: dword: bitmap data - must be 32bpp
+36: dword: size of the bitmap row in bytes
 
Returned value:
* function does not return value
 
---------------------- Constants for registers: ----------------------
eax - SF_BLITTER (73)
======================================================================
= Function 74, Subfunction 255, Get number of active network devices. =
======================================================================
Parameters:
* eax = 74 - function number
* bl = 255 - subfunction number
Returned value:
* eax = number of active network devices
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_DEVICE_COUNT (255)
======================================================================
======== Function 74, Subfunction 0, Get network device type. ========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 0 - subfunction number
* bh = device number
Returned value:
* eax = device type number, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_DEVICE_TYPE (0)
======================================================================
======== Function 74, Subfunction 1, Get network device name. ========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 1 - subfunction number
* bh = device number
* ecx = pointer to 64 byte buffer
Returned value:
* eax = -1 on error
* The network device name is written into the buffer, on success
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_DEVICE_NAME (1)
======================================================================
========= Function 74, Subfunction 2, Reset network device. ==========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 2 - subfunction number
* bh = device number
Returned value:
* eax = -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RESET_DEVICE (2)
======================================================================
========== Function 74, Subfunction 3, Stop network device. ==========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 3 - subfunction number
* bh = device number
Returned value:
* eax = -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_STOP_DEVICE (3)
======================================================================
=========== Function 74, Subfunction 4, Get device pointer. ==========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 4 - subfunction number
* bh = device number
Returned value:
* eax = device pointer, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_DEVICE_POINTER (4)
======================================================================
========= Function 74, Subfunction 6, Get packet TX counter. =========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 6 - subfunction number
* bh = device number
Returned value:
* eax = Number of packets sent since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_PACKET_COUNT (6)
======================================================================
========= Function 74, Subfunction 7, Get packet RX counter. =========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 7 - subfunction number
* bh = device number
Returned value:
* eax = Number of packets received since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_PACKET_COUNT (7)
======================================================================
========== Function 74, Subfunction 8, Get TX byte counter. ==========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 8 - subfunction number
* bh = device number
Returned value:
* eax = Number of bytes sent since device start (lower dword)
-1 on error
* ebx = Number of bytes sent since device start (higher dword)
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_BYTE_COUNT (8)
======================================================================
========== Function 74, Subfunction 9, Get RX byte counter. ==========
======================================================================
Parameters:
* eax = 74 - function number
* bl = 9 - subfunction number
* bh = device number
Returned value:
* eax = Number of bytes received since device start (lower dword)
-1 on error
* ebx = Number of bytes received since device start (higher dword)
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_BYTE_COUNT (9)
======================================================================
========== Function 74, Subfunction 10, Get link status. =============
======================================================================
Parameters:
* eax = 74 - function number
* bl = 10 - subfunction number
* bh = device number
Returned value:
* eax = link status, -1 on error
 
Link status:
ETH_LINK_DOWN = 0b ; Link is down
ETH_LINK_UNKNOWN= 1b ; There could be an active link
ETH_LINK_FD = 10b ; full duplex flag
ETH_LINK_10M = 100b ; 10 mbit
ETH_LINK_100M = 1000b ; 100 mbit
ETH_LINK_1G = 1100b ; gigabit
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_LINK_STATUS (10)
======================================================================
==== Function 74, Subfunction 11, Get TX error packets counter. ======
======================================================================
Parameters:
* eax = 74 - function number
* bl = 11 - subfunction number
* bh = device number
Returned value:
* eax = Number of erroneous packets received since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_PACKET_ERROR_COUNT (11)
======================================================================
=== Function 74, Subfunction 12, Get TX dropped packets counter. =====
======================================================================
Parameters:
* eax = 74 - function number
* bl = 12 - subfunction number
* bh = device number
Returned value:
* eax = Number of dropped packets since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_PACKET_DROP_COUNT (12)
======================================================================
==== Function 74, Subfunction 13, Get TX missed packets counter. =====
======================================================================
Parameters:
* eax = 74 - function number
* bl = 13 - subfunction number
* bh = device number
Returned value:
* eax = Number of missed packets since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_TX_PACKET_MISS_COUNT (13)
======================================================================
==== Function 74, Subfunction 14, Get RX error packets counter. ======
======================================================================
Parameters:
* eax = 74 - function number
* bl = 14 - subfunction number
* bh = device number
Returned value:
* eax = Number of erroneous packets received since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_PACKET_ERROR_COUNT (14)
======================================================================
=== Function 74, Subfunction 15, Get RX dropped packets counter. =====
======================================================================
Parameters:
* eax = 74 - function number
* bl = 15 - subfunction number
* bh = device number
Returned value:
* eax = Number of dropped packets since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_PACKET_DROP_COUNT (12)
======================================================================
==== Function 74, Subfunction 16, Get RX missed packets counter. =====
======================================================================
Parameters:
* eax = 74 - function number
* bl = 16 - subfunction number
* bh = device number
Returned value:
* eax = Number of missed packets since device start, -1 on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_GET (74)
bl - SSF_RX_PACKET_MISS_COUNT (16)
======================================================================
============== Function 75, Subfunction 0, Open socket. ==============
======================================================================
Parameters:
* eax = 75 - function number
* bl = 0 - subfunction number
* ecx = domain
* edx = type
* esi = protocol
Returned value:
* eax = socket number, -1 on error
* ebx = errorcode
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_OPEN (0)
======================================================================
============= Function 75, Subfunction 1, Close socket. ==============
======================================================================
Parameters:
* eax = 75 - function number
* bl = 1 - subfunction number
* ecx = socket number
Returned value:
* eax = -1 on error
* ebx = errorcode
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_CLOSE (1)
======================================================================
================== Function 75, Subfunction 2, Bind. =================
======================================================================
Parameters:
* eax = 75 - function number
* bl = 2 - subfunction number
* ecx = socket number
* edx = pointer to sockaddr structure
* esi = length of sockaddr structure
Format of SockAddr structure:
* +0: Word: Family
* +2: 14*Byte: Data
Returned value:
* eax = -1 on error
* ebx = errorcode
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_BIND (2)
======================================================================
================= Function 75, Subfunction 3, Listen. ================
======================================================================
Parameters:
* eax = 75 - function number
* bl = 3 - subfunction number
* ecx = socket number
* edx = backlog
Returned value:
* eax = -1 on error
* ebx = errorcode
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_LISTEN (3)
======================================================================
================ Function 75, Subfunction 4, Connect. ================
======================================================================
Parameters:
* eax = 75 - function number
* bl = 4 - subfunction number
* ecx = socket number
* edx = pointer to sockaddr structure
* esi = length of sockaddr structure
Format of SockAddr structure:
* +0: Word: Family
* +2: 14*Byte: Data
Returned value:
* eax = -1 on error
* ebx = errorcode
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_CONNECT (4)
======================================================================
================= Function 75, Subfunction 5, Accept. ================
======================================================================
Parameters:
* eax = 75 - function number
* bl = 5 - subfunction number
* ecx = socket number
* edx = pointer to sockaddr structure
* esi = length of sockaddr structure
Format of SockAddr structure:
* +0: Word: Family
* +2: 14*Byte: Data
Returned value:
* eax = socket number of accepted socket, -1 on error
* ebx = errorcode
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_ACCEPT (5)
======================================================================
================== Function 75, Subfunction 6, Send. =================
======================================================================
Parameters:
* eax = 75 - function number
* bl = 6 - subfunction number
* ecx = socket number
* edx = pointer to buffer
* esi = length of buffer
* edi = flags
Returned value:
* eax = number of bytes copied, -1 on error
* ebx = errorcode
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_SEND (6)
======================================================================
================ Function 75, Subfunction 7, Receive. ================
======================================================================
Parameters:
* eax = 75 - function number
* bl = 7 - subfunction number
* ecx = socket number
* edx = pointer to buffer
* esi = length of buffer
* edi = flags
Returned value:
* eax = number of bytes copied, -1 on error
* ebx = errorcode
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_RECEIVE (7)
======================================================================
=========== Function 75, Subfunction 8, Set socket options. ==========
======================================================================
Parameters:
* eax = 75 - function number
* bl = 8 - subfunction number
* ecx = socket number
* edx = pointer to optstruct
Returned value:
* eax = -1 on error
* ebx = errorcode
Remarks:
 
Optstruct:
dd level
dd optionname
dd optlength
db options...
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_SET_OPTIONS (8)
======================================================================
=========== Function 75, Subfunction 9, Get socket options. ==========
======================================================================
Parameters:
* eax = 75 - function number
* bl = 9 - subfunction number
* ecx = socket number
* edx = pointer to optstruct
Returned value:
* eax = -1 on error
* ebx = errorcode
Remarks:
 
Optstruct:
dd level
dd optionname
dd optlength
db options...
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_GET_OPTIONS (9)
======================================================================
============ Function 75, Subfunction 10, Get socketpair. ============
======================================================================
Parameters:
* eax = 75 - function number
* bl = 10 - subfunction number
Returned value:
* eax = socketnum1, -1 on error
* ebx = socketnum2, errorcode on error
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_SOCKET (75)
bl - SSF_GET_PAIR (10)
======================================================================
============ Function 76, Network options and statistics. ============
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = protocol number
* bh = device number
* bl = subfunction number
 
======================================================================
==== Function 76, Protocol 0 - Ethernet, Subfunction 0, Read MAC. ====
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 0 (Ethernet)
* bh = device number
* bl = 0 (Read MAC)
Returned value:
* eax = -1 on error, otherwise lower bits of MAC
* bx = upper bits of MAC
 
======================================================================
= Function 76, Protocol 1 - IPv4, Subfunction 0, Read # Packets sent =
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 0 (Read # packets sent)
Returned value:
* eax = number of packets sent (-1 on error)
 
======================================================================
= Function 76, Protocol 1 - IPv4, Subfunction 1, Read # Packets rcvd =
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 1 (Read # packets received)
Returned value:
* eax = number of packets received (-1 on error)
 
======================================================================
=== Function 76, Protocol 1 - IPv4, Subfunction 2, Read IP address ===
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 2 (Read IP address)
Returned value:
* eax = IP address (-1 on error)
 
======================================================================
=== Function 76, Protocol 1 - IPv4, Subfunction 3, Set IP address ====
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 3 (Set IP address)
* ecx = IP address
Returned value:
* eax = -1 on error
 
======================================================================
== Function 76, Protocol 1 - IPv4, Subfunction 4, Read DNS address ===
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 4 (Read DNS server IP address)
Returned value:
* eax = DNS server IP address (-1 on error)
 
======================================================================
=== Function 76, Protocol 1 - IPv4, Subfunction 5, Set DNS address ===
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 5 (Set DNS address)
* ecx = DNS server IP address
Returned value:
* eax = -1 on error
 
======================================================================
== Function 76, Protocol 1 - IPv4, Subfunction 6, Read subnet mask ===
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 6 (Read subnet mask)
Returned value:
* eax = subnet mask (-1 on error)
 
======================================================================
=== Function 76, Protocol 1 - IPv4, Subfunction 7, Set subnet mask ===
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 7 (Set subnet mask)
* ecx = subnet mask
Returned value:
* eax = -1 on error
 
======================================================================
===== Function 76, Protocol 1 - IPv4, Subfunction 8, Read gateway ====
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 8 (Read gateway IP address)
Returned value:
* eax = gateway IP address (-1 on error)
 
======================================================================
===== Function 76, Protocol 1 - IPv4, Subfunction 9, Set gateway =====
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 1 (IPv4)
* bh = device number
* bl = 9 (Set getway address)
* ecx = gateway IP address
Returned value:
* eax = -1 on error
 
======================================================================
= Function 76, Protocol 2 - ICMP, Subfunction 0, Read # Packets sent =
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 2 (ICMP)
* bh = device number
* bl = 0 (Read # packets sent)
Returned value:
* eax = number of packets sent (-1 on error)
 
======================================================================
= Function 76, Protocol 2 - ICMP, Subfunction 1, Read # Packets rcvd =
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 2 (ICMP)
* bh = device number
* bl = 1 (Read # packets received)
Returned value:
* eax = number of packets received (-1 on error)
 
======================================================================
= Function 76, Protocol 3 - UDP, Subfunction 0, Read # Packets sent ==
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 3 (UDP)
* bh = device number
* bl = 0 (Read # packets sent)
Returned value:
* eax = number of packets sent (-1 on error)
 
======================================================================
= Function 76, Protocol 3 - UDP, Subfunction 1, Read # Packets rcvd ==
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 3 (UDP)
* bh = device number
* bl = 1 (Read # packets received)
Returned value:
* eax = number of packets received (-1 on error)
 
======================================================================
= Function 76, Protocol 4 - TCP, Subfunction 0, Read # Packets sent ==
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 4 (TCP)
* bh = device number
* bl = 0 (Read # packets sent)
Returned value:
* eax = number of packets sent (-1 on error)
 
======================================================================
= Function 76, Protocol 4 - TCP, Subfunction 1, Read # Packets rcvd ==
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 4 (TCP)
* bh = device number
* bl = 1 (Read # packets received)
Returned value:
* eax = number of packets received (-1 on error)
 
======================================================================
= Function 76, Protocol 5 - ARP, Subfunction 0, Read # Packets sent ==
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 5 (ARP)
* bh = device number
* bl = 0 (Read # packets sent)
Returned value:
* eax = number of packets sent (-1 on error)
 
======================================================================
= Function 76, Protocol 5 - ARP, Subfunction 1, Read # Packets rcvd ==
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 5 (ARP)
* bh = device number
* bl = 1 (Read # packets received)
Returned value:
* eax = number of packets received (-1 on error)
 
======================================================================
== Function 76, Protocol 5 - ARP, Subfunction 2, Read # ARP entries ==
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 5 (ARP)
* bh = device number
* bl = 2 (Read # current entries in the ARP table)
Returned value:
* eax = number of entries (-1 on error)
 
======================================================================
==== Function 76, Protocol 5 - ARP, Subfunction 3, Read ARP entry ====
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 5 (ARP)
* bh = device number
* bl = 3 (Read ARP entry)
* ecx = ARP entry number (0 based)
* edi = ptr to buffer where ARP entry will be written
Returned value:
* eax = -1 on error
Remarks:
* ARP_entry struct is defined in ARP.inc in kernel and currently
looks like this:
struct ARP_entry
IP dd ?
MAC dp ?
Status dw ?
TTL dw ?
ends
 
======================================================================
===== Function 76, Protocol 5 - ARP, Subfunction 4, Add ARP entry ====
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 5 (ARP)
* bh = device number
* bl = 4 (Add ARP entry)
* esi = ptr to buffer holding ARP entry
Returned value:
* eax = -1 on error
Remarks:
* See previous function for details on ARP entry.
 
======================================================================
=== Function 76, Protocol 5 - ARP, Subfunction 5, Remove ARP entry ===
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 5 (ARP)
* bh = device number
* bl = 5 (Remove ARP entry)
* ecx = ARP entry number (0 based), use -1 to clear whole ARP table.
Returned value:
* eax = -1 on error
 
======================================================================
=== Function 76, Protocol 5 - ARP, Subfunction 6, Send ARP announce ==
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 5 (ARP)
* bh = device number
* bl = 6 (Send ARP announce)
Returned value:
* eax = -1 on error
 
======================================================================
=== Function 76, Protocol 5 - ARP, Subfunction 7, Read # conflicts ===
======================================================================
Parameters:
* eax = 76 - function number
* high half of ebx = 5 (ARP)
* bh = device number
* bl = 7 (Read # IP address conflicts that have occured)
Returned value:
* eax = # IP address conflicts (-1 on error)
 
---------------------- Constants for registers: ----------------------
eax - SF_NETWORK_PROTOCOL (76)
======================================================================
========== Function 77, Subfunction 0, Create futex object ===========
======================================================================
Parameters:
* eax = 77 - function number
* ebx = 0 - subfunction number
* ecx = pointer to futex dword
Returned value:
* eax = futex handle, 0 on error
Remarks:
* Use subfunction 1 to destroy the futex.
The kernel destroys the futexes automatically when the process
terminates.
 
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_CREATE (0)
======================================================================
========= Function 77, Subfunction 1, Destroy futex object ===========
======================================================================
Parameters:
* eax = 77 - function number
* ebx = 1 - subfunction number
* ecx = futex handle
Returned value:
* eax = 0 - successfull, -1 on error
Remarks:
* The futex handle must have been created by subfunction 0
 
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_DESTROY (1)
======================================================================
=============== Function 77, Subfunction 2, Futex wait ===============
======================================================================
Parameters:
* eax = 77 - function number
* ebx = 2 - subfunction number
* ecx = futex handle
* edx = control value
* esi = timeout in system ticks or 0 for infinity
Returned value:
* eax = 0 - successfull
-1 - timeout
-2 - futex dword does not have the same value as edx
Remarks:
* This functionn tests that the value at the futex dword still
contains the expected control value, and if so, then sleeps
waiting for a wake operation on the futex.
* The futex handle must have been created by subfunction 0
 
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_WAIT (2)
======================================================================
=============== Function 77, Subfunction 3, Futex wake ===============
======================================================================
Parameters:
* eax = 77 - function number
* ebx = 3 - subfunction number
* ecx = futex handle
* edx = number of waiters to wake
Returned value:
* eax = number of waiters that were woken up
 
Remarks:
* This function wakes at most edx of the waiters that are
waiting (e.g., inside futex wait) on the futex dword
* The futex handle must have been created by subfunction 0
 
---------------------- Constants for registers: ----------------------
eax - SF_FUTEX (77)
ebx - SSF_WAKE (3)
======================================================================
=== Function 80 - file system interface with parameter of encoding ===
======================================================================
Parameters:
* eax = 80
* ebx = pointer to the information structure
Returned value:
* eax = 0 - success; otherwise file system error code
* some subfunctions return value in other registers too
General format of the information structure:
* +0: dword: subfunction number
* +4: dword: offset in file or folder
* +8: dword: higher part of offset or flags
* +12 = +0xC: dword: size of data
* +16 = +0x10: dword: pointer to data
* +20 = +0x14: dword: string encoding:
1 = cp866
2 = UTF-16LE
3 = UTF-8
0 = default (supports encoding byte at the start of the string)
* +24 = +0x18: dword: pointer to zero terminated string with path
 
The rest is similar to sysfunction 70.
 
======================================================================
=============== Function -1 - terminate thread/process ===============
======================================================================
Parameters:
* eax = -1 - function number
Returned value:
* function does not return neither value nor control
Remarks:
* If the process did not create threads obviously, it has only
one thread, which termination results in process termination.
* If the current thread is last in the process, its termination
also results in process terminates.
* This function terminates the current thread. Other thread can be
killed by call to subfunction 2 of function 18.
 
---------------------- Constants for registers: ----------------------
eax - SF_TERMINATE_PROCESS (-1)
======================================================================
=========================== List of events ===========================
======================================================================
Next event can be retrieved by the call of one from functions 10
(to wait for event), 11 (to check without waiting), 23
(to wait during the given time).
These functions return only those events, which enter into a mask set
by function 40. By default it is first three,
there is enough for most applications.
Codes of events:
* 1 = redraw event (is reset by call to function 0)
* 2 = key on keyboard is pressed (acts, only when the window is
active) or hotkey is pressed; is reset, when all keys from
the buffer are read out by function 2
* 3 = button is pressed, defined earlier by function 8
(or close button, created implicitly by function 0;
minimize button is handled by the system and sends no message;
acts, only when the window is active;
is reset when all buttons from the buffer
are read out by function 17)
* 4 = reserved (in current implementation never comes even after
unmasking by function 40)
* 5 = kernel finished redrawing of the desktop background
* 6 = mouse event (something happened - button pressing or moving;
is reset at reading)
* 7 = IPC event (see function 60 -
Inter Process Communication; is reset at reading)
* 8 = network event (is reset at reading)
* 9 = debug event (is reset at reading; see
debug subsystem)
* 16..31 = event with appropriate IRQ
(16=IRQ0, 31=IRQ15) (is reset after reading all IRQ data)
 
======================================================================
=================== Error codes of the file system ===================
======================================================================
* 0 = success
* 2 = function is not supported for the given file system
* 3 = unknown file system
* 5 = file not found
* 6 = end of file, EOF
* 7 = pointer lies outside of application memory
* 8 = disk is full
* 9 = file system error
* 10 = access denied
* 11 = device error
* 12 = file system requires more memory
 
Application start functions can return also following errors:
* 30 = 0x1E = not enough memory
* 31 = 0x1F = file is not executable
* 32 = 0x20 = too many processes
/kernel/branches/kolibrios-pe-clevermouse/docs/doxygen/doxygen.cfg
0,0 → 1,2612
# Doxyfile 1.9.1
 
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
# All text after a double hash (##) is considered a comment and is placed in
# front of the TAG it is preceding.
#
# All text after a single hash (#) is considered a comment and will be ignored.
# The format is:
# TAG = value [value, ...]
# For lists, items can also be appended using:
# TAG += value [value, ...]
# Values that contain spaces should be placed between quotes (\" \").
 
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
 
# This tag specifies the encoding used for all characters in the configuration
# file that follow. The default is UTF-8 which is also the encoding used for all
# text before the first occurrence of this tag. Doxygen uses libiconv (or the
# iconv built into libc) for the transcoding. See
# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
# The default value is: UTF-8.
 
DOXYFILE_ENCODING = UTF-8
 
# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
# double-quotes, unless you are using Doxywizard) that should identify the
# project for which the documentation is generated. This name is used in the
# title of most generated pages and in a few other places.
# The default value is: My Project.
 
PROJECT_NAME = "KolibriOS kernel"
 
# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
# could be handy for archiving the generated documentation or if some version
# control system is used.
 
PROJECT_NUMBER =
 
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
# quick idea about the purpose of the project. Keep the description short.
 
PROJECT_BRIEF =
 
# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
# in the documentation. The maximum height of the logo should not exceed 55
# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
# the logo to the output directory.
 
PROJECT_LOGO =
 
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
# into which the generated documentation will be written. If a relative path is
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
 
OUTPUT_DIRECTORY =
 
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
# will distribute the generated files over these directories. Enabling this
# option can be useful when feeding doxygen a huge amount of source files, where
# putting all generated files in the same directory would otherwise causes
# performance problems for the file system.
# The default value is: NO.
 
CREATE_SUBDIRS = NO
 
# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
# characters to appear in the names of generated files. If set to NO, non-ASCII
# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
# U+3044.
# The default value is: NO.
 
ALLOW_UNICODE_NAMES = NO
 
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
# Ukrainian and Vietnamese.
# The default value is: English.
 
OUTPUT_LANGUAGE = English
 
# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all generated output in the proper direction.
# Possible values are: None, LTR, RTL and Context.
# The default value is: None.
 
OUTPUT_TEXT_DIRECTION = None
 
# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES.
 
BRIEF_MEMBER_DESC = YES
 
# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
# description of a member or function before the detailed description
#
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
# The default value is: YES.
 
REPEAT_BRIEF = YES
 
# This tag implements a quasi-intelligent brief description abbreviator that is
# used to form the text in various listings. Each string in this list, if found
# as the leading text of the brief description, will be stripped from the text
# and the result, after processing the whole list, is used as the annotated
# text. Otherwise, the brief description is used as-is. If left blank, the
# following values are used ($name is automatically replaced with the name of
# the entity):The $name class, The $name widget, The $name file, is, provides,
# specifies, contains, represents, a, an and the.
 
ABBREVIATE_BRIEF = "The $name class" \
"The $name widget" \
"The $name file" \
is \
provides \
specifies \
contains \
represents \
a \
an \
the
 
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# doxygen will generate a detailed section even if there is only a brief
# description.
# The default value is: NO.
 
ALWAYS_DETAILED_SEC = NO
 
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
# The default value is: NO.
 
INLINE_INHERITED_MEMB = NO
 
# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used
# The default value is: YES.
 
FULL_PATH_NAMES = YES
 
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
# Stripping is only done if one of the specified strings matches the left-hand
# part of the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the path to
# strip.
#
# Note that you can specify absolute paths here, but also relative paths, which
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
 
STRIP_FROM_PATH =
 
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
# header file to include in order to use a class. If left blank only the name of
# the header file containing the class definition is used. Otherwise one should
# specify the list of include paths that are normally passed to the compiler
# using the -I flag.
 
STRIP_FROM_INC_PATH =
 
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
# less readable) file names. This can be useful is your file systems doesn't
# support long names like on DOS, Mac, or CD-ROM.
# The default value is: NO.
 
SHORT_NAMES = NO
 
# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
# first line (until the first dot) of a Javadoc-style comment as the brief
# description. If set to NO, the Javadoc-style will behave just like regular Qt-
# style comments (thus requiring an explicit @brief command for a brief
# description.)
# The default value is: NO.
 
JAVADOC_AUTOBRIEF = NO
 
# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
# such as
# /***************
# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
# Javadoc-style will behave just like regular comments and it will not be
# interpreted by doxygen.
# The default value is: NO.
 
JAVADOC_BANNER = NO
 
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
# requiring an explicit \brief command for a brief description.)
# The default value is: NO.
 
QT_AUTOBRIEF = NO
 
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
# a brief description. This used to be the default behavior. The new default is
# to treat a multi-line C++ comment block as a detailed description. Set this
# tag to YES if you prefer the old behavior instead.
#
# Note that setting this tag to YES also means that rational rose comments are
# not recognized any more.
# The default value is: NO.
 
MULTILINE_CPP_IS_BRIEF = NO
 
# By default Python docstrings are displayed as preformatted text and doxygen's
# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the
# doxygen's special commands can be used and the contents of the docstring
# documentation blocks is shown as doxygen documentation.
# The default value is: YES.
 
PYTHON_DOCSTRING = YES
 
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
 
INHERIT_DOCS = YES
 
# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
# page for each member. If set to NO, the documentation of a member will be part
# of the file/class/namespace that contains it.
# The default value is: NO.
 
SEPARATE_MEMBER_PAGES = NO
 
# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
# uses this value to replace tabs by spaces in code fragments.
# Minimum value: 1, maximum value: 16, default value: 4.
 
TAB_SIZE = 4
 
# This tag can be used to specify a number of aliases that act as commands in
# the documentation. An alias has the form:
# name=value
# For example adding
# "sideeffect=@par Side Effects:\n"
# will allow you to put the command \sideeffect (or @sideeffect) in the
# documentation, which will result in a user-defined paragraph with heading
# "Side Effects:". You can put \n's in the value part of an alias to insert
# newlines (in the resulting output). You can put ^^ in the value part of an
# alias to insert a newline as if a physical newline was in the original file.
# When you need a literal { or } or , in the value part of an alias you have to
# escape them by means of a backslash (\), this can lead to conflicts with the
# commands \{ and \} for these it is advised to use the version @{ and @} or use
# a double escape (\\{ and \\})
 
ALIASES =
 
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
# only. Doxygen will then generate output that is more tailored for C. For
# instance, some of the names that are used will be different. The list of all
# members will be omitted, etc.
# The default value is: NO.
 
OPTIMIZE_OUTPUT_FOR_C = NO
 
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
# Python sources only. Doxygen will then generate output that is more tailored
# for that language. For instance, namespaces will be presented as packages,
# qualified scopes will look different, etc.
# The default value is: NO.
 
OPTIMIZE_OUTPUT_JAVA = NO
 
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
# sources. Doxygen will then generate output that is tailored for Fortran.
# The default value is: NO.
 
OPTIMIZE_FOR_FORTRAN = NO
 
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
# sources. Doxygen will then generate output that is tailored for VHDL.
# The default value is: NO.
 
OPTIMIZE_OUTPUT_VHDL = NO
 
# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
# sources only. Doxygen will then generate output that is more tailored for that
# language. For instance, namespaces will be presented as modules, types will be
# separated into more groups, etc.
# The default value is: NO.
 
OPTIMIZE_OUTPUT_SLICE = NO
 
# Doxygen selects the parser to use depending on the extension of the files it
# parses. With this tag you can assign which parser to use for a given
# extension. Doxygen has a built-in mapping, but you can override or extend it
# using this tag. The format is ext=language, where ext is a file extension, and
# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,
# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, VHDL,
# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
# tries to guess whether the code is fixed or free formatted code, this is the
# default for Fortran type files). For instance to make doxygen treat .inc files
# as Fortran files (default is PHP), and .f files as C (default is Fortran),
# use: inc=Fortran f=C.
#
# Note: For files without extension you can use no_extension as a placeholder.
#
# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
# the files are not read by doxygen. When specifying no_extension you should add
# * to the FILE_PATTERNS.
#
# Note see also the list of default file extension mappings.
 
EXTENSION_MAPPING = inc=C asm=C
 
# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
# according to the Markdown format, which allows for more readable
# documentation. See https://daringfireball.net/projects/markdown/ for details.
# The output of markdown processing is further processed by doxygen, so you can
# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
# case of backward compatibilities issues.
# The default value is: YES.
 
MARKDOWN_SUPPORT = YES
 
# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
# to that level are automatically included in the table of contents, even if
# they do not have an id attribute.
# Note: This feature currently applies only to Markdown headings.
# Minimum value: 0, maximum value: 99, default value: 5.
# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
 
TOC_INCLUDE_HEADINGS = 5
 
# When enabled doxygen tries to link words that correspond to documented
# classes, or namespaces to their corresponding documentation. Such a link can
# be prevented in individual cases by putting a % sign in front of the word or
# globally by setting AUTOLINK_SUPPORT to NO.
# The default value is: YES.
 
AUTOLINK_SUPPORT = YES
 
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
# to include (a tag file for) the STL sources as input, then you should set this
# tag to YES in order to let doxygen match functions declarations and
# definitions whose arguments contain STL classes (e.g. func(std::string);
# versus func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
# The default value is: NO.
 
BUILTIN_STL_SUPPORT = NO
 
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
# The default value is: NO.
 
CPP_CLI_SUPPORT = NO
 
# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
# will parse them like normal C++ but will assume all classes use public instead
# of private inheritance when no explicit protection keyword is present.
# The default value is: NO.
 
SIP_SUPPORT = NO
 
# For Microsoft's IDL there are propget and propput attributes to indicate
# getter and setter methods for a property. Setting this option to YES will make
# doxygen to replace the get and set methods by a property in the documentation.
# This will only work if the methods are indeed getting or setting a simple
# type. If this is not the case, or you want to show the methods anyway, you
# should set this option to NO.
# The default value is: YES.
 
IDL_PROPERTY_SUPPORT = YES
 
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.
 
DISTRIBUTE_GROUP_DOC = NO
 
# If one adds a struct or class to a group and this option is enabled, then also
# any nested class or struct is added to the same group. By default this option
# is disabled and one has to add nested compounds explicitly via \ingroup.
# The default value is: NO.
 
GROUP_NESTED_COMPOUNDS = NO
 
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent
# subgrouping. Alternatively, this can be done per class using the
# \nosubgrouping command.
# The default value is: YES.
 
SUBGROUPING = YES
 
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
# are shown inside the group in which they are included (e.g. using \ingroup)
# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
# and RTF).
#
# Note that this feature does not work in combination with
# SEPARATE_MEMBER_PAGES.
# The default value is: NO.
 
INLINE_GROUPED_CLASSES = NO
 
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
# with only public data fields or simple typedef fields will be shown inline in
# the documentation of the scope in which they are defined (i.e. file,
# namespace, or group documentation), provided this scope is documented. If set
# to NO, structs, classes, and unions are shown on a separate page (for HTML and
# Man pages) or section (for LaTeX and RTF).
# The default value is: NO.
 
INLINE_SIMPLE_STRUCTS = NO
 
# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
# enum is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
# namespace, or class. And the struct will be named TypeS. This can typically be
# useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
# The default value is: NO.
 
TYPEDEF_HIDES_STRUCT = NO
 
# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
# cache is used to resolve symbols given their name and scope. Since this can be
# an expensive process and often the same symbol appears multiple times in the
# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
# doxygen will become slower. If the cache is too large, memory is wasted. The
# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
# symbols. At the end of a run doxygen will report the cache usage and suggest
# the optimal cache size from a speed point of view.
# Minimum value: 0, maximum value: 9, default value: 0.
 
LOOKUP_CACHE_SIZE = 0
 
# The NUM_PROC_THREADS specifies the number threads doxygen is allowed to use
# during processing. When set to 0 doxygen will based this on the number of
# cores available in the system. You can set it explicitly to a value larger
# than 0 to get more control over the balance between CPU load and processing
# speed. At this moment only the input processing can be done using multiple
# threads. Since this is still an experimental feature the default is set to 1,
# which efficively disables parallel processing. Please report any issues you
# encounter. Generating dot graphs in parallel is controlled by the
# DOT_NUM_THREADS setting.
# Minimum value: 0, maximum value: 32, default value: 1.
 
NUM_PROC_THREADS = 1
 
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
 
# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
# documentation are documented, even if no documentation was available. Private
# class members and static file members will be hidden unless the
# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
# Note: This will also disable the warnings about undocumented members that are
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
 
EXTRACT_ALL = YES
 
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.
 
EXTRACT_PRIVATE = NO
 
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
# methods of a class will be included in the documentation.
# The default value is: NO.
 
EXTRACT_PRIV_VIRTUAL = NO
 
# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
# scope will be included in the documentation.
# The default value is: NO.
 
EXTRACT_PACKAGE = NO
 
# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
# included in the documentation.
# The default value is: NO.
 
EXTRACT_STATIC = NO
 
# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
# locally in source files will be included in the documentation. If set to NO,
# only classes defined in header files are included. Does not have any effect
# for Java sources.
# The default value is: YES.
 
EXTRACT_LOCAL_CLASSES = YES
 
# This flag is only useful for Objective-C code. If set to YES, local methods,
# which are defined in the implementation section but not in the interface are
# included in the documentation. If set to NO, only methods in the interface are
# included.
# The default value is: NO.
 
EXTRACT_LOCAL_METHODS = NO
 
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
# 'anonymous_namespace{file}', where file will be replaced with the base name of
# the file that contains the anonymous namespace. By default anonymous namespace
# are hidden.
# The default value is: NO.
 
EXTRACT_ANON_NSPACES = NO
 
# If this flag is set to YES, the name of an unnamed parameter in a declaration
# will be determined by the corresponding definition. By default unnamed
# parameters remain unnamed in the output.
# The default value is: YES.
 
RESOLVE_UNNAMED_PARAMS = YES
 
# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
# undocumented members inside documented classes or files. If set to NO these
# members will be included in the various overviews, but no documentation
# section is generated. This option has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
 
HIDE_UNDOC_MEMBERS = NO
 
# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
# undocumented classes that are normally visible in the class hierarchy. If set
# to NO, these classes will be included in the various overviews. This option
# has no effect if EXTRACT_ALL is enabled.
# The default value is: NO.
 
HIDE_UNDOC_CLASSES = NO
 
# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
# declarations. If set to NO, these declarations will be included in the
# documentation.
# The default value is: NO.
 
HIDE_FRIEND_COMPOUNDS = NO
 
# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
# documentation blocks found inside the body of a function. If set to NO, these
# blocks will be appended to the function's detailed documentation block.
# The default value is: NO.
 
HIDE_IN_BODY_DOCS = NO
 
# The INTERNAL_DOCS tag determines if documentation that is typed after a
# \internal command is included. If the tag is set to NO then the documentation
# will be excluded. Set it to YES to include the internal documentation.
# The default value is: NO.
 
INTERNAL_DOCS = NO
 
# With the correct setting of option CASE_SENSE_NAMES doxygen will better be
# able to match the capabilities of the underlying filesystem. In case the
# filesystem is case sensitive (i.e. it supports files in the same directory
# whose names only differ in casing), the option must be set to YES to properly
# deal with such files in case they appear in the input. For filesystems that
# are not case sensitive the option should be be set to NO to properly deal with
# output files written for symbols that only differ in casing, such as for two
# classes, one named CLASS and the other named Class, and to also support
# references to files without having to specify the exact matching casing. On
# Windows (including Cygwin) and MacOS, users should typically set this option
# to NO, whereas on Linux or other Unix flavors it should typically be set to
# YES.
# The default value is: system dependent.
 
CASE_SENSE_NAMES = NO
 
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
# their full class and namespace scopes in the documentation. If set to YES, the
# scope will be hidden.
# The default value is: NO.
 
HIDE_SCOPE_NAMES = NO
 
# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
# append additional text to a page's title, such as Class Reference. If set to
# YES the compound reference will be hidden.
# The default value is: NO.
 
HIDE_COMPOUND_REFERENCE= NO
 
# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
# the files that are included by a file in the documentation of that file.
# The default value is: YES.
 
SHOW_INCLUDE_FILES = YES
 
# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
# grouped member an include statement to the documentation, telling the reader
# which file to include in order to use the member.
# The default value is: NO.
 
SHOW_GROUPED_MEMB_INC = NO
 
# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
# files with double quotes in the documentation rather than with sharp brackets.
# The default value is: NO.
 
FORCE_LOCAL_INCLUDES = NO
 
# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
# documentation for inline members.
# The default value is: YES.
 
INLINE_INFO = YES
 
# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
# (detailed) documentation of file and class members alphabetically by member
# name. If set to NO, the members will appear in declaration order.
# The default value is: YES.
 
SORT_MEMBER_DOCS = YES
 
# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
# descriptions of file, namespace and class members alphabetically by member
# name. If set to NO, the members will appear in declaration order. Note that
# this will also influence the order of the classes in the class list.
# The default value is: NO.
 
SORT_BRIEF_DOCS = NO
 
# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
# (brief and detailed) documentation of class members so that constructors and
# destructors are listed first. If set to NO the constructors will appear in the
# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
# member documentation.
# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
# detailed member documentation.
# The default value is: NO.
 
SORT_MEMBERS_CTORS_1ST = NO
 
# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
# of group names into alphabetical order. If set to NO the group names will
# appear in their defined order.
# The default value is: NO.
 
SORT_GROUP_NAMES = NO
 
# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
# fully-qualified names, including namespaces. If set to NO, the class list will
# be sorted only by class name, not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
# Note: This option applies only to the class list, not to the alphabetical
# list.
# The default value is: NO.
 
SORT_BY_SCOPE_NAME = NO
 
# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
# type resolution of all parameters of a function it will reject a match between
# the prototype and the implementation of a member function even if there is
# only one candidate or it is obvious which candidate to choose by doing a
# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
# accept a match between prototype and implementation in such cases.
# The default value is: NO.
 
STRICT_PROTO_MATCHING = NO
 
# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
# list. This list is created by putting \todo commands in the documentation.
# The default value is: YES.
 
GENERATE_TODOLIST = YES
 
# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
# list. This list is created by putting \test commands in the documentation.
# The default value is: YES.
 
GENERATE_TESTLIST = YES
 
# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
# list. This list is created by putting \bug commands in the documentation.
# The default value is: YES.
 
GENERATE_BUGLIST = YES
 
# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
# the deprecated list. This list is created by putting \deprecated commands in
# the documentation.
# The default value is: YES.
 
GENERATE_DEPRECATEDLIST= YES
 
# The ENABLED_SECTIONS tag can be used to enable conditional documentation
# sections, marked by \if <section_label> ... \endif and \cond <section_label>
# ... \endcond blocks.
 
ENABLED_SECTIONS =
 
# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
# initial value of a variable or macro / define can have for it to appear in the
# documentation. If the initializer consists of more lines than specified here
# it will be hidden. Use a value of 0 to hide initializers completely. The
# appearance of the value of individual variables and macros / defines can be
# controlled using \showinitializer or \hideinitializer command in the
# documentation regardless of this setting.
# Minimum value: 0, maximum value: 10000, default value: 30.
 
MAX_INITIALIZER_LINES = 30
 
# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
# the bottom of the documentation of classes and structs. If set to YES, the
# list will mention the files that were used to generate the documentation.
# The default value is: YES.
 
SHOW_USED_FILES = YES
 
# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
# will remove the Files entry from the Quick Index and from the Folder Tree View
# (if specified).
# The default value is: YES.
 
SHOW_FILES = YES
 
# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
# page. This will remove the Namespaces entry from the Quick Index and from the
# Folder Tree View (if specified).
# The default value is: YES.
 
SHOW_NAMESPACES = YES
 
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
# popen()) the command command input-file, where command is the value of the
# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
# by doxygen. Whatever the program writes to standard output is used as the file
# version. For an example see the documentation.
 
FILE_VERSION_FILTER =
 
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. To create the layout file
# that represents doxygen's defaults, run doxygen with the -l option. You can
# optionally specify a file name after the option, if omitted DoxygenLayout.xml
# will be used as the name of the layout file.
#
# Note that if you run doxygen from a directory containing a file called
# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
# tag is left empty.
 
LAYOUT_FILE =
 
# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
# the reference definitions. This must be a list of .bib files. The .bib
# extension is automatically appended if omitted. This requires the bibtex tool
# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
# For LaTeX the style of the bibliography can be controlled using
# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
# search path. See also \cite for info how to create references.
 
CITE_BIB_FILES =
 
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
 
# The QUIET tag can be used to turn on/off the messages that are generated to
# standard output by doxygen. If QUIET is set to YES this implies that the
# messages are off.
# The default value is: NO.
 
QUIET = NO
 
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
# this implies that the warnings are on.
#
# Tip: Turn warnings on while writing the documentation.
# The default value is: YES.
 
WARNINGS = YES
 
# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
# will automatically be disabled.
# The default value is: YES.
 
WARN_IF_UNDOCUMENTED = YES
 
# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
# potential errors in the documentation, such as not documenting some parameters
# in a documented function, or documenting parameters that don't exist or using
# markup commands wrongly.
# The default value is: YES.
 
WARN_IF_DOC_ERROR = YES
 
# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
# are documented, but have no documentation for their parameters or return
# value. If set to NO, doxygen will only warn about wrong or incomplete
# parameter documentation, but not about the absence of documentation. If
# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
# The default value is: NO.
 
WARN_NO_PARAMDOC = NO
 
# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS
# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but
# at the end of the doxygen process doxygen will return with a non-zero status.
# Possible values are: NO, YES and FAIL_ON_WARNINGS.
# The default value is: NO.
 
WARN_AS_ERROR = NO
 
# The WARN_FORMAT tag determines the format of the warning messages that doxygen
# can produce. The string should contain the $file, $line, and $text tags, which
# will be replaced by the file and line number from which the warning originated
# and the warning text. Optionally the format may contain $version, which will
# be replaced by the version of the file (if it could be obtained via
# FILE_VERSION_FILTER)
# The default value is: $file:$line: $text.
 
WARN_FORMAT = "$file:$line: $text"
 
# The WARN_LOGFILE tag can be used to specify a file to which warning and error
# messages should be written. If left blank the output is written to standard
# error (stderr).
 
WARN_LOGFILE =
 
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
 
# The INPUT tag is used to specify the files and/or directories that contain
# documented source files. You may enter file names like myfile.cpp or
# directories like /usr/src/myproject. Separate the files or directories with
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
 
INPUT =
 
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
# documentation (see:
# https://www.gnu.org/software/libiconv/) for the list of possible encodings.
# The default value is: UTF-8.
 
INPUT_ENCODING = UTF-8
 
# If the value of the INPUT tag contains directories, you can use the
# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
# *.h) to filter out the source-files in the directories.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# read by doxygen.
#
# Note the list of default checked file patterns might differ from the list of
# default file extension mappings.
#
# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment),
# *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, *.vhdl,
# *.ucf, *.qsf and *.ice.
 
FILE_PATTERNS = *.inc *.asm
 
# The RECURSIVE tag can be used to specify whether or not subdirectories should
# be searched for input files as well.
# The default value is: NO.
 
RECURSIVE = YES
 
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
#
# Note that relative paths are relative to the directory from which doxygen is
# run.
 
EXCLUDE =
 
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
# The default value is: NO.
 
EXCLUDE_SYMLINKS = NO
 
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
# certain files from those directories.
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories for example use the pattern */test/*
 
EXCLUDE_PATTERNS =
 
# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
# (namespaces, classes, functions, etc.) that should be excluded from the
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
#
# Note that the wildcards are matched against the file with absolute path, so to
# exclude all test directories use the pattern */test/*
 
EXCLUDE_SYMBOLS =
 
# The EXAMPLE_PATH tag can be used to specify one or more files or directories
# that contain example code fragments that are included (see the \include
# command).
 
EXAMPLE_PATH =
 
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
# *.h) to filter out the source-files in the directories. If left blank all
# files are included.
 
EXAMPLE_PATTERNS = *
 
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
# searched for input files to be used with the \include or \dontinclude commands
# irrespective of the value of the RECURSIVE tag.
# The default value is: NO.
 
EXAMPLE_RECURSIVE = NO
 
# The IMAGE_PATH tag can be used to specify one or more files or directories
# that contain images that are to be included in the documentation (see the
# \image command).
 
IMAGE_PATH =
 
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
# by executing (via popen()) the command:
#
# <filter> <input-file>
#
# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
# name of an input file. Doxygen will then use the output that the filter
# program writes to standard output. If FILTER_PATTERNS is specified, this tag
# will be ignored.
#
# Note that the filter must not add or remove lines; it is applied before the
# code is scanned, but not when the output code is generated. If lines are added
# or removed, the anchors will not be placed correctly.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
 
INPUT_FILTER =
 
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
# basis. Doxygen will compare the file name with each pattern and apply the
# filter if there is a match. The filters are a list of the form: pattern=filter
# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
# patterns match the file name, INPUT_FILTER is applied.
#
# Note that for custom extensions or not directly supported extensions you also
# need to set EXTENSION_MAPPING for the extension otherwise the files are not
# properly processed by doxygen.
 
FILTER_PATTERNS =
 
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
# INPUT_FILTER) will also be used to filter the input files that are used for
# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
# The default value is: NO.
 
FILTER_SOURCE_FILES = NO
 
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
# it is also possible to disable source filtering for a specific pattern using
# *.ext= (so without naming a filter).
# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
 
FILTER_SOURCE_PATTERNS =
 
# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
# is part of the input, its contents will be placed on the main page
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
 
USE_MDFILE_AS_MAINPAGE =
 
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
 
# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
# generated. Documented entities will be cross-referenced with these sources.
#
# Note: To get rid of all source code in the generated output, make sure that
# also VERBATIM_HEADERS is set to NO.
# The default value is: NO.
 
SOURCE_BROWSER = NO
 
# Setting the INLINE_SOURCES tag to YES will include the body of functions,
# classes and enums directly into the documentation.
# The default value is: NO.
 
INLINE_SOURCES = NO
 
# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
# special comment blocks from generated source code fragments. Normal C, C++ and
# Fortran comments will always remain visible.
# The default value is: YES.
 
STRIP_CODE_COMMENTS = YES
 
# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
# entity all documented functions referencing it will be listed.
# The default value is: NO.
 
REFERENCED_BY_RELATION = NO
 
# If the REFERENCES_RELATION tag is set to YES then for each documented function
# all documented entities called/used by that function will be listed.
# The default value is: NO.
 
REFERENCES_RELATION = NO
 
# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
# to YES then the hyperlinks from functions in REFERENCES_RELATION and
# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
# link to the documentation.
# The default value is: YES.
 
REFERENCES_LINK_SOURCE = YES
 
# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
# source code will show a tooltip with additional information such as prototype,
# brief description and links to the definition and documentation. Since this
# will make the HTML file larger and loading of large files a bit slower, you
# can opt to disable this feature.
# The default value is: YES.
# This tag requires that the tag SOURCE_BROWSER is set to YES.
 
SOURCE_TOOLTIPS = YES
 
# If the USE_HTAGS tag is set to YES then the references to source code will
# point to the HTML generated by the htags(1) tool instead of doxygen built-in
# source browser. The htags tool is part of GNU's global source tagging system
# (see https://www.gnu.org/software/global/global.html). You will need version
# 4.8.6 or higher.
#
# To use it do the following:
# - Install the latest version of global
# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
# - Make sure the INPUT points to the root of the source tree
# - Run doxygen as normal
#
# Doxygen will invoke htags (and that will in turn invoke gtags), so these
# tools must be available from the command line (i.e. in the search path).
#
# The result: instead of the source browser generated by doxygen, the links to
# source code will now point to the output of htags.
# The default value is: NO.
# This tag requires that the tag SOURCE_BROWSER is set to YES.
 
USE_HTAGS = NO
 
# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
# verbatim copy of the header file for each class for which an include is
# specified. Set to NO to disable this.
# See also: Section \class.
# The default value is: YES.
 
VERBATIM_HEADERS = YES
 
# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
# clang parser (see:
# http://clang.llvm.org/) for more accurate parsing at the cost of reduced
# performance. This can be particularly helpful with template rich C++ code for
# which doxygen's built-in parser lacks the necessary type information.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
# The default value is: NO.
 
CLANG_ASSISTED_PARSING = NO
 
# If clang assisted parsing is enabled and the CLANG_ADD_INC_PATHS tag is set to
# YES then doxygen will add the directory of each input to the include path.
# The default value is: YES.
 
CLANG_ADD_INC_PATHS = YES
 
# If clang assisted parsing is enabled you can provide the compiler with command
# line options that you would normally use when invoking the compiler. Note that
# the include paths will already be set by doxygen for the files and directories
# specified with INPUT and INCLUDE_PATH.
# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
 
CLANG_OPTIONS =
 
# If clang assisted parsing is enabled you can provide the clang parser with the
# path to the directory containing a file called compile_commands.json. This
# file is the compilation database (see:
# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the
# options used when the source files were built. This is equivalent to
# specifying the -p option to a clang tool, such as clang-check. These options
# will then be passed to the parser. Any options specified with CLANG_OPTIONS
# will be added as well.
# Note: The availability of this option depends on whether or not doxygen was
# generated with the -Duse_libclang=ON option for CMake.
 
CLANG_DATABASE_PATH =
 
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
 
# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
# compounds will be generated. Enable this if the project contains a lot of
# classes, structs, unions or interfaces.
# The default value is: YES.
 
ALPHABETICAL_INDEX = YES
 
# In case all classes in a project start with a common prefix, all classes will
# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
# can be used to specify a prefix (or a list of prefixes) that should be ignored
# while generating the index headers.
# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
 
IGNORE_PREFIX =
 
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
 
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
 
GENERATE_HTML = YES
 
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: html.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_OUTPUT = html
 
# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
# generated HTML page (for example: .htm, .php, .asp).
# The default value is: .html.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_FILE_EXTENSION = .html
 
# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
# each generated HTML page. If the tag is left blank doxygen will generate a
# standard header.
#
# To get valid HTML the header file that includes any scripts and style sheets
# that doxygen needs, which is dependent on the configuration options used (e.g.
# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
# default header using
# doxygen -w html new_header.html new_footer.html new_stylesheet.css
# YourConfigFile
# and then modify the file new_header.html. See also section "Doxygen usage"
# for information on how to generate the default header that doxygen normally
# uses.
# Note: The header is subject to change so you typically have to regenerate the
# default header when upgrading to a newer version of doxygen. For a description
# of the possible markers and block names see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_HEADER =
 
# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
# generated HTML page. If the tag is left blank doxygen will generate a standard
# footer. See HTML_HEADER for more information on how to generate a default
# footer and what special commands can be used inside the footer. See also
# section "Doxygen usage" for information on how to generate the default footer
# that doxygen normally uses.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_FOOTER =
 
# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
# sheet that is used by each HTML page. It can be used to fine-tune the look of
# the HTML output. If left blank doxygen will generate a default style sheet.
# See also section "Doxygen usage" for information on how to generate the style
# sheet that doxygen normally uses.
# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
# it is more robust and this tag (HTML_STYLESHEET) will in the future become
# obsolete.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_STYLESHEET =
 
# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# cascading style sheets that are included after the standard style sheets
# created by doxygen. Using this option one can overrule certain style aspects.
# This is preferred over using HTML_STYLESHEET since it does not replace the
# standard style sheet and is therefore more robust against future updates.
# Doxygen will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list). For an example see the documentation.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_EXTRA_STYLESHEET =
 
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
# files will be copied as-is; there are no commands or markers available.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_EXTRA_FILES =
 
# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
# will adjust the colors in the style sheet and background images according to
# this color. Hue is specified as an angle on a colorwheel, see
# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
# purple, and 360 is red again.
# Minimum value: 0, maximum value: 359, default value: 220.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_COLORSTYLE_HUE = 220
 
# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
# in the HTML output. For a value of 0 the output will use grayscales only. A
# value of 255 will produce the most vivid colors.
# Minimum value: 0, maximum value: 255, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_COLORSTYLE_SAT = 100
 
# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
# luminance component of the colors in the HTML output. Values below 100
# gradually make the output lighter, whereas values above 100 make the output
# darker. The value divided by 100 is the actual gamma applied, so 80 represents
# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
# change the gamma.
# Minimum value: 40, maximum value: 240, default value: 80.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_COLORSTYLE_GAMMA = 80
 
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
# page will contain the date and time when the page was generated. Setting this
# to YES can help to show when doxygen was last run and thus if the
# documentation is up to date.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_TIMESTAMP = NO
 
# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
# documentation will contain a main index with vertical navigation menus that
# are dynamically created via JavaScript. If disabled, the navigation index will
# consists of multiple levels of tabs that are statically embedded in every HTML
# page. Disable this option to support browsers that do not have JavaScript,
# like the Qt help browser.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_DYNAMIC_MENUS = YES
 
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_DYNAMIC_SECTIONS = NO
 
# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
# shown in the various tree structured indices initially; the user can expand
# and collapse entries dynamically later on. Doxygen will expand the tree to
# such a level that at most the specified number of entries are visible (unless
# a fully collapsed tree already exceeds this amount). So setting the number of
# entries 1 will produce a full collapsed tree by default. 0 is a special value
# representing an infinite number of entries and will result in a full expanded
# tree by default.
# Minimum value: 0, maximum value: 9999, default value: 100.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_INDEX_NUM_ENTRIES = 100
 
# If the GENERATE_DOCSET tag is set to YES, additional index files will be
# generated that can be used as input for Apple's Xcode 3 integrated development
# environment (see:
# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To
# create a documentation set, doxygen will generate a Makefile in the HTML
# output directory. Running make will produce the docset in that directory and
# running make install will install the docset in
# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
# genXcode/_index.html for more information.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
GENERATE_DOCSET = NO
 
# This tag determines the name of the docset feed. A documentation feed provides
# an umbrella under which multiple documentation sets from a single provider
# (such as a company or product suite) can be grouped.
# The default value is: Doxygen generated docs.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
DOCSET_FEEDNAME = "Doxygen generated docs"
 
# This tag specifies a string that should uniquely identify the documentation
# set bundle. This should be a reverse domain-name style string, e.g.
# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
DOCSET_BUNDLE_ID = org.doxygen.Project
 
# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# string, e.g. com.mycompany.MyDocSet.documentation.
# The default value is: org.doxygen.Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
 
# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
# The default value is: Publisher.
# This tag requires that the tag GENERATE_DOCSET is set to YES.
 
DOCSET_PUBLISHER_NAME = Publisher
 
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see:
# https://www.microsoft.com/en-us/download/details.aspx?id=21138) on Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
# files are now used as the Windows 98 help format, and will replace the old
# Windows help format (.hlp) on all Windows platforms in the future. Compressed
# HTML files also contain an index, a table of contents, and you can search for
# words in the documentation. The HTML workshop also contains a viewer for
# compressed HTML files.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
GENERATE_HTMLHELP = NO
 
# The CHM_FILE tag can be used to specify the file name of the resulting .chm
# file. You can add a path in front of the file if the result should not be
# written to the html output directory.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
CHM_FILE =
 
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler (hhc.exe). If non-empty,
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
HHC_LOCATION =
 
# The GENERATE_CHI flag controls if a separate .chi index file is generated
# (YES) or that it should be included in the main .chm file (NO).
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
GENERATE_CHI = NO
 
# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
# and project file content.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
CHM_INDEX_ENCODING =
 
# The BINARY_TOC flag controls whether a binary table of contents is generated
# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
BINARY_TOC = NO
 
# The TOC_EXPAND flag can be set to YES to add extra items for group members to
# the table of contents of the HTML help documentation and to the tree view.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
 
TOC_EXPAND = NO
 
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
# (.qch) of the generated HTML documentation.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
GENERATE_QHP = NO
 
# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
# the file name of the resulting .qch file. The path specified is relative to
# the HTML output folder.
# This tag requires that the tag GENERATE_QHP is set to YES.
 
QCH_FILE =
 
# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
# Project output. For more information please see Qt Help Project / Namespace
# (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_QHP is set to YES.
 
QHP_NAMESPACE = org.doxygen.Project
 
# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
# Help Project output. For more information please see Qt Help Project / Virtual
# Folders (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).
# The default value is: doc.
# This tag requires that the tag GENERATE_QHP is set to YES.
 
QHP_VIRTUAL_FOLDER = doc
 
# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
# filter to add. For more information please see Qt Help Project / Custom
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
 
QHP_CUST_FILTER_NAME =
 
# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
# custom filter to add. For more information please see Qt Help Project / Custom
# Filters (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).
# This tag requires that the tag GENERATE_QHP is set to YES.
 
QHP_CUST_FILTER_ATTRS =
 
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
# project's filter section matches. Qt Help Project / Filter Attributes (see:
# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
# This tag requires that the tag GENERATE_QHP is set to YES.
 
QHP_SECT_FILTER_ATTRS =
 
# The QHG_LOCATION tag can be used to specify the location (absolute path
# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to
# run qhelpgenerator on the generated .qhp file.
# This tag requires that the tag GENERATE_QHP is set to YES.
 
QHG_LOCATION =
 
# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
# generated, together with the HTML files, they form an Eclipse help plugin. To
# install this plugin and make it available under the help contents menu in
# Eclipse, the contents of the directory containing the HTML and XML files needs
# to be copied into the plugins directory of eclipse. The name of the directory
# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
# After copying Eclipse needs to be restarted before the help appears.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
GENERATE_ECLIPSEHELP = NO
 
# A unique identifier for the Eclipse help plugin. When installing the plugin
# the directory name containing the HTML and XML files should also have this
# name. Each documentation set should have its own identifier.
# The default value is: org.doxygen.Project.
# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
 
ECLIPSE_DOC_ID = org.doxygen.Project
 
# If you want full control over the layout of the generated HTML pages it might
# be necessary to disable the index and replace it with your own. The
# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
# of each HTML page. A value of NO enables the index and the value YES disables
# it. Since the tabs in the index contain the same information as the navigation
# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
DISABLE_INDEX = YES
 
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. If the tag
# value is set to YES, a side panel will be generated containing a tree-like
# index structure (just like the one that is generated for HTML Help). For this
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
# the same information as the tab index, you could consider setting
# DISABLE_INDEX to YES when enabling this option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
GENERATE_TREEVIEW = YES
 
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
#
# Note that a value of 0 will completely suppress the enum values from appearing
# in the overview section.
# Minimum value: 0, maximum value: 20, default value: 4.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
ENUM_VALUES_PER_LINE = 4
 
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
# to set the initial width (in pixels) of the frame in which the tree is shown.
# Minimum value: 0, maximum value: 1500, default value: 250.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
TREEVIEW_WIDTH = 250
 
# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
# external symbols imported via tag files in a separate window.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
EXT_LINKS_IN_WINDOW = NO
 
# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg
# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see
# https://inkscape.org) to generate formulas as SVG images instead of PNGs for
# the HTML output. These images will generally look nicer at scaled resolutions.
# Possible values are: png (the default) and svg (looks nicer but requires the
# pdf2svg or inkscape tool).
# The default value is: png.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
HTML_FORMULA_FORMAT = png
 
# Use this tag to change the font size of LaTeX formulas included as images in
# the HTML documentation. When you change the font size after a successful
# doxygen run you need to manually remove any form_*.png images from the HTML
# output directory to force them to be regenerated.
# Minimum value: 8, maximum value: 50, default value: 10.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
FORMULA_FONTSIZE = 10
 
# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
# generated for formulas are transparent PNGs. Transparent PNGs are not
# supported properly for IE 6.0, but are supported on all modern browsers.
#
# Note that when changing this option you need to delete any form_*.png files in
# the HTML output directory before the changes have effect.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
FORMULA_TRANSPARENT = YES
 
# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands
# to create new LaTeX commands to be used in formulas as building blocks. See
# the section "Including formulas" for details.
 
FORMULA_MACROFILE =
 
# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
# https://www.mathjax.org) which uses client side JavaScript for the rendering
# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
# installed or if you want to formulas look prettier in the HTML output. When
# enabled you may also need to install MathJax separately and configure the path
# to it using the MATHJAX_RELPATH option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
USE_MATHJAX = NO
 
# When MathJax is enabled you can set the default output format to be used for
# the MathJax output. See the MathJax site (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details.
# Possible values are: HTML-CSS (which is slower, but has the best
# compatibility), NativeMML (i.e. MathML) and SVG.
# The default value is: HTML-CSS.
# This tag requires that the tag USE_MATHJAX is set to YES.
 
MATHJAX_FORMAT = HTML-CSS
 
# When MathJax is enabled you need to specify the location relative to the HTML
# output directory using the MATHJAX_RELPATH option. The destination directory
# should contain the MathJax.js script. For instance, if the mathjax directory
# is located at the same level as the HTML output directory, then
# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
# Content Delivery Network so you can quickly see the result without installing
# MathJax. However, it is strongly recommended to install a local copy of
# MathJax from https://www.mathjax.org before deployment.
# The default value is: https://cdn.jsdelivr.net/npm/mathjax@2.
# This tag requires that the tag USE_MATHJAX is set to YES.
 
MATHJAX_RELPATH = https://cdn.jsdelivr.net/npm/mathjax@2
 
# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
# extension names that should be enabled during MathJax rendering. For example
# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
# This tag requires that the tag USE_MATHJAX is set to YES.
 
MATHJAX_EXTENSIONS =
 
# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
# of code that will be used on startup of the MathJax code. See the MathJax site
# (see:
# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an
# example see the documentation.
# This tag requires that the tag USE_MATHJAX is set to YES.
 
MATHJAX_CODEFILE =
 
# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
# the HTML output. The underlying search engine uses javascript and DHTML and
# should work on any modern browser. Note that when using HTML help
# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
# there is already a search function so this one should typically be disabled.
# For large projects the javascript based search engine can be slow, then
# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
# search using the keyboard; to jump to the search box use <access key> + S
# (what the <access key> is depends on the OS and browser, but it is typically
# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
# key> to jump into the search results window, the results can be navigated
# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
# the search. The filter options can be selected when the cursor is inside the
# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
# to select a filter and <Enter> or <escape> to activate or cancel the filter
# option.
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
 
SEARCHENGINE = YES
 
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using JavaScript. There
# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
# setting. When disabled, doxygen will generate a PHP script for searching and
# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
# and searching needs to be provided by external tools. See the section
# "External Indexing and Searching" for details.
# The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES.
 
SERVER_BASED_SEARCH = NO
 
# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
# script for searching. Instead the search results are written to an XML file
# which needs to be processed by an external indexer. Doxygen will invoke an
# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
# search results.
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see:
# https://xapian.org/).
#
# See the section "External Indexing and Searching" for details.
# The default value is: NO.
# This tag requires that the tag SEARCHENGINE is set to YES.
 
EXTERNAL_SEARCH = NO
 
# The SEARCHENGINE_URL should point to a search engine hosted by a web server
# which will return the search results when EXTERNAL_SEARCH is enabled.
#
# Doxygen ships with an example indexer (doxyindexer) and search engine
# (doxysearch.cgi) which are based on the open source search engine library
# Xapian (see:
# https://xapian.org/). See the section "External Indexing and Searching" for
# details.
# This tag requires that the tag SEARCHENGINE is set to YES.
 
SEARCHENGINE_URL =
 
# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
# search data is written to a file for indexing by an external tool. With the
# SEARCHDATA_FILE tag the name of this file can be specified.
# The default file is: searchdata.xml.
# This tag requires that the tag SEARCHENGINE is set to YES.
 
SEARCHDATA_FILE = searchdata.xml
 
# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
# projects and redirect the results back to the right project.
# This tag requires that the tag SEARCHENGINE is set to YES.
 
EXTERNAL_SEARCH_ID =
 
# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
# projects other than the one defined by this configuration file, but that are
# all added to the same external search index. Each project needs to have a
# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
# to a relative location where the documentation can be found. The format is:
# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
# This tag requires that the tag SEARCHENGINE is set to YES.
 
EXTRA_SEARCH_MAPPINGS =
 
#---------------------------------------------------------------------------
# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
 
# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
# The default value is: YES.
 
GENERATE_LATEX = NO
 
# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: latex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_OUTPUT = latex
 
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
# invoked.
#
# Note that when not enabling USE_PDFLATEX the default is latex when enabling
# USE_PDFLATEX the default is pdflatex and when in the later case latex is
# chosen this is overwritten by pdflatex. For specific output languages the
# default can have been set differently, this depends on the implementation of
# the output language.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_CMD_NAME =
 
# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
# index for LaTeX.
# Note: This tag is used in the Makefile / make.bat.
# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
# (.tex).
# The default file is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
MAKEINDEX_CMD_NAME = makeindex
 
# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
# generate index for LaTeX. In case there is no backslash (\) as first character
# it will be automatically added in the LaTeX code.
# Note: This tag is used in the generated output file (.tex).
# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
# The default value is: makeindex.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_MAKEINDEX_CMD = makeindex
 
# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
COMPACT_LATEX = NO
 
# The PAPER_TYPE tag can be used to set the paper type that is used by the
# printer.
# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
# 14 inches) and executive (7.25 x 10.5 inches).
# The default value is: a4.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
PAPER_TYPE = a4
 
# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
# that should be included in the LaTeX output. The package can be specified just
# by its name or with the correct syntax as to be used with the LaTeX
# \usepackage command. To get the times font for instance you can specify :
# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
# To use the option intlimits with the amsmath package you can specify:
# EXTRA_PACKAGES=[intlimits]{amsmath}
# If left blank no extra packages will be included.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
EXTRA_PACKAGES =
 
# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
# generated LaTeX document. The header should contain everything until the first
# chapter. If it is left blank doxygen will generate a standard header. See
# section "Doxygen usage" for information on how to let doxygen write the
# default header to a separate file.
#
# Note: Only use a user-defined header if you know what you are doing! The
# following commands have a special meaning inside the header: $title,
# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
# string, for the replacement values of the other commands the user is referred
# to HTML_HEADER.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_HEADER =
 
# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
# generated LaTeX document. The footer should contain everything after the last
# chapter. If it is left blank doxygen will generate a standard footer. See
# LATEX_HEADER for more information on how to generate a default footer and what
# special commands can be used inside the footer.
#
# Note: Only use a user-defined footer if you know what you are doing!
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_FOOTER =
 
# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
# LaTeX style sheets that are included after the standard style sheets created
# by doxygen. Using this option one can overrule certain style aspects. Doxygen
# will copy the style sheet files to the output directory.
# Note: The order of the extra style sheet files is of importance (e.g. the last
# style sheet in the list overrules the setting of the previous ones in the
# list).
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_EXTRA_STYLESHEET =
 
# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the LATEX_OUTPUT output
# directory. Note that the files will be copied as-is; there are no commands or
# markers available.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_EXTRA_FILES =
 
# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
# contain links (just like the HTML output) instead of page references. This
# makes the output suitable for online browsing using a PDF viewer.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
PDF_HYPERLINKS = YES
 
# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as
# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX
# files. Set this option to YES, to get a higher quality PDF documentation.
#
# See also section LATEX_CMD_NAME for selecting the engine.
# The default value is: YES.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
USE_PDFLATEX = YES
 
# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
# command to the generated LaTeX files. This will instruct LaTeX to keep running
# if errors occur, instead of asking the user for help. This option is also used
# when generating formulas in HTML.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_BATCHMODE = NO
 
# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
# index chapters (such as File Index, Compound Index, etc.) in the output.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_HIDE_INDICES = NO
 
# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
# code with syntax highlighting in the LaTeX output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_SOURCE_CODE = NO
 
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
# bibliography, e.g. plainnat, or ieeetr. See
# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
# The default value is: plain.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_BIB_STYLE = plain
 
# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
# page will contain the date and time when the page was generated. Setting this
# to NO can help when comparing the output of multiple runs.
# The default value is: NO.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_TIMESTAMP = NO
 
# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
# path from which the emoji images will be read. If a relative path is entered,
# it will be relative to the LATEX_OUTPUT directory. If left blank the
# LATEX_OUTPUT directory will be used.
# This tag requires that the tag GENERATE_LATEX is set to YES.
 
LATEX_EMOJI_DIRECTORY =
 
#---------------------------------------------------------------------------
# Configuration options related to the RTF output
#---------------------------------------------------------------------------
 
# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
# RTF output is optimized for Word 97 and may not look too pretty with other RTF
# readers/editors.
# The default value is: NO.
 
GENERATE_RTF = NO
 
# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: rtf.
# This tag requires that the tag GENERATE_RTF is set to YES.
 
RTF_OUTPUT = rtf
 
# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
# documents. This may be useful for small projects and may help to save some
# trees in general.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
 
COMPACT_RTF = NO
 
# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
# contain hyperlink fields. The RTF file will contain links (just like the HTML
# output) instead of page references. This makes the output suitable for online
# browsing using Word or some other Word compatible readers that support those
# fields.
#
# Note: WordPad (write) and others do not support links.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
 
RTF_HYPERLINKS = NO
 
# Load stylesheet definitions from file. Syntax is similar to doxygen's
# configuration file, i.e. a series of assignments. You only have to provide
# replacements, missing definitions are set to their default value.
#
# See also section "Doxygen usage" for information on how to generate the
# default style sheet that doxygen normally uses.
# This tag requires that the tag GENERATE_RTF is set to YES.
 
RTF_STYLESHEET_FILE =
 
# Set optional variables used in the generation of an RTF document. Syntax is
# similar to doxygen's configuration file. A template extensions file can be
# generated using doxygen -e rtf extensionFile.
# This tag requires that the tag GENERATE_RTF is set to YES.
 
RTF_EXTENSIONS_FILE =
 
# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
# with syntax highlighting in the RTF output.
#
# Note that which sources are shown also depends on other settings such as
# SOURCE_BROWSER.
# The default value is: NO.
# This tag requires that the tag GENERATE_RTF is set to YES.
 
RTF_SOURCE_CODE = NO
 
#---------------------------------------------------------------------------
# Configuration options related to the man page output
#---------------------------------------------------------------------------
 
# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
# classes and files.
# The default value is: NO.
 
GENERATE_MAN = NO
 
# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it. A directory man3 will be created inside the directory specified by
# MAN_OUTPUT.
# The default directory is: man.
# This tag requires that the tag GENERATE_MAN is set to YES.
 
MAN_OUTPUT = man
 
# The MAN_EXTENSION tag determines the extension that is added to the generated
# man pages. In case the manual section does not start with a number, the number
# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
# optional.
# The default value is: .3.
# This tag requires that the tag GENERATE_MAN is set to YES.
 
MAN_EXTENSION = .3
 
# The MAN_SUBDIR tag determines the name of the directory created within
# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
# MAN_EXTENSION with the initial . removed.
# This tag requires that the tag GENERATE_MAN is set to YES.
 
MAN_SUBDIR =
 
# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
# will generate one additional man file for each entity documented in the real
# man page(s). These additional files only source the real man page, but without
# them the man command would be unable to find the correct page.
# The default value is: NO.
# This tag requires that the tag GENERATE_MAN is set to YES.
 
MAN_LINKS = NO
 
#---------------------------------------------------------------------------
# Configuration options related to the XML output
#---------------------------------------------------------------------------
 
# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
# captures the structure of the code including all documentation.
# The default value is: NO.
 
GENERATE_XML = NO
 
# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
# it.
# The default directory is: xml.
# This tag requires that the tag GENERATE_XML is set to YES.
 
XML_OUTPUT = xml
 
# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
# listings (including syntax highlighting and cross-referencing information) to
# the XML output. Note that enabling this will significantly increase the size
# of the XML output.
# The default value is: YES.
# This tag requires that the tag GENERATE_XML is set to YES.
 
XML_PROGRAMLISTING = YES
 
# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
# namespace members in file scope as well, matching the HTML output.
# The default value is: NO.
# This tag requires that the tag GENERATE_XML is set to YES.
 
XML_NS_MEMB_FILE_SCOPE = NO
 
#---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output
#---------------------------------------------------------------------------
 
# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
# that can be used to generate PDF.
# The default value is: NO.
 
GENERATE_DOCBOOK = NO
 
# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
# front of it.
# The default directory is: docbook.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
 
DOCBOOK_OUTPUT = docbook
 
# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
# program listings (including syntax highlighting and cross-referencing
# information) to the DOCBOOK output. Note that enabling this will significantly
# increase the size of the DOCBOOK output.
# The default value is: NO.
# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
 
DOCBOOK_PROGRAMLISTING = NO
 
#---------------------------------------------------------------------------
# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
 
# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
# the structure of the code including all documentation. Note that this feature
# is still experimental and incomplete at the moment.
# The default value is: NO.
 
GENERATE_AUTOGEN_DEF = NO
 
#---------------------------------------------------------------------------
# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
 
# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
# file that captures the structure of the code including all documentation.
#
# Note that this feature is still experimental and incomplete at the moment.
# The default value is: NO.
 
GENERATE_PERLMOD = NO
 
# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
# output from the Perl module output.
# The default value is: NO.
# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
PERLMOD_LATEX = NO
 
# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
# formatted so it can be parsed by a human reader. This is useful if you want to
# understand what is going on. On the other hand, if this tag is set to NO, the
# size of the Perl module output will be much smaller and Perl will parse it
# just the same.
# The default value is: YES.
# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
PERLMOD_PRETTY = YES
 
# The names of the make variables in the generated doxyrules.make file are
# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
# so different doxyrules.make files included by the same Makefile don't
# overwrite each other's variables.
# This tag requires that the tag GENERATE_PERLMOD is set to YES.
 
PERLMOD_MAKEVAR_PREFIX =
 
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
 
# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
# C-preprocessor directives found in the sources and include files.
# The default value is: YES.
 
ENABLE_PREPROCESSING = YES
 
# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
# in the source code. If set to NO, only conditional compilation will be
# performed. Macro expansion can be done in a controlled way by setting
# EXPAND_ONLY_PREDEF to YES.
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
MACRO_EXPANSION = NO
 
# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
# the macro expansion is limited to the macros specified with the PREDEFINED and
# EXPAND_AS_DEFINED tags.
# The default value is: NO.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
EXPAND_ONLY_PREDEF = NO
 
# If the SEARCH_INCLUDES tag is set to YES, the include files in the
# INCLUDE_PATH will be searched if a #include is found.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
SEARCH_INCLUDES = YES
 
# The INCLUDE_PATH tag can be used to specify one or more directories that
# contain include files that are not input files but should be processed by the
# preprocessor.
# This tag requires that the tag SEARCH_INCLUDES is set to YES.
 
INCLUDE_PATH =
 
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
# directories. If left blank, the patterns specified with FILE_PATTERNS will be
# used.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
INCLUDE_FILE_PATTERNS =
 
# The PREDEFINED tag can be used to specify one or more macro names that are
# defined before the preprocessor is started (similar to the -D option of e.g.
# gcc). The argument of the tag is a list of macros of the form: name or
# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
# is assumed. To prevent a macro definition from being undefined via #undef or
# recursively expanded use the := operator instead of the = operator.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
PREDEFINED =
 
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
# tag can be used to specify a list of macro names that should be expanded. The
# macro definition that is found in the sources will be used. Use the PREDEFINED
# tag if you want to use a different macro definition that overrules the
# definition found in the source code.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
EXPAND_AS_DEFINED =
 
# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
# remove all references to function-like macros that are alone on a line, have
# an all uppercase name, and do not end with a semicolon. Such function macros
# are typically used for boiler-plate code, and will confuse the parser if not
# removed.
# The default value is: YES.
# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
 
SKIP_FUNCTION_MACROS = YES
 
#---------------------------------------------------------------------------
# Configuration options related to external references
#---------------------------------------------------------------------------
 
# The TAGFILES tag can be used to specify one or more tag files. For each tag
# file the location of the external documentation should be added. The format of
# a tag file without this location is as follows:
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
# TAGFILES = file1=loc1 "file2 = loc2" ...
# where loc1 and loc2 can be relative or absolute paths or URLs. See the
# section "Linking to external documentation" for more information about the use
# of tag files.
# Note: Each tag file must have a unique name (where the name does NOT include
# the path). If a tag file is not located in the directory in which doxygen is
# run, you must also specify the path to the tagfile here.
 
TAGFILES =
 
# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
# tag file that is based on the input files it reads. See section "Linking to
# external documentation" for more information about the usage of tag files.
 
GENERATE_TAGFILE =
 
# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
# the class index. If set to NO, only the inherited external classes will be
# listed.
# The default value is: NO.
 
ALLEXTERNALS = NO
 
# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
# in the modules index. If set to NO, only the current project's groups will be
# listed.
# The default value is: YES.
 
EXTERNAL_GROUPS = YES
 
# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
# the related pages index. If set to NO, only the current project's pages will
# be listed.
# The default value is: YES.
 
EXTERNAL_PAGES = YES
 
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
 
# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
# NO turns the diagrams off. Note that this option also works with HAVE_DOT
# disabled, but it is recommended to install and use dot, since it yields more
# powerful graphs.
# The default value is: YES.
 
CLASS_DIAGRAMS = YES
 
# You can include diagrams made with dia in doxygen documentation. Doxygen will
# then run dia to produce the diagram and insert it in the documentation. The
# DIA_PATH tag allows you to specify the directory where the dia binary resides.
# If left empty dia is assumed to be found in the default search path.
 
DIA_PATH =
 
# If set to YES the inheritance and collaboration graphs will hide inheritance
# and usage relations if the target is undocumented or is not a class.
# The default value is: YES.
 
HIDE_UNDOC_RELATIONS = YES
 
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz (see:
# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
# Bell Labs. The other options in this section have no effect if this option is
# set to NO
# The default value is: NO.
 
HAVE_DOT = NO
 
# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
# to run in parallel. When set to 0 doxygen will base this on the number of
# processors available in the system. You can set it explicitly to a value
# larger than 0 to get control over the balance between CPU load and processing
# speed.
# Minimum value: 0, maximum value: 32, default value: 0.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_NUM_THREADS = 0
 
# When you want a differently looking font in the dot files that doxygen
# generates you can specify the font name using DOT_FONTNAME. You need to make
# sure dot is able to find the font, which can be done by putting it in a
# standard location or by setting the DOTFONTPATH environment variable or by
# setting DOT_FONTPATH to the directory containing the font.
# The default value is: Helvetica.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_FONTNAME = Helvetica
 
# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
# dot graphs.
# Minimum value: 4, maximum value: 24, default value: 10.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_FONTSIZE = 10
 
# By default doxygen will tell dot to use the default font as specified with
# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
# the path where dot can find it using this tag.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_FONTPATH =
 
# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
# each documented class showing the direct and indirect inheritance relations.
# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
 
CLASS_GRAPH = YES
 
# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
# graph for each documented class showing the direct and indirect implementation
# dependencies (inheritance, containment, and class references variables) of the
# class with other documented classes.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
 
COLLABORATION_GRAPH = YES
 
# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
# groups, showing the direct groups dependencies.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
 
GROUP_GRAPHS = YES
 
# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
 
UML_LOOK = NO
 
# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
# class node. If there are many fields or methods and many nodes the graph may
# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
# number of items for each type to make the size more manageable. Set this to 0
# for no limit. Note that the threshold may be exceeded by 50% before the limit
# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
# but if the number exceeds 15, the total amount of fields shown is limited to
# 10.
# Minimum value: 0, maximum value: 100, default value: 10.
# This tag requires that the tag UML_LOOK is set to YES.
 
UML_LIMIT_NUM_FIELDS = 10
 
# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and
# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS
# tag is set to YES, doxygen will add type and arguments for attributes and
# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen
# will not generate fields with class member information in the UML graphs. The
# class diagrams will look similar to the default class diagrams but using UML
# notation for the relationships.
# Possible values are: NO, YES and NONE.
# The default value is: NO.
# This tag requires that the tag UML_LOOK is set to YES.
 
DOT_UML_DETAILS = NO
 
# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters
# to display on a single line. If the actual line length exceeds this threshold
# significantly it will wrapped across multiple lines. Some heuristics are apply
# to avoid ugly line breaks.
# Minimum value: 0, maximum value: 1000, default value: 17.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_WRAP_THRESHOLD = 17
 
# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
# collaboration graphs will show the relations between templates and their
# instances.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
 
TEMPLATE_RELATIONS = NO
 
# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
# YES then doxygen will generate a graph for each documented file showing the
# direct and indirect include dependencies of the file with other documented
# files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
 
INCLUDE_GRAPH = YES
 
# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
# set to YES then doxygen will generate a graph for each documented file showing
# the direct and indirect include dependencies of the file with other documented
# files.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
 
INCLUDED_BY_GRAPH = YES
 
# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
# dependency graph for every global function or class method.
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable call graphs for selected
# functions only using the \callgraph command. Disabling a call graph can be
# accomplished by means of the command \hidecallgraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
 
CALL_GRAPH = NO
 
# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
# dependency graph for every global function or class method.
#
# Note that enabling this option will significantly increase the time of a run.
# So in most cases it will be better to enable caller graphs for selected
# functions only using the \callergraph command. Disabling a caller graph can be
# accomplished by means of the command \hidecallergraph.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
 
CALLER_GRAPH = NO
 
# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
# hierarchy of all classes instead of a textual one.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
 
GRAPHICAL_HIERARCHY = YES
 
# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
# dependencies a directory has on other directories in a graphical way. The
# dependency relations are determined by the #include relations between the
# files in the directories.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DIRECTORY_GRAPH = YES
 
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
# generated by dot. For an explanation of the image formats see the section
# output formats in the documentation of the dot tool (Graphviz (see:
# http://www.graphviz.org/)).
# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
# to make the SVG files visible in IE 9+ (other browsers do not have this
# requirement).
# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
# png:gdiplus:gdiplus.
# The default value is: png.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_IMAGE_FORMAT = png
 
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
# enable generation of interactive SVG images that allow zooming and panning.
#
# Note that this requires a modern browser other than Internet Explorer. Tested
# and working are Firefox, Chrome, Safari, and Opera.
# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
# the SVG files visible. Older versions of IE do not have SVG support.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
 
INTERACTIVE_SVG = NO
 
# The DOT_PATH tag can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_PATH =
 
# The DOTFILE_DIRS tag can be used to specify one or more directories that
# contain dot files that are included in the documentation (see the \dotfile
# command).
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOTFILE_DIRS =
 
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile
# command).
 
MSCFILE_DIRS =
 
# The DIAFILE_DIRS tag can be used to specify one or more directories that
# contain dia files that are included in the documentation (see the \diafile
# command).
 
DIAFILE_DIRS =
 
# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
# path where java can find the plantuml.jar file. If left blank, it is assumed
# PlantUML is not used or called during a preprocessing step. Doxygen will
# generate a warning when it encounters a \startuml command in this case and
# will not generate output for the diagram.
 
PLANTUML_JAR_PATH =
 
# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
# configuration file for plantuml.
 
PLANTUML_CFG_FILE =
 
# When using plantuml, the specified paths are searched for files specified by
# the !include statement in a plantuml block.
 
PLANTUML_INCLUDE_PATH =
 
# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
# that will be shown in the graph. If the number of nodes in a graph becomes
# larger than this value, doxygen will truncate the graph, which is visualized
# by representing a node as a red box. Note that doxygen if the number of direct
# children of the root node in a graph is already larger than
# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
# Minimum value: 0, maximum value: 10000, default value: 50.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_GRAPH_MAX_NODES = 50
 
# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
# generated by dot. A depth value of 3 means that only nodes reachable from the
# root by following a path via at most 3 edges will be shown. Nodes that lay
# further from the root node will be omitted. Note that setting this option to 1
# or 2 may greatly reduce the computation time needed for large code bases. Also
# note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
# Minimum value: 0, maximum value: 1000, default value: 0.
# This tag requires that the tag HAVE_DOT is set to YES.
 
MAX_DOT_GRAPH_DEPTH = 0
 
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
# background. This is disabled by default, because dot on Windows does not seem
# to support this out of the box.
#
# Warning: Depending on the platform used, enabling this option may lead to
# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
# read).
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_TRANSPARENT = NO
 
# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
# makes dot run faster, but since only newer versions of dot (>1.8.10) support
# this, this feature is disabled by default.
# The default value is: NO.
# This tag requires that the tag HAVE_DOT is set to YES.
 
DOT_MULTI_TARGETS = NO
 
# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
# explaining the meaning of the various boxes and arrows in the dot generated
# graphs.
# The default value is: YES.
# This tag requires that the tag HAVE_DOT is set to YES.
 
GENERATE_LEGEND = YES
 
# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate
# files that are used to generate the various graphs.
#
# Note: This setting is not only used for dot files but also for msc and
# plantuml temporary files.
# The default value is: YES.
 
DOT_CLEANUP = YES
/kernel/branches/kolibrios-pe-clevermouse/docs/doxygen
Property changes:
Added: svn:ignore
+*
/kernel/branches/kolibrios-pe-clevermouse/docs/drivers_api.txt
0,0 → 1,105
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2011-2012. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
All functions are stdcall unless mentioned otherwise.
 
=== Disk ===
The kernel exports the functions 'DiskAdd', 'DiskMediaChanged', 'DiskDel' for
drivers. They must be called in the following order: DiskAdd, then zero or
more DiskMediaChanged, then optionally DiskDel. The driver must not call
two functions in parallel, including two calls to DiskMediaChanged.
 
void* DiskAdd(DISKFUNC* functions, const char* name, void* userdata, int flags);
; The pointer 'functions' must be valid at least until the disk will be deleted
; (until DISKFUNC.close is called).
; The pointer 'name' can be invalid after this function returns.
; It should point to ASCIIZ-string without leading '/' in latin lowercase and
; digits, like 'usbhd0'.
; The value 'userdata' is any pointer-sized data, passed as is to all
; callbacks.
DISK_NO_INSERT_NOTIFICATION = 1
; The bitfield 'flags' has currently only one bit defined. If it is set, the
; driver will never call DiskMediaChanged(hDisk, true), so the kernel must scan
; for media insertion when the operation is requested.
struc DISKFUNC
{
.strucsize dd ?
.close dd ?
; void close(void* userdata);
; Optional.
; The last function that is called for the given disk. The kernel calls it when
; the kernel has finished all operations with the disk and it is safe to free
; all driver-specific data identified by 'userdata'.
.closemedia dd ?
; void closemedia(void* userdata);
; Optional.
; The kernel calls this function when it finished all processing with the
; current media. If media is removed, the driver should decline all requests
; to that media with DISK_STATUS_NO_MEDIA, even if new media is inserted,
; until this function is called. If media is removed, a new call to
; DiskMediaChanged(hDisk, true) is not allowed until this function is called.
.querymedia dd ?
; int querymedia(void* userdata, DISKMEDIAINFO* info);
; return value: 0 = success, otherwise = error
.read dd ?
; int read(void* userdata, void* buffer, __int64 startsector,
; int* numsectors);
; return value: 0 = success, otherwise = error
.write dd ?
; int write(void* userdata, const void* buffer, __int64 startsector,
; int* numsectors);
; Optional.
; return value: 0 = success, otherwise = error
.flush dd ?
; int flush(void* userdata);
; Optional.
; Flushes the hardware cache, if it exists. Note that a driver should not
; implement a software cache for read/write, since they are called from the
; kernel cache manager.
.adjust_cache_size dd ?
; unsigned int adjust_cache_size(void* userdata, unsigned int suggested_size);
; Optional.
; Returns the cache size for this device in bytes. 0 = disable cache.
}
struc DISKMEDIAINFO
{
.flags dd ?
DISK_MEDIA_READONLY = 1
.sectorsize dd ?
.capacity dq ?
}
void DiskDel(void* hDisk);
; This function informs the kernel that the disk should be deleted from the
; system. This function removes the disk from the global file system; however,
; it is possible that active operations with the disk are still running. When
; the disk is actually removed, the kernel calls the 'close' function, which
; can free all device-related resources.
void DiskMediaChanged(void* hDisk, int newstate);
; This function informs the kernel that a media has been inserted, removed or
; changed. 'newstate' should be zero if currently there is no media inserted
; and nonzero in the other case. This function must not be called with nonzero
; 'newstate' from any of callbacks. This function must not be called if another
; call to this function is active.
 
=== Timers ===
Timers allow to schedule a function call to some time in the future, once
or periodically. A timer function can do anything, including adding/removing
other timers and itself, but it should not run time-consuming tasks, since that
would block the processing thread for a long time; for such tasks it is
recommended to create new thread.
 
void* TimerHS(unsigned int deltaStart, unsigned int interval,
void* timerFunc, void* userData);
; Registers a timer which is activated in (deltaStart == 0 ? deltaStart :
; interval) 1/100ths of second starting from the current time. If interval
; is zero, this timer is automatically deleted when activated. Otherwise,
; this timer will be activated every (interval) 1/100ths of second from the
; first activation. Activated timer calls timerFunc(userData) as stdcall.
; Returned value: NULL = failed, otherwise = timer handle which can be passed
; to CancelTimerHS.
void CancelTimerHS(void* hTimer);
; Cancels previously registered timer.
/kernel/branches/kolibrios-pe-clevermouse/docs/stack.txt
0,0 → 1,214
eax = 74 - Work directly with network interface
ebx = -1 (Get number of active network devices)
 
out:
eax = number of active network devices
 
bh = device number, for all following functions !
 
bl = 0 (Get device type)
 
out:
eax = device type number
 
bl = 1 (Get device name)
 
in:
ecx = pointer to 64 byte buffer
out:
name is copied into the buffer
eax = -1 on error
 
bl = 2 (Reset the device)
 
in
none
out
eax = -1 on error
 
bl = 3 (Stop device)
 
in
none
out
eax = -1 on error
 
TO BE FIGURED OUT
 
eax = 75 - Work with Sockets
 
These functions work like the ones found in UNIX (and windows)
for more info, please read http://beej.us/guide/bgnet/
 
bl = 0 (Open Socket)
 
in:
ecx = domain
edx = type
esi = protocol
out:
eax = socket number, -1 on error
 
bl = 1 (Close Socket)
 
in:
ecx = socket number
out:
eax = -1 on error
 
bl = 2 (Bind)
 
in:
ecx = socket number
edx = pointer to sockaddr structure
esi = length of sockaddr structure
out:
eax = -1 on error
 
bl = 3 (Listen)
 
in:
ecx = socket number
edx = backlog
out:
eax = -1 on error
 
bl = 4 (connect)
 
in:
ecx = socket number
edx = pointer to sockaddr structure
esi = length of sockaddr structure
out:
eax = -1 on error
 
bl = 5 (accept)
 
in:
ecx = socket number
edx = pointer to sockaddr structure
esi = length of sockaddr structure
out:
eax = socket number, -1 on error
 
bl = 6 (send)
 
in:
ecx = socket number
edx = pointer to buffer
esi = length of buffer
edi = flags
out:
eax = -1 on error
 
bl = 7 (receive)
 
in:
ecx = socket number
edx = pointer to buffer
esi = length of buffer
edi = flags
out:
eax = number of bytes copied, -1 on error
 
bl = 8 (set socket options)
 
in:
ecx = socket number
edx = ptr to optstruct
 
Optstruct: dd level
dd optionname
dd optlength
db options...
 
The buffer's first dword is the length of the buffer, minus the first dword offcourse
 
out:
eax = -1 on error
 
bl = 9 (get socket options)
 
in:
ecx = socket number
edx = ptr to optstruct
 
Optstruct: dd level
dd optionname
dd optlength
db options...
out:
eax = -1 on error, socket option otherwise
 
bl = 10 (get IPC socketpair)
 
in:
/
out:
eax = -1 on error, socketnum1 otherwise
ebx = socketnum2
 
TIP
 
when you import 'network.inc' and 'macros.inc' into your source code, you can use the following syntax to work with sockets:
 
 
for example, to open a socket
 
mcall socket, AF_INET, SOCK_DGRAM,0
mov [socketnum], eax
 
then to connect to a server
 
mcall connect, [socketnum], sockaddr, 18
 
 
eax = 76 - Work with protocols
 
high half of ebx = protocol number (for all subfunctions!)
bh = device number (for all subfunctions!)
bl = subfunction number, depends on protocol type
 
For Ethernet protocol
 
0 - Read # Packets send
1 - Read # Packets received
2 - Read # Bytes send
3 - Read # Bytes received
4 - Read MAC
5 - Write MAC
6 - Read IN-QUEUE size
7 - Read OUT-QUEUE size
For IPv4 protocol
 
0 - Read # IP packets send
1 - Read # IP packets received
2 - Read IP
3 - Write IP
4 - Read DNS
5 - Write DNS
6 - Read subnet
7 - Write subnet
8 - Read gateway
9 - Write gateway
For ARP protocol
 
0 - Read # ARP packets send
1 - Read # ARP packets received
2 - Get # ARP entry's
3 - Read ARP entry
4 - Add static ARP entry
5 - Remove ARP entry (-1 = remove all)
For ICMP protocol
 
0 - Read # ICMP packets send
1 - Read # ICMP packets received
3 - enable/disable ICMP echo reply
For UDP protocol
 
0 - Read # UDP packets send
1 - Read # UDP packets received
For TCP protocol
 
0 - Read # TCP packets send
1 - Read # TCP packets received
/kernel/branches/kolibrios-pe-clevermouse/docs/events_subsystem.ru.txt
0,0 → 1,232
Дата последней правки 26/07/2013.
Подсистема событий ядра может понадобиться при написании драйверов и сервисов, работающих в режиме ядра.
Она не имеет отношения к подсистеме событий пользовательского интерфейса.
С точки зрения ядра событие - объект ядра и принадлежит создавшему его потоку.
 
struc EVENT
{
.magic dd ? ; 'EVNT'
.destroy dd ? ; internal destructor
.fd dd ? ; next object in list
.bk dd ? ; prev object in list
.pid dd ? ; owner id. идентификатор владельца (потока)
.id dd ? ; event uid. уникальный идентификатор события (просто номерок)
.state dd ? ; internal flags; см. далее.
.code dd ? ; старший байт класс события, ; следующий байт приоритет
; (будет использоваться только внутри ядра, при чтении всегда 0),
; Чем больше численное значение двойного слова тем важнее событие.
; два младших байта код события.
rd 5 ; .data - точная структура этого поля не определена и зависит
; от поля .code. (Здесь можно передавать какие-то свои данные,
; при необходимости :)
.size = $ - .magic
.codesize = $ - .code
}
 
События реального времени получили класс 0хFF. Пока определёны только:
EVENT.code= ;(Используется в звуковой подсистеме).
RT_INP_EMPTY = 0xFF000001
RT_OUT_EMPTY = 0xFF000002
RT_INP_FULL = 0xFF000003
RT_OUT_FULL = 0xFF000004
 
 
Флаги поля EVENT.state определены в gui/event.inc.
EVENT_SIGNALED = 0x20000000 ;бит 29 событие активно/неактивно;
EVENT_WATCHED = 0x10000000 ;бит 28, поток-владелец ожидает активации события;
MANUAL_RESET = 0x40000000 ;бит 30, не деактивировать событие автоматически по получении;
MANUAL_DESTROY = 0x80000000 ;бит 31, не возвращать событие в список свободных по получении.
 
На момент ревизии 3732 (и далее по тексту то же) определение находится в \kernel\trunk\const.inc
и выглядит так:
 
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 EVENT APPOBJ
id dd ? ;event uid
state dd ? ;internal flags
code dd ?
rd 5 ; .data
ends
 
Код находится в gui/event.inc.
Сами события как обьекты существуют в памяти ядра в виде двусвязного списка (см. поля .bk и .fd).
При инициализации ядро резервирует память и создает 512 таких обьектов, помещая их в список FreeEvents
(свободных событий). При нехватке событий (все заняты, а нужно ещё) ядро создает ещё 512 свободных
и т.д. Каждый поток имеет свои (двусвязные) списки (в которые может быть помещено событие):
ObjList - список объектов ядра, ассоциированных с этим потоком;
EventList - список событий ядра для потока.
Сами события, физически, при перемещении между списками и смене очередности в списке не перемещаются
и не копируются. Это происходит только благодаря модификации полей .fd и .bk. Принцип работы списков,
как очередей - FIFO. Использутся неблокирующая отправка и блокирующее получение. Адресация - прямая
(у события всегда есть поток-владелец), по идентификатору потока.
 
Жизненый цикл событий определяется флагами при создании. По умолчанию ядро использует значения
MANUAL_RESET = 0 и MANUAL_DESTROY = 0. Такое событие является "одноразовым", и автоматически освобождается
ядром, возвращаясь в список свободных событий после получения.
Событие с флагом MANUAL_DESTROY = 1 после получения переходит в неактивное состояние, но остаётся в списке
объектов потока и может использоваться снова. Событие с флагами MANUAL_DESTROY = 1 и MANUAL_RESET = 1
остаётся активным после получения и может быть сброшено вызовом ClearEvent.
 
Пример (вариант) жизненного цикла события из звуковой подсистемы:
Для зукового буфера (их может быть несколько) драйвер создает событие в списке ObjList с помощью
CreateEvent и флагом MANUAL_DESTROY. Далее драйвер вызывает WaitEvent для этого события (ожидает флага
EVENT_SIGNALED в событии) и блокируется, в ожидании запроса на пополнение буфера. Запрос отправляется
с помощью RaiseEvent из другого потока. Отправка (RaiseEvent) и получение (WaitEvent) циклически
повторяются при опустошении буфера. При остановке воспроизведения драйвер деактивирует событие с помощью
ClearEvent.
 
Вообще говоря, структура события приведена здесь только лишь для понимания принципов работы подсистемы.
Самостоятельная работа с полями не приветствуется, ввиду возможных в будущем проблем с совместимостью.
Работа должна производится только через API (функции подсистемы), с доступом только к тем полям, доступ к
которым предоставляет функция. При этом пару "указатель на событие" и "уникальный идентификатор события"
следует рассматривать как один 64-х битный уникальный идентификатор. (Если вы вызвали CreateEvent, напимер,
его нужно запомнить где-нибудь [если это нужно] для дальнейшей работы с событием).
 
Функции для работы с событиями экспортитуемые ядром:
(для драйверов и т.п.; вызываются в режиме ядра)
 
CreateEvent
RaiseEvent
ClearEvent
SendEvent
DestroyEvent
WaitEvent
WaitEventTimeout
GetEvent
Для пользовательских приложений Ф68.14 (GetEvent с обёрткой)
 
---------------------------------------------------------------------------------------------
CreateEvent:
Создаёт новое событие в очереди ObjList текущего потока.
Устанавливает:
EVENT.destroy <= внутренний деструктор по умолчанию;
EVENT.pid <= текущий Process id;
EVENT.id <= уникальный идентификатор;
EVENT.state <= ecx - флаги;
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword;
Возвращает:
eax - указатель на событие или 0 при ошибке.
edx - Event.id.
Портит: eax,ebx,edx,ecx,esi,edi
---------------------------------------------------------------------------------------------
RaiseEvent:
Активирует уже существующее событие (может принадлежать другому потоку) установкой
флага EVENT_SIGNALED. Если необходимо, - устанавливает данные EVENT.code.
Если флаг EVENT_SIGNALED в самом событии уже активен - больше ничего не делает.
Если EVENT_SIGNALED не установлен в самом событии, то он будет установлен, кроме случая
{EVENT_WATCHED в edx=1 и EVENT_WATCHED в событии=0}.
Т.е. при установке EVENT_WATCHED в edx, проверяется, ожидает ли поток-владелец активации
события.
Кроме EVENT_SIGNALED в событии никакие другие флаги не модифицируются.
Принимает:
eax - указатель на событие;
ebx - id, уникальный идентификатор события;
edx - флаги для операции (формат EVENT.state);
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword;
Возвращает: ?
Портит: eax,ebx,edx,ecx,esi,edi .
---------------------------------------------------------------------------------------------
ClearEvent:
Перемещает событие в список ObjList потока-владельца. (Возможно оно там и находилось.)
Сбрасывает флаги EVENT_SIGNALED, EVENT_WATCHED. С остальными полями (.code, .id),
ничего не делает.
Принимает:
eax - указатель на событие;
ebx - id, уникальный идентификатор события.
Возвращает: ?
Портит: eax,ebx,ecx,edi .
---------------------------------------------------------------------------------------------
SendEvent:
Создаёт новое событие в списке событий целевого потока. Устанавливает в событии
флаг EVENT_SIGNALED.
Принимает:
EVENT.pid <= eax - pid, идентификатор целевого потока;
EVENT.code <= [esi], (если esi=0, то не копирует), размер 6*dword;
Возвращает:
eax - указатель на событие или 0 при ошибке.
edx - Event.id. уникальный идентификатор.
Портит: eax,ebx,ecx,esi,edi .
---------------------------------------------------------------------------------------------
DestroyEvent:
Переносит EVENT в список FreeEvents, чистит поля .magic,.destroy,.pid,.id.
Событие может принадлежать другому потоку.
Принимает:
eax - указатель на событие;
ebx - id, уникальный идентификатор события.
Возвращает:
eax - 0 при ошибке, не 0 при успехе.
Портит: eax,ebx,ecx .
---------------------------------------------------------------------------------------------
WaitEvent:
Бесконечно ожидает установки флага EVENT_SIGNALED в конкретном событии, принадлежащем
вызывающему WaitEvent потоку. Сигнализирующий поток устанавливат этот флаг через
RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5.
Перед заморозкой устанавливается флаг EVENT_WATCHED в событии.
Если в полученном событии НЕ установлен MANUAL_RESET, то:
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются.
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent),
а при активном - перемещается в список ObjList текущего слота.}
Принимает:
eax - указатель на событие;
ebx - id, уникальный идентификатор события.
Возвращает: ?
Портит: eax,ebx,edx,ecx,esi,edi .
---------------------------------------------------------------------------------------------
WaitEventTimeout:
Ожидает с таймаутом установки флага EVENT_SIGNALED в конкретном событии, принадлежащем
вызывающему WaitEventTimeout потоку. Сигнализирующий поток устанавливат этот флаг через
RaiseEvent. Ожидающий поток замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5.
Перед заморозкой устанавливается флаг EVENT_WATCHED в событии.
Если в полученном событии НЕ установлен MANUAL_RESET, то:
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются.
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent),
а при активном - перемещается в список ObjList текущего слота.}
Принимает:
eax - указатель на событие;
ebx - id, уникальный идентификатор события.
ecx - время ожидания в тиках системного таймера.
Возвращает:
eax - 0 - таймаут, если событие не активировалось, или
не 0, если было активировано.
Портит: eax,ebx,edx,ecx,esi,edi .
---------------------------------------------------------------------------------------------
GetEvent:
Бесконечно ожидает любое событие в очереди событий текущего потока. Поток замораживается
путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword)
по получении копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере.
Если в полученном событии НЕ установлен MANUAL_RESET, то:
{EVENT_SIGNALED и EVENT_WATCHED по получении события сбрасываются.
При неактивном MANUAL_DESTROY - событие уничтожается штатно (DestroyEvent),
а при активном - перемещается в список ObjList текущего слота.}
Принимает:
edi - указатель на буфер, куда копировать данные.
Возвращает:
буфер, содержащий следующую информацию:
+0: (EVENT.code) dword: идентификатор последующих данных сигнала
+4: (EVENT.data, поле формально не определено) данные принятого
сигнала (5*dword), формат которых определяется первым dword-ом.
Портит: eax,ebx,edx,ecx,esi,edi .
--------------------------------------------------------------------------------------------
Ф 68.14 для приложений: ;это тот же GetEvent, но с обёрткой.
Бесконечно ожидает любое событие в очереди событий текущего потока. Ожидающий поток
замораживается путем перевода TASKDATA.state<=TSTATE_WAITING=5. Данные события (EVENT.code+5*dword)
копируются в указанный буфер. Сбрасывает байт приоритета (см. выше) в буфере.
Принимает:
eax - 68 - номер функции
ebx - 14 - номер подфункции
ecx - указатель на буфер для информации (размер 6*dword)
Возвращает:
буфер, на который указывает ecx, содержит следующую информацию:
+0: (EVENT.code) dword: идентификатор последующих данных сигнала
+4: (EVENT.data, поле формально не определено) данные принятого
сигнала (5*dword), формат которых определяется первым dword-ом.
Портит:
eax .
---------------------------------------------------------------------------------------------
/kernel/branches/kolibrios-pe-clevermouse/docs/events_subsystem.txt
0,0 → 1,248
Last edit: 26/07/2013
 
Kernel event subsystem may be useful when writing drivers and kernel space
services. It is not related to the subsystem of GUI events. An event, from the
kernel's point of view, is a kernel space object which is owned by the thread
that created it.
 
struc EVENT
{
.magic dd ? ; 'EVNT'
.destroy dd ? ; internal destructor
.fd dd ? ; next object in list
.bk dd ? ; prev object in list
.pid dd ? ; owner (thread) id
.id dd ? ; event uid. (just a number)
.state dd ? ; internal flags; see below
.code dd ? ; MSB: event class; next byte: priority
; (used by kernel only, always 0 for reading),
; The higher dword value the higher event priority.
; Two LSBs: event code.
rd 5 ; .data: the structure of this field is not defined and
; depends on .code field. (Pass any data you need here)
.size = $ - .magic
.codesize = $ - .code
}
 
Realtime events have class 0хFF. Currently defined:
EVENT.code= ; (Used in sound subsystem)
RT_INP_EMPTY = 0xFF000001
RT_OUT_EMPTY = 0xFF000002
RT_INP_FULL = 0xFF000003
RT_OUT_FULL = 0xFF000004
 
 
Flags of EVENT.state field are defined in gui/event.inc.
EVENT_SIGNALED = 0x20000000 ; bit 29: event is active/inactive
EVENT_WATCHED = 0x10000000 ; bit 28: owner thread is waiting for the
; event to be active
MANUAL_RESET = 0x40000000 ; bit 30: do not deactivate event
: automatically on receive
MANUAL_DESTROY = 0x80000000 ; bit 31: do not return event to a list of
; free ones on receive
 
As of SVN r3732 (assume same below) the definition is located in
/kernel/trunk/const.inc and is as follows:
 
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 EVENT APPOBJ
id dd ? ; event uid
state dd ? ; internal flags
code dd ?
rd 5 ; .data
ends
 
Code is located in gui/event.inc.
Event objects live in kernel memory as a double-linked list (see fields .bk and
.fd). While initialization the kernel reserves memory, creates 512 events and
places them into FreeEvents list. When out of free event, kernel creates another
512 ones etc. Each thread has own double-linked lists where an event may be
placed to:
ObjList -- a list of kernel objects associated with the thread;
EventList -- a list of kernel events for the thread.
When events are moved between lists or reordered their data are not copied. This
is done only via modification of .fd and .bk fields. These lists work as FIFO
queues. Sending does not block, receiving blocks. Addressing is direct, by
thread id. There always is an owner thread for an event.
 
Event's life cycle is defined by flags while creation. By default the kernel
uses values MANUAL_RESET = 0 and MANUAL_DESTROY = 0. Such an event is oneshot
and is automatically freed by the kernel and returned to the FreeEvents list
when received. An event with flag MANUAL_DESTROY = 1 becomes inactive when
received but remains in thread's object list and can be reused. An event with
flags MANUAL_DESTROY = 1 and MANUAL_RESET = 1 remains active when received and
can be reset via call to ClearEvent.
 
A life cycle example of a sound subsystem event:
* For an audio buffer (possibly several) the driver creates an event in ObjList
by calling CreateEvent with flag MANUAL_DESTROY.
* Then driver calls WaitEvent for the event (waits for EVENT_SIGNALED event
flag) and blocks waiting for buffer update request.
* The buffer update request is sent with RaiseEvent from another thread.
* Sending (RaiseEvent) and receiving (WaitEvent) are repeated as buffer gets
empty.
* Driver deactivates the event with ClearEvent when playback is stopped.
 
Actually, the event structure is described here only for understanding of
subsystem work principles. Direct field access is discouraged due to possible
compatibility issues in the future. Only API calls should be used. A pair
"pointer to an event" and "event id" is considered a single 64-bit id. This id
should be stored somewhere after a call to CreateEvent for further work with the
event.
 
The kernel exports following event related functions:
(for drivers, etc; called from kernel mode)
 
CreateEvent
RaiseEvent
ClearEvent
SendEvent
DestroyEvent
WaitEvent
WaitEventTimeout
GetEvent
For user applications sysfn 68.14 (a wrapper to GetEvent)
 
--------------------------------------------------------------------------------
CreateEvent:
Creates a new event in ObjList queue of current thread.
Sets:
EVENT.destroy <= default internal destructor
EVENT.pid <= current Process id
EVENT.id <= unique id
EVENT.state <= ecx: flags
EVENT.code <= [esi]: size is 6*dword, do not copy if esi=0
Returns:
eax -- pointer to the event or 0 for error.
edx -- Event.id.
Destroys: eax,ebx,edx,ecx,esi,edi
--------------------------------------------------------------------------------
RaiseEvent:
Activates existing event (may be owned by another thread) by setting
EVENT_SIGNALED flag. Sets EVENT.code data if necessary. Does nothing
more if EVENT_SIGNALED flag is already active in the event. If
EVENT_SIGNALED flag is not set in the event it will be set, except when
EVENT_WATCHED in edx = 1 and EVENT_WATCHED in the event = 0. I.e. while
setting EVENT_WATCHED in edx it is checked if owner thread is waiting
for event activation. No flags, except EVENT_SIGNALED, are modified in
the event.
Gets:
eax -- pointer to event
ebx -- id
edx -- flags (see EVENT.state)
Sets:
EVENT.code <= [esi]: size is 6*dword, do not copy if esi=0
Returns: ?
Destroys: eax,ebx,edx,ecx,esi,edi
--------------------------------------------------------------------------------
ClearEvent:
Move event to ObjList of owner thread. (May be it was already there.)
Reset flags EVENT_SIGNALED and EVENT_WATCHED, keep other fields (.code,
.id).
Gets:
eax -- pointer to event
ebx -- id
Returns: ?
Destroys: eax,ebx,ecx,edi
--------------------------------------------------------------------------------
SendEvent:
Create a new event in the event list of target thread. Sets
EVENT_SIGNALED flag in the event.
Gets:
EVENT.pid <= eax: target thread id;
EVENT.code <= [esi]: size is 6*dword, do not copy if esi=0
Returns:
eax -- pointer to event or 0 for error
edx -- Event.id
Destroys: eax,ebx,ecx,esi,edi
--------------------------------------------------------------------------------
DestroyEvent:
Moves event to FreeEvents, clears fields .magic, .destroy, .pid, .id.
The event may be owned by other thread.
Gets:
eax -- pointer to event
ebx -- event id
Returns:
eax -- 0 for error, non-zero for success
Destroy: eax,ebx,ecx
--------------------------------------------------------------------------------
WaitEvent:
Wait infinitely until flag EVENT_SIGNALED is set in the event owned by
the caller thread. This flag is set by signaling thread via RaiseEvent.
Waiting thread is frozen by setting TASKDATA.state <= TSTATE_WAITING=5.
Flag EVENT_WATCHED is set in the event before freeze.
If flag MANUAL_RESET is NOT set in the event then:
EVENT_SIGNALED and EVENT_WATCHED are reset when the event is
received.
When MANUAL_DESTROY is
inactive: the event is destroyed by DestroyEvent,
active: the event is moved to ObjList of current thread.
Gets:
eax -- pointer to event
ebx -- event id
Returns: ?
Destroys: eax,ebx,edx,ecx,esi,edi
--------------------------------------------------------------------------------
WaitEventTimeout:
Wait with a timeout until flag EVENT_SIGNALED is set in the event owned
by caller thread. This flag is set by signaling thread via RaiseEvent.
Waiting thread is frozen by setting TASKDATA.state <= TSTATE_WAITING=5.
Flag EVENT_WATCHED is set in the event before freeze.
If flag MANUAL_RESET is NOT set in the event then:
EVENT_SIGNALED and EVENT_WATCHED are reset when the event is
received.
When MANUAL_DESTROY is
inactive: the event is destroyed by DestroyEvent,
active: the event is moved to ObjList of current thread.
Gets:
eax -- pointer to event
ebx -- event id
ecx -- timeout, in ticks of system timer
Returns:
eax -- 0 if the event was not activated, or
not 0 if activated
Destroys: eax,ebx,edx,ecx,esi,edi
--------------------------------------------------------------------------------
GetEvent:
Waits infinitely for any event in the queue of current thread. Thread is
frozen by setting TASKDATA.state <= TSTATE_WAITING = 5. Event data
(EVENT.code + 5*dword) are copied to specified buffer when received.
Reset priority byte (see above) in the buffer.
If flag MANUAL_RESET is NOT set in the event then:
EVENT_SIGNALED and EVENT_WATCHED are reset when the event is
received.
When MANUAL_DESTROY is
inactive: the event is destroyed by DestroyEvent,
active: the event is moved to ObjList of current thread.
Gets:
edi -- pointer to buffer to copy data
Returns:
buffer with following data:
+0: (EVENT.code) dword: id of following signal data
+4: (EVENT.data) 5*dword: signal data, format depends on
EVENT.code
Destroys: eax,ebx,edx,ecx,esi,edi
--------------------------------------------------------------------------------
SysFn 68.14 for application: ; wrapped GetEvent
Waits infinitely for any event in the queue of current thread. Thread is
frozen by setting TASKDATA.state <= TSTATE_WAITING = 5. Event data
(EVENT.code + 5*dword) are copied to specified buffer when received.
Reset priority byte (see above) in the buffer.
Gets:
eax -- 68: function number
ebx -- 14: subfunction number
ecx -- pointer to data buffer (size is 6*dword)
Returns:
ecx = buffer with following data:
+0: (EVENT.code) dword: id of following signal data
+4: (EVENT.data) 5*dword: signal data, format depends on
EVENT.code
Destroys:
eax
/kernel/branches/kolibrios-pe-clevermouse/docs/usbapi.txt
0,0 → 1,211
When the kernel detects a connected USB device, it configures the device in
terms of USB protocol - SET_ADDRESS + SET_CONFIGURATION, the first
configuration is always selected. The kernel also reads device descriptor to
print some information, reads and parses configuration descriptor. For every
interface the kernel looks for class code of this interface and loads the
corresponding COFF driver. Currently the correspondence is hardcoded into
the kernel code and looks as follows: 3 = usbhid.obj, 7 = usbprint.obj,
8 = usbstor.obj, 9 is handled by the kernel itself, other = usbother.obj.
 
The driver must be standard driver in COFF format, exporting procedure
named "START" and a variable named "version". Loader calls "START" procedure
as stdcall with one parameter DRV_ENTRY = 1; if initialization is successful,
the "START" procedure is also called by shutdown code with one parameter
DRV_EXIT = -1.
 
The driver must register itself as a USB driver in "START" procedure.
This is done by call to exported function RegUSBDriver and passing the returned
value as result of "START" procedure.
 
void* __stdcall RegUSBDriver(
const char* name,
void* handler,
const USBFUNC* usbfunc
);
 
The parameter 'name' should match the name of driver, "usbhid" for usbhid.obj.
The parameter 'handler' is optional; if it is non-NULL, it should point to
the standard handler for IOCTL interface as in non-USB drivers.
The parameter 'usbfunc' is a pointer to the following structure:
 
struc USBFUNC
{
.strucsize dd ? ; size of the structure, including this field
.add_device dd ? ; pointer to AddDevice function in the driver
; required
.device_disconnect dd ? ; pointer to DeviceDisconnected function in the driver
; optional, may be NULL
; other functions may be added in the future
}
 
The driver should implement the function
 
void* __stdcall AddDevice(
void* pipe0,
void* configdescr,
void* interfacedescr
);
 
The parameter 'pipe0' is a handle of the control pipe for endpoint zero
of the device. It can be used as the argument of USBControlTransferAsync.
The parameter 'configdescr' points to USB configuration descriptor
and all associated data, as returned by GET_DESCRIPTOR request.
The total length of all associated data is contained in the configuration
descriptor.
The parameter 'interfacedescr' points to USB interface descriptor corresponding
to the interface which is initializing. This is a pointer inside data
associated with the configuration descriptor.
Note that one device can implement many interfaces, so AddDevice may be
called several times with the same 'configdescr' and different 'interfacedescr'.
The returned value NULL means that the initialization has failed.
Any other value means that configuration was successful; the kernel does not
try to interpret the value. It can be, for example, pointer to the internal
data allocated with Kmalloc, or index in some internal table.
 
The driver can implement the function
 
void __stdcall DeviceDisconnected(
void* devicedata
);
 
If this function is implemented, the kernel calls it when the device is
disconnected, passing the returned value of AddDevice as 'devicedata'.
 
The driver can use the following functions exported by the kernel.
 
void* __stdcall USBOpenPipe(
void* pipe0,
int endpoint,
int maxpacketsize,
int type,
int interval
);
 
The parameter 'pipe0' is a handle of the pipe for endpoint zero for
the device, as passed to AddDevice. It is used to identify the device.
The parameter 'endpoint' is endpoint number as defined by USB. Lower
4 bits form the number itself, bit 7 - highest bit of low byte -
is 0/1 for OUT/IN endpoints, other bits should be zero.
The parameter 'maxpacketsize' sets the maximum packet size for this pipe.
The parameter 'type' selects the type of the endpoint as defined by USB:
0 = control, 1 = isochronous (not supported yet), 2 = bulk, 3 = interrupt.
The parameter 'interval' is ignored for control and bulk endpoints.
For interrupt endpoints, it sets the polling interval in milliseconds.
The function returns a handle to the pipe or NULL on failure.
The output handle becomes invalid when a) it is explicitly closed with
the following function or b) the function DeviceDisconnected provided
by the driver returns.
 
void __stdcall USBClosePipe(
void* pipe
);
 
Releases all resources associated with the given pipe. The only parameter
must be a handle returned by USBOpenPipe.
When a device is disconnected, all associated pipes are closed by the kernel;
there is no need to ever call this function if all pipes are used continuously
while a device is connected.
 
void* __stdcall USBNormalTransferAsync(
void* pipe,
void* buffer,
int size,
void* callback,
void* calldata,
int flags
);
void* __stdcall USBControlTransferAsync(
void* pipe,
void* setup,
void* buffer,
int size,
void* callback,
void* calldata,
int flags
);
 
The first function inserts a bulk or interrupt transfer to the transfer queue
for given pipe. Type and direction of transfer are fixed for bulk and interrupt
endpoints and are set in USBOpenPipe. The second function inserts a control
transfer to the transfer queue for given pipe. Direction of a control transfer
is concluded from 'setup' packet, bit 7 of byte 0 is set for IN transfers
and cleared for OUT transfers. These function return immediately; when data
are transferred, the callback function will be called.
 
The parameter 'pipe' is a handle returned by USBOpenPipe.
The parameter 'setup' of USBControlTransferAsync points to 8-byte
configuration packet as defined by USB.
The parameter 'buffer' is a pointer to buffer. For IN transfers, it will be
filled with the data. For OUT transfers, it should contain data to be
transferred. It can be NULL for an empty transfer or if no additional data are
required for a control transfer.
The parameter 'size' is size of data to transfer. It can be 0 for an empty
transfer or if no additional data are required for a control transfer.
The parameter 'callback' is a pointer to a function which will be called
when the transfer will be done.
The parameter 'calldata' will be passed as is to the callback function.
For example, it can be NULL, it can be a pointer to device data or it can be
a pointer to data used to pass additional parameters between caller and
callback. The transfer-specific data can also be associated with 'buffer',
preceding (negative offsets from 'buffer') or following (offsets more than
or equal to 'size') the buffer itself.
The parameter 'flags' is the bitmask.
The bit 0 is ignored for OUT transfers, for IN transfers it controls whether
the device can transfer less data than 'size' bytes. If the bit is 0, a small
transfer is an error; if the bit is 1, a small transfer is OK.
All other bits are reserved and should be zero.
The returned value is NULL if an error occured and non-NULL if the transfer
was successfully queued. If an error will occur later, the callback function
will be notified.
 
void __stdcall CallbackFunction(
void* pipe,
int status,
void* buffer,
int length,
void* calldata
);
 
The parameters 'pipe', 'buffer', 'calldata' are the same as for the
corresponding USB*TransferAsync.
The parameter 'length' is the number of bytes transferred. For
control transfers, this includes 8 bytes from SETUP stage, so
0 means that SETUP stage failed and 'size'+8 means full transfer.
The parameter 'status' is nonzero if an error occured.
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 due to device disconnect
USB_STATUS_CANCELLED = 17 ; transfer cancelled with USBAbortPipe
 
If several transfers are queued for the same pipe, their callback functions
are called in the same order as they were queued.
When a pipe is closed, either explicitly with USBClosePipe, or
implicitly due to device disconnect, all callback functions are called
with USB_STATUS_CLOSED. The call to DeviceDisconnected() occurs after
all callbacks.
 
void __stdcall USBAbortPipe(void* pipe);
Initiates cancellation of all active transfers for the given pipe. Asynchronous.
When a transfer will be cancelled, the associated callback function
will be called with USB_STATUS_CANCELLED.
 
void* __stdcall USBGetParam(void* pipe0, int param);
Returns miscellaneous parameters of the device.
pipe0 is the pointer to the config pipe.
param = 0: return pointer to device descriptor
param = 1: return pointer to config descriptor, same as passed to AddDevice
param = 2: return speed at which the device is operating, one of
USB_SPEED_FS = 0 ; full-speed
USB_SPEED_LS = 1 ; low-speed
USB_SPEED_HS = 2 ; high-speed
/kernel/branches/kolibrios-pe-clevermouse/docs/loader_doc.txt
0,0 → 1,95
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2011. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
; (english text below)
 
;------------------------------------------
; Интерфейс сохранения параметров
;------------------------------------------
Если при передаче управления ядру загрузчик устанавливает AX='KL',
то в DS:SI ядро ожидает дальнего указателя на следующую структуру:
db версия структуры, должна быть 1
dw флаги:
бит 0 установлен = присутствует образ рамдиска в памяти
dd дальний указатель на процедуру сохранения параметров
может быть 0, если загрузчик не поддерживает
Процедура сохранения параметров должна записать первый сектор ядра
kernel.mnt назад на то место, откуда она его считала; возврат из
процедуры осуществляется по retf.
 
;------------------------------------------
; Указание загрузчиком системного каталога
;------------------------------------------
Перед передачей управления ядру могут быть установлены следующие регистры:
CX='HA'
DX='RD'
Это указывает на то, что регистр BX указывает на системный раздел. Каталог /kolibri/ на
этом разделе является системным, к нему можно обращаться как к /sys/
 
Возможные значения регистра BL (указывает на устройство):
'a' - Primary Master
'b' - Primary Slave
'c' - Secondary Master
'd' - Secondary Slave
'r' - RAM диск
'm' - Приводы CD-ROM
 
Возможные значения регистра BH (указывает на раздел):
для BL='a','b','c','d','r' - указывает на раздел, где расположен системный каталог
для BL='m',указывает на номер физического устройства, с которого надо начинать поиск системного каталога.
 
примеры значений регистра BX:
'a1' - /hd0/1/
'a2' - /hd0/2/
'b1' - /hd1/1/
'd4' - /hd3/4/
'm0' - поиск по сидюкам каталога kolibri
'r1' - /rd/1/
 
 
;------------------------------------------
; Interface for saving boot-screen settings
;------------------------------------------
If a loader sets AX='KL' when transferring control to the kernel,
the kernel expects in DS:SI far pointer to the following structure:
db structure version, must be 1
dw flags
bit 0 set = ramdisk image in memory is present
dd far pointer to save settings procedure
may be 0 if such procedure is not supported by loader
Procedure for saving settings must write the first sector of the kernel
kernel.mnt back to the place, from where it has been read; return from
this procedure must be with retf.
 
;------------------------------------------
; System directory information from loader
;------------------------------------------
Before transfer of control to the kernel following registers can be set:
CX = 'HA'
DX = 'RD'
This indicates that the register BX identifies system partition. The folder /kolibri/ in
this partition is system folder, it can be referenced as /sys/
 
Possible values for register BL (indicates the device):
'a' - Primary Master
'b' - Primary Slave
'c' - Secondary Master
'd' - Secondary Slave
'r' - RAM disc
'm' - ROM drives
 
Possible values for register BH (indicates section):
for BL = 'a', 'b', 'c', 'd', 'r' to denote partition where the system folder
for BL = 'm', indicates the number of physical devices, which must begin a systematic search directory.
 
Examples of register BX:
'a1' - /hd0/1/
'a2' - /hd0/2/
'b1' - /hd1/1/
'd4' - /hd3/4/
'm0' - search directory 'kolibri' by all CD-ROMs
'r1' - /rd/1/
/kernel/branches/kolibrios-pe-clevermouse/docs/apm.txt
0,0 → 1,518
--------p-155300-----------------------------
INT 15 - Advanced Power Management v1.0+ - INSTALLATION CHECK
AX = 5300h
BX = device ID of system BIOS (0000h)
Return: CF clear if successful
AH = major version (BCD)
AL = minor version (BCD)
BX = 504Dh ("PM")
CX = flags (see #00472)
CF set on error
AH = error code (06h,09h,86h) (see #00473)
BUG: early versions of the Award Modular BIOS with built-in APM support
reportedly do not set BX on return
 
Bitfields for APM flags:
Bit(s) Description (Table 00472)
0 16-bit protected mode interface supported
1 32-bit protected mode interface supported
2 CPU idle call reduces processor speed
3 BIOS power management disabled
4 BIOS power management disengaged (APM v1.1)
5-7 reserved
 
(Table 00473)
Values for APM error code:
01h power management functionality disabled
02h interface connection already in effect
03h interface not connected
04h real-mode interface not connected
05h 16-bit protected-mode interface already connected
06h 16-bit protected-mode interface not supported
07h 32-bit protected-mode interface already connected
08h 32-bit protected-mode interface not supported
09h unrecognized device ID
0Ah invalid parameter value in CX
0Bh (APM v1.1) interface not engaged
0Ch (APM v1.2) function not supported
0Dh (APM v1.2) Resume Timer disabled
0Eh-1Fh reserved for other interface and general errors
20h-3Fh reserved for CPU errors
40h-5Fh reserved for device errors
60h can't enter requested state
61h-7Fh reserved for other system errors
80h no power management events pending
81h-85h reserved for other power management event errors
86h APM not present
87h-9Fh reserved for other power management event errors
A0h-FEh reserved
FFh undefined
--------p-155301-----------------------------
INT 15 - Advanced Power Management v1.0+ - CONNECT REAL-MODE INTERFACE
AX = 5301h
BX = device ID of system BIOS (0000h)
Return: CF clear if successful
CF set on error
AH = error code (02h,05h,07h,09h) (see #00473)
Note: on connection, an APM v1.1 or v1.2 BIOS switches to APM v1.0
compatibility mode until it is informed that the user supports a
newer version of APM (see AX=530Eh)
SeeAlso: AX=5302h,AX=5303h,AX=5304h
--------p-155302-----------------------------
INT 15 R - Advanced Power Management v1.0+ - CONNECT 16-BIT PROTMODE INTERFACE
AX = 5302h
BX = device ID of system BIOS (0000h)
Return: CF clear if successful
AX = real-mode segment base address of protected-mode 16-bit code
segment
BX = offset of entry point
CX = real-mode segment base address of protected-mode 16-bit data
segment
---APM v1.1---
SI = APM BIOS code segment length
DI = APM BIOS data segment length
CF set on error
AH = error code (02h,05h,06h,07h,09h) (see #00473)
Notes: the caller must initialize two consecutive descriptors with the
returned segment base addresses; these descriptors must be valid
whenever the protected-mode interface is called, and will have
their limits arbitrarily set to 64K.
the protected mode interface is invoked by making a far call with the
same register values as for INT 15; it must be invoked while CPL=0,
the code segment descriptor must have a DPL of 0, the stack must be
in a 16-bit segment and have enough room for BIOS use and possible
interrupts, and the current I/O permission bit map must allow access
to the I/O ports used for power management.
functions 00h-03h are not available from protected mode
on connection, an APM v1.1 or v1.2 BIOS switches to APM v1.0
compatibility mode until it is informed that the user supports a
newer version of APM (see AX=530Eh)
SeeAlso: AX=5301h,AX=5303h,AX=5304h
--------p-155303-----------------------------
INT 15 - Advanced Power Management v1.0+ - CONNECT 32-BIT PROTMODE INTERFACE
AX = 5303h
BX = device ID of system BIOS (0000h)
Return: CF clear if successful
AX = real-mode segment base address of protected-mode 32-bit code
segment
EBX = offset of entry point
CX = real-mode segment base address of protected-mode 16-bit code
segment
DX = real-mode segment base address of protected-mode 16-bit data
segment
---APM v1.1---
SI = APM BIOS code segment length
DI = APM BIOS data segment length
CF set on error
AH = error code (02h,05h,07h,08h,09h) (see #00473)
Notes: the caller must initialize three consecutive descriptors with the
returned segment base addresses for 32-bit code, 16-bit code, and
16-bit data, respectively; these descriptors must be valid whenever
the protected-mode interface is called, and will have their limits
arbitrarily set to 64K.
the protected mode interface is invoked by making a far call to the
32-bit code segment with the same register values as for INT 15; it
must be invoked while CPL=0, the code segment descriptor must have a
DPL of 0, the stack must be in a 32-bit segment and have enough room
for BIOS use and possible interrupts, and the current I/O permission
bit map must allow access to the I/O ports used for power management.
functions 00h-03h are not available from protected mode
on connection, an APM v1.1 or v1.2 BIOS switches to APM v1.0
compatibility mode until it is informed that the user supports a
newer version of APM (see AX=530Eh)
SeeAlso: AX=5301h,AX=5302h,AX=5304h
--------p-155304-----------------------------
INT 15 - Advanced Power Management v1.0+ - DISCONNECT INTERFACE
AX = 5304h
BX = device ID of system BIOS (0000h)
Return: CF clear if successful
CF set on error
AH = error code (03h,09h) (see #00473)
SeeAlso: AX=5301h,AX=5302h,AX=5303h
--------p-155305-----------------------------
INT 15 - Advanced Power Management v1.0+ - CPU IDLE
AX = 5305h
Return: CF clear if successful (after system leaves idle state)
CF set on error
AH = error code (03h,0Bh) (see #00473)
Notes: call when the system is idle and should be suspended until the next
system event or interrupt
should not be called from within a hardware interrupt handler to avoid
reentrance problems
if an interrupt causes the system to resume normal processing, the
interrupt may or may not have been handled when the BIOS returns
from this call; thus, the caller should allow interrupts on return
interrupt handlers may not retain control if the BIOS allows
interrupts while in idle mode even if they are able to determine
that they were called from idle mode
the caller should issue this call continuously in a loop until it needs
to perform some processing of its own
SeeAlso: AX=1000h,AX=5306h,INT 2F/AX=1680h
--------p-155306-----------------------------
INT 15 - Advanced Power Management v1.0+ - CPU BUSY
AX = 5306h
Return: CF clear if successful
CF set on error
AH = error code (03h,0Bh) (see #00473)
Notes: called to ensure that the system runs at full speed even on systems
where the BIOS is unable to recognize increased activity (especially
if interrupts are hooked by other programs and not chained to the
BIOS)
this call may be made even when the system is already running at full
speed, but it will create unnecessary overhead
should not be called from within a hardware interrupt handler to avoid
reentrance problems
SeeAlso: AX=5305h
--------p-155307-----------------------------
INT 15 - Advanced Power Management v1.0+ - SET POWER STATE
AX = 5307h
BX = device ID (see #00474)
CX = system state ID (see #00475)
Return: CF clear if successful
CF set on error
AH = error code (01h,03h,09h,0Ah,0Bh,60h) (see #00473)
Note: should not be called from within a hardware interrupt handler to avoid
reentrance problems
SeeAlso: AX=530Ch
 
(Table 00474)
Values for APM device IDs:
0000h system BIOS
0001h all devices for which the system BIOS manages power
01xxh display (01FFh for all attached display devices)
02xxh secondary storage (02FFh for all attached secondary storage devices)
03xxh parallel ports (03FFh for all attached parallel ports)
04xxh serial ports (04FFh for all attached serial ports)
---APM v1.1+ ---
05xxh network adapters (05FFh for all attached network adapters)
06xxh PCMCIA sockets (06FFh for all)
0700h-7FFFh reserved
80xxh system battery devices (APM v1.2)
8100h-DFFFh reserved
Exxxh OEM-defined power device IDs
F000h-FFFFh reserved
 
(Table 00475)
Values for system state ID:
0000h ready (not supported for device ID 0001h)
0001h stand-by
0002h suspend
0003h off (not supported for device ID 0001h in APM v1.0)
---APM v1.1---
0004h last request processing notification (only for device ID 0001h)
0005h last request rejected (only for device ID 0001h)
0006h-001Fh reserved system states
0020h-003Fh OEM-defined system states
0040h-007Fh OEM-defined device states
0080h-FFFFh reserved device states
--------p-155307CX0001-----------------------
INT 15 - Advanced Power Management v1.0+ - SYSTEM STAND-BY
AX = 5307h
CX = 0001h
BX = 0001h (device ID for all power-managed devices)
Return: CF clear
Notes: puts the entire system into stand-by mode; normally called in response
to a System Stand-by Request notification after any necessary
processing, but may also be invoked at the caller's discretion
should not be called from within a hardware interrupt handler to avoid
reentrance problems
the stand-by state is typically exited on an interrupt
SeeAlso: AX=4280h,AX=5307h/CX=0002h"SUSPEND",AX=5307h/CX=0003h,AX=530Bh
--------p-155307CX0002-----------------------
INT 15 - Advanced Power Management v1.0+ - SUSPEND SYSTEM
AX = 5307h
CX = 0002h
BX = 0001h (device ID for all power-managed devices)
Return: after system is resumed
CF clear
Notes: puts the entire system into a low-power suspended state; normally
called in response to a Suspend System Request notification after
any necessary processing, but may also be invoked at the caller's
discretion
should not be called from within a hardware interrupt handler to avoid
reentrance problems
the caller may need to update its date and time values because the
system could have been suspended for a long period of time
SeeAlso: AX=5307h/CX=0001h"STAND-BY",AX=530Bh
--------p-155307CX0003-----------------------
INT 15 - Advanced Power Management v1.2 - TURN OFF SYSTEM
AX = 5307h
CX = 0003h
BX = 0001h (device ID for all power-managed devices)
Return: after system is resumed
CF clear
Notes: if supported by the system's power supply, turns off the system power
SeeAlso: AX=5307h/CX=0001h"STAND-BY",AX=530Bh
--------p-155308-----------------------------
INT 15 - Advanced Power Management v1.0+ - ENABLE/DISABLE POWER MANAGEMENT
AX = 5308h
BX = device ID for all devices power-managed by APM
0001h (APM v1.1+)
FFFFh (APM v1.0)
CX = new state
0000h disabled
0001h enabled
Return: CF clear if successful
CF set on error
AH = error code (01h,03h,09h,0Ah,0Bh) (see #00473)
Notes: when power management is disabled, the system BIOS will not
automatically power down devices, enter stand-by or suspended mode,
or perform any power-saving actions in response to AX=5305h calls
should not be called from within a hardware interrupt handler to avoid
reentrance problems
the APM BIOS should never be both disabled and disengaged at the same
time
SeeAlso: AX=5309h,AX=530Dh,AX=530Fh
--------p-155309-----------------------------
INT 15 - Advanced Power Management v1.0+ - RESTORE POWER-ON DEFAULTS
AX = 5309h
BX = device ID for all devices power-managed by APM
0001h (APM v1.1)
FFFFh (APM v1.0)
Return: CF clear if successful
CF set on error
AH = error code (03h,09h,0Bh) (see #00473)
Note: should not be called from within a hardware interrupt handler to avoid
reentrance problems
SeeAlso: AX=5308h
--------p-15530A-----------------------------
INT 15 - Advanced Power Management v1.0+ - GET POWER STATUS
AX = 530Ah
BX = device ID
0001h all devices power-managed by APM
80xxh specific battery unit number XXh (01h-FFh) (APM v1.2)
Return: CF clear if successful
BH = AC line status
00h off-line
01h on-line
02h on backup power (APM v1.1)
FFh unknown
other reserved
BL = battery status (see #00476)
CH = battery flag (APM v1.1+) (see #00477)
CL = remaining battery life, percentage
00h-64h (0-100) percentage of full charge
FFh unknown
DX = remaining battery life, time (APM v1.1) (see #00478)
---if specific battery unit specified---
SI = number of battery units currently installed
CF set on error
AH = error code (09h,0Ah) (see #00473)
Notes: should not be called from within a hardware interrupt handler to avoid
reentrance problems
supported in real mode (INT 15) and both 16-bit and 32-bit protected
mode
 
(Table 00476)
Values for APM v1.0+ battery status:
00h high
01h low
02h critical
03h charging
FFh unknown
other reserved
SeeAlso: #00477,#00478
 
Bitfields for APM v1.1+ battery flag:
Bit(s) Description (Table 00477)
0 high
1 low
2 critical
3 charging
4 selected battery not present (APM v1.2)
5-6 reserved (0)
7 no system battery
Note: all bits set (FFh) if unknown
SeeAlso: #00476,#00478
 
Bitfields for APM v1.1+ remaining battery life:
Bit(s) Description (Table 00478)
15 time units: 0=seconds, 1=minutes
14-0 battery life in minutes or seconds
Note: all bits set (FFFFh) if unknown
SeeAlso: #00476,#00477
--------p-15530B-----------------------------
INT 15 - Advanced Power Management v1.0+ - GET POWER MANAGEMENT EVENT
AX = 530Bh
Return: CF clear if successful
BX = event code (see #00479)
CX = event information (APM v1.2) if BX=0003h or BX=0004h
bit 0: PCMCIA socket was powered down in suspend state
CF set on error
AH = error code (03h,0Bh,80h) (see #00473)
Notes: although power management events are often asynchronous, notification
will not be made until polled via this call to permit software to
only receive event notification when it is prepared to process
power management events; since these events are not very time-
critical, it should be sufficient to poll once or twice per second
the critical resume notification is made after the system resumes
from an emergency suspension; normally, the system BIOS only notifies
its partner that it wishes to suspend and relies on the partner to
actually request the suspension, but no notification is made on an
emergency suspension
should not be called from within a hardware interrupt handler to avoid
reentrance problems
SeeAlso: AX=5307h,AX=5307h/CX=0001h"STAND-BY",AX=5307h/CX=0002h"SUSPEND"
 
(Table 00479)
Values for APM event code:
0001h system stand-by request
0002h system suspend request
0003h normal resume system notification
0004h critical resume system notification
0005h battery low notification
---APM v1.1---
0006h power status change notification
0007h update time notification
0008h critical system suspend notification
0009h user system standby request notification
000Ah user system suspend request notification
000Bh system standby resume notification
---APM v1.2---
000Ch capabilities change notification (see AX=5310h)
------
000Dh-00FFh reserved system events
01xxh reserved device events
02xxh OEM-defined APM events
0300h-FFFFh reserved
--------p-15530C-----------------------------
INT 15 - Advanced Power Management v1.1+ - GET POWER STATE
AX = 530Ch
BX = device ID (see #00474)
Return: CF clear if successful
CX = system state ID (see #00475)
CF set on error
AH = error code (01h,09h) (see #00473)
SeeAlso: AX=5307h
--------p-15530D-----------------------------
INT 15 - Advanced Power Management v1.1+ - EN/DISABLE DEVICE POWER MANAGEMENT
AX = 530Dh
BX = device ID (see #00474)
CX = function
0000h disable power management
0001h enable power management
Return: CF clear if successful
CF set on error
AH = error code (01h,03h,09h,0Ah,0Bh) (see #00473)
Desc: specify whether automatic power management should be active for a
given device
SeeAlso: AX=5308h,AX=530Fh
--------p-15530E-----------------------------
INT 15 - Advanced Power Management v1.1+ - DRIVER VERSION
AX = 530Eh
BX = device ID of system BIOS (0000h)
CH = APM driver major version (BCD)
CL = APM driver minor version (BCD) (02h for APM v1.2)
Return: CF clear if successful
AH = APM connection major version (BCD)
AL = APM connection minor version (BCD)
CF set on error
AH = error code (03h,09h,0Bh) (see #00473)
SeeAlso: AX=5300h,AX=5303h
--------p-15530F-----------------------------
INT 15 - Advanced Power Management v1.1+ - ENGAGE/DISENGAGE POWER MANAGEMENT
AX = 530Fh
BX = device ID (see #00474)
CX = function
0000h disengage power management
0001h engage power management
Return: CF clear if successful
CF set on error
AH = error code (01h,09h) (see #00473)
Notes: unlike AX=5308h, this call does not affect the functioning of the APM
BIOS
when cooperative power management is disengaged, the APM BIOS performs
automatic power management of the system or device
SeeAlso: AX=5308h,AX=530Dh
--------p-155310-----------------------------
INT 15 - Advanced Power Management v1.2 - GET CAPABILITIES
AX = 5310h
BX = device ID (see #00474)
0000h (APM BIOS)
other reserved
Return: CF clear if successful
BL = number of battery units supported (00h if no system batteries)
CX = capabilities flags (see #00480)
CF set on error
AH = error code (01h,09h,86h) (see #00473)
Notes: this function is supported via the INT 15, 16-bit protected mode, and
32-bit protected mode interfaces; it does not require that a
connection be established prior to use
this function will return the capabilities currently in effect, not
any new settings which have been made but do not take effect until
a system restart
SeeAlso: AX=5300h,AX=530Fh,AX=5311h,AX=5312h,AX=5313h
 
Bitfields for APM v1.2 capabilities flags:
Bit(s) Description (Table 00480)
15-8 reserved
7 PCMCIA Ring Indicator will wake up system from suspend mode
6 PCMCIA Ring Indicator will wake up system from standby mode
5 Resume on Ring Indicator will wake up system from suspend mode
4 Resume on Ring Indicator will wake up system from standby mode
3 resume timer will wake up system from suspend mode
2 resume timer will wake up system from standby mode
1 can enter global suspend state
0 can enter global standby state
--------p-155311-----------------------------
INT 15 - Advanced Power Management v1.2 - GET/SET/DISABLE RESUME TIMER
AX = 5311h
BX = device ID (see #00474)
0000h (APM BIOS)
other reserved
CL = function
00h disable Resume Timer
01h get Resume Timer
02h set Resume Timer
CH = resume time, seconds (BCD)
DL = resume time, minutes (BCD)
DH = resume time, hours (BCD)
SI = resume date (BCD), high byte = month, low byte = day
DI = resume date, year (BCD)
Return: CF clear if successful
---if getting timer---
CH = resume time, seconds (BCD)
DL = resume time, minutes (BCD)
DH = resume time, hours (BCD)
SI = resume date (BCD), high byte = month, low byte = day
DI = resume date, year (BCD)
CF set on error
AH = error code (03h,09h,0Ah,0Bh,0Ch,0Dh,86h) (see #00473)
Notes: this function is supported via the INT 15, 16-bit protected mode, and
32-bit protected mode interfaces
SeeAlso: AX=5300h,AX=5310h,AX=5312h,AX=5313h
--------p-155312-----------------------------
INT 15 - Advanced Power Management v1.2 - ENABLE/DISABLE RESUME ON RING
AX = 5312h
BX = device ID (see #00474)
0000h (APM BIOS)
other reserved
CL = function
00h disable Resume on Ring Indicator
01h enable Resume on Ring Indicator
02h get Resume on Ring Indicator status
Return: CF clear if successful
CX = resume status (0000h disabled, 0001h enabled)
CF set on error
AH = error code (03h,09h,0Ah,0Bh,0Ch,86h) (see #00473)
Notes: this function is supported via the INT 15, 16-bit protected mode, and
32-bit protected mode interfaces
SeeAlso: AX=5300h,AX=5310h,AX=5311h,AX=5313h
--------p-155313-----------------------------
INT 15 - Advanced Power Management v1.2 - ENABLE/DISABLE TIMER-BASED REQUESTS
AX = 5313h
BX = device ID (see #00474)
0000h (APM BIOS)
other reserved
CL = function
00h disable timer-based requests
01h enable timer-based requests
02h get timer-based requests status
Return: CF clear if successful
CX = timer-based requests status (0000h disabled, 0001h enabled)
CF set on error
AH = error code (03h,09h,0Ah,0Bh,86h) (see #00473)
Notes: this function is supported via the INT 15, 16-bit protected mode, and
32-bit protected mode interfaces
some BIOSes set AH on return even when successful
SeeAlso: AX=5300h,AX=5310h,AX=5311h,AX=5312h
/kernel/branches/kolibrios-pe-clevermouse/docs
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/acpi/acpi.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/proc32.inc
0,0 → 1,316
 
; Macroinstructions for defining and calling procedures
 
; @brief Directly call STDCALL procedure
; @param proc Callee name
; @param arg Arguments to pass
macro stdcall proc,[arg]
{ common
if ~ arg eq
reverse
pushd arg
common
end if
call proc }
 
; @brief Indirectly call STDCALL procedure
; @param proc Callee name
; @param arg Arguments to pass
macro invoke proc,[arg]
{ common
if ~ arg eq
reverse
pushd arg
common
end if
call [proc] }
 
; @brief Directly call CDECL procedure
; @param proc Callee name
; @param arg Arguments to pass
macro ccall proc,[arg]
{ common
size@ccall = 0
if ~ arg eq
reverse
pushd arg
size@ccall = size@ccall+4
common
end if
call proc
if size@ccall
add esp, size@ccall
end if }
 
; @brief Indirectly call CDECL procedure
; @param proc Callee name
; @param arg Arguments to pass
macro cinvoke proc,[arg]
{ common
size@ccall = 0
if ~ arg eq
reverse
pushd arg
size@ccall = size@ccall+4
common
end if
call [proc]
if size@ccall
add esp, size@ccall
end if }
 
; @brief Define a procedure.\n
; Calling convention for the procedure may be defined before parameter
; list using `stdcall` or `c` word like this:\n
; `proc name stdcall, param0, param1`\n
; List of registers used in the procedure may be specified before
; parameter list using `uses` word like this:\n
; `proc name uses eax ebx ecx, param0, param1`\n
; If you need to specify both calling convention and used registers
; put calling convention first and then `uses` statement like this:\n
; `proc name stdcall uses ebx ecx edx, param0, param1`\n
; The defined procedure should be ended using `endp` macro.
; @param args Name of the procedure and a comma-separated argument list.
; Type of any parameter may be specified by semicolon after its
; name like this:\n
; `proc name param0:dword, param1:qword`.
macro proc [args]
{ common
match name params, args>
\{ define@proc name,<params \} }
 
prologue@proc equ prologuedef
 
; @dont_give_a_doxygen
macro prologuedef procname,flag,parmbytes,localbytes,reglist
{ local loc
loc = (localbytes+3) and (not 3)
parmbase@proc equ ebp+8
localbase@proc equ ebp-loc
if parmbytes | localbytes
push ebp
mov ebp, esp
if localbytes
sub esp, loc
end if
end if
irps reg, reglist \{ push reg \} }
 
epilogue@proc equ epiloguedef
 
; @dont_give_a_doxygen
macro epiloguedef procname,flag,parmbytes,localbytes,reglist
{ irps reg, reglist \{ reverse pop reg \}
if parmbytes | localbytes
leave
end if
if flag and 10000b
retn
else
retn parmbytes
end if }
 
close@proc equ
 
; @dont_give_a_doxygen
macro define@proc name,statement
{ local params,flag,regs,parmbytes,localbytes,current
if used name
name:
match =stdcall args, statement \{ params equ args
flag = 11b \}
match =stdcall, statement \{ params equ
flag = 11b \}
match =c args, statement \{ params equ args
flag = 10001b \}
match =c, statement \{ params equ
flag = 10001b \}
match =params, params \{ params equ statement
flag = 0 \}
match =uses reglist=,args, params \{ regs equ reglist
params equ args \}
match =regs =uses reglist, regs params \{ regs equ reglist
params equ \}
match =regs, regs \{ regs equ \}
match prologue:reglist, prologue@proc:<regs> \{ prologue name,flag,parmbytes,localbytes,reglist \}
virtual at parmbase@proc
match =,args, params \{ defargs@proc args \}
match =args@proc args, args@proc params \{ defargs@proc args \}
parmbytes = $-(parmbase@proc)
end virtual
name # % = parmbytes/4
all@vars equ
current = 0
macro locals
\{ virtual at localbase@proc+current
macro label def \\{ match . type,def> \\\{ deflocal@proc .,label,<type \\\} \\}
struc db [val] \\{ \common deflocal@proc .,db,val \\}
struc du [val] \\{ \common deflocal@proc .,du,val \\}
struc dw [val] \\{ \common deflocal@proc .,dw,val \\}
struc dp [val] \\{ \common deflocal@proc .,dp,val \\}
struc dd [val] \\{ \common deflocal@proc .,dd,val \\}
struc dt [val] \\{ \common deflocal@proc .,dt,val \\}
struc dq [val] \\{ \common deflocal@proc .,dq,val \\}
struc rb cnt \\{ deflocal@proc .,rb cnt, \\}
struc rw cnt \\{ deflocal@proc .,rw cnt, \\}
struc rp cnt \\{ deflocal@proc .,rp cnt, \\}
struc rd cnt \\{ deflocal@proc .,rd cnt, \\}
struc rt cnt \\{ deflocal@proc .,rt cnt, \\}
struc rq cnt \\{ deflocal@proc .,rq cnt, \\} \}
macro endl
\{ purge label
restruc db,du,dw,dp,dd,dt,dq
restruc rb,rw,rp,rd,rt,rq
current = $-(localbase@proc)
end virtual \}
macro ret operand
\{ match any, operand \\{ retn operand \\}
match , operand \\{ match epilogue:reglist, epilogue@proc:<regs> \\\{ epilogue name,flag,parmbytes,localbytes,reglist \\\} \\} \}
macro finish@proc
\{ localbytes = current
match close:reglist, close@proc:<regs> \\{ close name,flag,parmbytes,localbytes,reglist \\}
end if \} }
 
; @dont_give_a_doxygen
macro defargs@proc [arg]
{ common
if ~ arg eq
forward
local ..arg,current@arg
match argname:type, arg
\{ current@arg equ argname
label ..arg type
argname equ ..arg
if dqword eq type
dd ?,?,?,?
else if tbyte eq type
dd ?,?,?
else if qword eq type | pword eq type
dd ?,?
else
dd ?
end if \}
match =current@arg,current@arg
\{ current@arg equ arg
arg equ ..arg
..arg dd ? \}
common
args@proc equ current@arg
forward
restore current@arg
common
end if }
 
; @dont_give_a_doxygen
macro deflocal@proc name,def,[val] { name def val }
 
; @dont_give_a_doxygen
macro deflocal@proc name,def,[val]
{ common
match vars, all@vars \{ all@vars equ all@vars, \}
all@vars equ all@vars name
forward
local ..var,..tmp
..var def val
match =?, val \{ ..tmp equ \}
match any =?, val \{ ..tmp equ \}
match any (=?), val \{ ..tmp equ \}
match =label, def \{ ..tmp equ \}
match tmp : value, ..tmp : val
\{ tmp: end virtual
initlocal@proc ..var,def value
virtual at tmp\}
common
match first rest, ..var, \{ name equ first \} }
 
struc label type { label . type }
 
; @dont_give_a_doxygen
macro initlocal@proc name,def
{ virtual at name
def
size@initlocal = $ - name
end virtual
position@initlocal = 0
while size@initlocal > position@initlocal
virtual at name
def
if size@initlocal - position@initlocal < 2
current@initlocal = 1
load byte@initlocal byte from name+position@initlocal
else if size@initlocal - position@initlocal < 4
current@initlocal = 2
load word@initlocal word from name+position@initlocal
else
current@initlocal = 4
load dword@initlocal dword from name+position@initlocal
end if
end virtual
if current@initlocal = 1
mov byte [name+position@initlocal], byte@initlocal
else if current@initlocal = 2
mov word [name+position@initlocal], word@initlocal
else
mov dword [name+position@initlocal], dword@initlocal
end if
position@initlocal = position@initlocal + current@initlocal
end while }
 
; @brief Mark the end of a procedure created by `proc` macro
macro endp
{ purge ret,locals,endl
finish@proc
purge finish@proc
restore regs@proc
match all,args@proc \{ restore all \}
restore args@proc
match all,all@vars \{ restore all \} }
 
macro local [var]
{ common
locals
forward done@local equ
match varname[count]:vartype, var
\{ match =BYTE, vartype \\{ varname rb count
restore done@local \\}
match =WORD, vartype \\{ varname rw count
restore done@local \\}
match =DWORD, vartype \\{ varname rd count
restore done@local \\}
match =PWORD, vartype \\{ varname rp count
restore done@local \\}
match =QWORD, vartype \\{ varname rq count
restore done@local \\}
match =TBYTE, vartype \\{ varname rt count
restore done@local \\}
match =DQWORD, vartype \\{ label varname dqword
rq count+count
restore done@local \\}
match , done@local \\{ virtual
varname vartype
end virtual
rb count*sizeof.\#vartype
restore done@local \\} \}
match :varname:vartype, done@local:var
\{ match =BYTE, vartype \\{ varname db ?
restore done@local \\}
match =WORD, vartype \\{ varname dw ?
restore done@local \\}
match =DWORD, vartype \\{ varname dd ?
restore done@local \\}
match =PWORD, vartype \\{ varname dp ?
restore done@local \\}
match =QWORD, vartype \\{ varname dq ?
restore done@local \\}
match =TBYTE, vartype \\{ varname dt ?
restore done@local \\}
match =DQWORD, vartype \\{ label varname dqword
dq ?,?
restore done@local \\}
match , done@local \\{ varname vartype
restore done@local \\} \}
match ,done@local
\{ var
restore done@local \}
common
endl }
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/macros.inc
0,0 → 1,143
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
__REV = 0
 
macro $Revision a {
match =: Num =$,a \{
if __REV < Num
__REV = Num
end if
\}
}
 
macro ignore_empty_revision_keyword {
; svn keywords are neither substituted by git-svn nor catched by $Revision
; macro above, ignore them to not fail the build
macro $Rev#ision$ \{\}
}
ignore_empty_revision_keyword
 
$Revision$
 
 
;// mike.dld, 2006-29-01 [
 
; macros definition
macro diff16 title,l1,l2
{
local s,d
s = l2-l1
display title,': 0x'
repeat 16
d = 48 + s shr ((16-%) shl 2) and $0F
if d > 57
d = d + 65-57-1
end if
display d
end repeat
display 13,10
}
macro diff10 title,l1,l2
{
local s,d,z,m
s = l2-l1
z = 0
m = 1000000000
display title,': '
repeat 10
d = '0' + s / m
s = s - (s/m)*m
m = m / 10
if d <> '0'
z = 1
end if
if z <> 0
display d
end if
end repeat
display 13,10
}
 
include 'kglobals.inc'
 
; \begin{diamond}[29.09.2006]
 
; @brief May be useful for kernel debugging
; example 1:
; dbgstr 'Hello, World!'
; example 2:
; dbgstr 'Hello, World!', save_flags
; @param string Output string
; @param f Put here anything if you gonna save flags
macro dbgstr string*, f
{
local a
iglobal_nested
a db 'K : ',string,13,10,0
endg_nested
if ~ f eq
pushfd
end if
push esi
mov esi, a
call sys_msg_board_str
pop esi
if ~ f eq
popfd
end if
}
; \end{diamond}[29.09.2006]
 
 
macro list_init head
{
mov [head+LHEAD.next], head
mov [head+LHEAD.prev], head
}
 
macro __list_add new, prev, next
{
mov [next+LHEAD.prev], new
mov [new+LHEAD.next], next
mov [new+LHEAD.prev], prev
mov [prev+LHEAD.next], new
}
 
macro list_add new, head
{
mov eax, [head+LHEAD.next]
__list_add new, head, eax
}
 
macro list_add_tail new, head
{
mov eax, [head+LHEAD.prev]
__list_add new, eax, head
}
 
macro list_del entry
{
mov edx, [entry+LHEAD.next]
mov ecx, [entry+LHEAD.prev]
mov [edx+LHEAD.prev], ecx
mov [ecx+LHEAD.next], edx
}
 
; MOV Immediate.
; Useful for things like movi eax,10:
; shorter than regular mov, but slightly slower,
; do not use it in performance-critical places.
macro movi dst, imm
{
if imm >= -0x80 & imm <= 0x7F
push imm
pop dst
else
mov dst, imm
end if
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/hid/keyboard.inc
0,0 → 1,578
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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$
 
 
VKEY_LSHIFT = 00000000_00000001b
VKEY_RSHIFT = 00000000_00000010b
VKEY_LCONTROL = 00000000_00000100b
VKEY_RCONTROL = 00000000_00001000b
VKEY_LALT = 00000000_00010000b
VKEY_RALT = 00000000_00100000b
VKEY_CAPSLOCK = 00000000_01000000b
VKEY_NUMLOCK = 00000000_10000000b
VKEY_SCRLOCK = 00000001_00000000b
VKEY_LWIN = 00000010_00000000b
VKEY_RWIN = 00000100_00000000b
 
VKEY_SHIFT = VKEY_LSHIFT + VKEY_RSHIFT
VKEY_CONTROL = VKEY_LCONTROL + VKEY_RCONTROL
VKEY_ALT = VKEY_LALT + VKEY_RALT
 
uglobal
align 4
kb_state dd 0
ext_code db 0
 
keyboard_mode db 0
keyboard_data db 0
 
altmouseb db 0
ctrl_alt_del db 0
 
kb_lights db 0
old_kb_lights db 0
 
align 4
hotkey_scancodes rd 256 ; we have 256 scancodes
hotkey_list rd 256*4 ; max 256 defined hotkeys
hotkey_buffer rd 120*2 ; buffer for 120 hotkeys
endg
 
iglobal
hotkey_tests dd hotkey_test0
dd hotkey_test1
dd hotkey_test2
dd hotkey_test3
dd hotkey_test4
hotkey_tests_num = 5
endg
;---------------------------------------------------------------------
hotkey_test0:
test al, al
setz al
ret
;---------------------------------------------------------------------
hotkey_test1:
test al, al
setnp al
ret
;---------------------------------------------------------------------
hotkey_test2:
cmp al, 3
setz al
ret
;---------------------------------------------------------------------
hotkey_test3:
cmp al, 1
setz al
ret
;---------------------------------------------------------------------
hotkey_test4:
cmp al, 2
setz al
ret
;---------------------------------------------------------------------
hotkey_do_test:
push eax
mov edx, [kb_state]
shr edx, cl
add cl, cl
mov eax, [eax+4]
shr eax, cl
and eax, 15
cmp al, hotkey_tests_num
jae .fail
xchg eax, edx
and al, 3
call [hotkey_tests + edx*4]
cmp al, 1
pop eax
ret
;--------------------------------------
.fail:
stc
pop eax
ret
;---------------------------------------------------------------------
align 4
set_keyboard_data:
movzx eax, word[thread_count]; top window process
movzx eax, word[WIN_POS+eax*2]
shl eax, 8
mov al, [SLOT_BASE+eax+APPDATA.keyboard_mode]
mov [keyboard_mode], al
mov eax, ecx
push ebx esi edi ebp
call send_scancode
pop ebp edi esi ebx
ret
;---------------------------------------------------------------------
struct KEYBOARD
next dd ?
prev dd ?
functions dd ?
userdata dd ?
ends
struct KBDFUNC
strucsize dd ?
close dd ?
setlights dd ?
ends
 
iglobal
keyboards:
dd keyboards
dd keyboards
endg
uglobal
keyboard_list_mutex MUTEX
endg
 
register_keyboard:
push ebx
movi eax, sizeof.KEYBOARD
call malloc
test eax, eax
jz .nothing
mov ecx, [esp+4+4]
mov [eax+KEYBOARD.functions], ecx
mov ecx, [esp+8+4]
mov [eax+KEYBOARD.userdata], ecx
xchg eax, ebx
mov ecx, keyboard_list_mutex
call mutex_lock
mov ecx, keyboards
mov edx, [ecx+KEYBOARD.prev]
mov [ebx+KEYBOARD.next], ecx
mov [ebx+KEYBOARD.prev], edx
mov [edx+KEYBOARD.next], ebx
mov [ecx+KEYBOARD.prev], ebx
mov ecx, [ebx+KEYBOARD.functions]
cmp [ecx+KBDFUNC.strucsize], KBDFUNC.setlights
jbe .unlock
mov ecx, [ecx+KBDFUNC.setlights]
test ecx, ecx
jz .unlock
stdcall ecx, [ebx+KEYBOARD.userdata], dword [kb_lights]
.unlock:
mov ecx, keyboard_list_mutex
call mutex_unlock
xchg eax, ebx
.nothing:
pop ebx
ret 8
 
delete_keyboard:
push ebx
mov ebx, [esp+4+4]
mov ecx, keyboard_list_mutex
call mutex_lock
mov eax, [ebx+KEYBOARD.next]
mov edx, [ebx+KEYBOARD.prev]
mov [eax+KEYBOARD.prev], edx
mov [edx+KEYBOARD.next], eax
call mutex_unlock
mov ecx, [ebx+KEYBOARD.functions]
cmp [ecx+KBDFUNC.strucsize], KBDFUNC.close
jbe .nothing
mov ecx, [ecx+KBDFUNC.close]
test ecx, ecx
jz .nothing
stdcall ecx, [ebx+KEYBOARD.userdata]
.nothing:
pop ebx
ret 4
;---------------------------------------------------------------------
align 4
irq1:
movzx eax, word[thread_count]; top window process
movzx eax, word[WIN_POS+eax*2]
shl eax, BSF sizeof.APPDATA
mov al, [SLOT_BASE+eax+APPDATA.keyboard_mode]
mov [keyboard_mode], al
in al, 0x60
;--------------------------------------
send_scancode:
mov [keyboard_data], al
; ch = scancode
; cl = ext_code
; bh = 0 - normal key
; bh = 1 - modifier (Shift/Ctrl/Alt)
; bh = 2 - extended code
mov ch, al
cmp al, 0xE0
je @f
cmp al, 0xE1
jne .normal_code
@@:
mov bh, 2
mov [ext_code], al
jmp .writekey
;--------------------------------------
.normal_code:
mov cl, 0
xchg cl, [ext_code]
and al, 0x7F
mov bh, 1
;--------------------------------------
@@:
cmp al, 0x5B
jne @f
cmp cl, 0xE0
jne @f
mov eax, VKEY_LWIN
mov bh, 0
jmp .modifier
;--------------------------------------
@@:
cmp al, 0x5C
jne @f
cmp cl, 0xE0
jne @f
mov eax, VKEY_RWIN
mov bh, 0
jmp .modifier
;--------------------------------------
@@:
cmp al, 0x2A
jne @f
cmp cl, 0xE0
je .writekey
mov eax, VKEY_LSHIFT
jmp .modifier
;--------------------------------------
@@:
cmp al, 0x36
jne @f
cmp cl, 0xE0
je .writekey
mov eax, VKEY_RSHIFT
jmp .modifier
;--------------------------------------
@@:
cmp al, 0x38
jne @f
mov eax, VKEY_LALT
test cl, cl
jz .modifier
mov al, VKEY_RALT
jmp .modifier
;--------------------------------------
@@:
cmp al, 0x1D
jne @f
mov eax, VKEY_LCONTROL
test cl, cl
jz .modifier
mov al, VKEY_RCONTROL
cmp cl, 0xE0
jz .modifier
mov [ext_code], cl
jmp .writekey
;--------------------------------------
@@:
cmp al, 0x3A
jne @f
mov bl, 4
mov eax, VKEY_CAPSLOCK
jmp .no_key.xor
;--------------------------------------
@@:
cmp al, 0x45
jne @f
test cl, cl
jnz .writekey
mov bl, 2
mov eax, VKEY_NUMLOCK
jmp .no_key.xor
;--------------------------------------
@@:
cmp al, 0x46
jne @f
mov bl, 1
mov eax, VKEY_SCRLOCK
jmp .no_key.xor
;--------------------------------------
@@:
xor ebx, ebx
test ch, ch
js .writekey
movzx eax, ch ; plain key
mov bl, [keymap+eax]
mov edx, [kb_state]
test dl, VKEY_CONTROL ; ctrl alt del
jz .noctrlaltdel
test dl, VKEY_ALT
jz .noctrlaltdel
cmp ch, 53h
jne .noctrlaltdel
mov [ctrl_alt_del], 1
call wakeup_osloop
.noctrlaltdel:
test dl, VKEY_CONTROL ; ctrl on ?
jz @f
sub bl, 0x60
@@:
test dl, VKEY_CAPSLOCK ; caps lock on ?
jz .no_caps_lock
test dl, VKEY_SHIFT ; shift on ?
jz .keymap_shif
jmp @f
;--------------------------------------
.no_caps_lock:
test dl, VKEY_SHIFT ; shift on ?
jz @f
.keymap_shif:
mov bl, [keymap_shift+eax]
@@:
test dl, VKEY_ALT ; alt on ?
jz @f
mov bl, [keymap_alt+eax]
@@:
jmp .writekey
;--------------------------------------
.modifier:
test ch, ch
js .modifier.up
or [kb_state], eax
jmp .writekey
;--------------------------------------
.modifier.up:
not eax
and [kb_state], eax
jmp .writekey
;--------------------------------------
.no_key.xor:
mov bh, 0
test ch, ch
js .writekey
xor [kb_state], eax
xor [kb_lights], bl
.writekey:
pushad
; test for system hotkeys
movzx eax, ch
cmp bh, 1
ja .nohotkey
jb @f
xor eax, eax
@@:
mov eax, [hotkey_scancodes + eax*4]
.hotkey_loop:
test eax, eax
jz .nohotkey
mov cl, 0
call hotkey_do_test
jc .hotkey_cont
mov cl, 2
call hotkey_do_test
jc .hotkey_cont
mov cl, 4
call hotkey_do_test
jnc .hotkey_found
.hotkey_cont:
mov eax, [eax]
jmp .hotkey_loop
;--------------------------------------
.hotkey_found:
mov eax, [eax+8]
; put key in buffer for process in slot eax
mov edi, hotkey_buffer
@@:
cmp dword [edi], 0
jz .found_free
add edi, 8
cmp edi, hotkey_buffer+120*8
jb @b
; no free space - replace first entry
mov edi, hotkey_buffer
.found_free:
mov [edi], eax
movzx eax, ch
cmp bh, 1
jnz @f
xor eax, eax
@@:
mov [edi+4], ax
mov eax, [kb_state]
mov [edi+6], ax
 
cmp [PID_lock_input], dword 0
je .nohotkey
 
popad
jmp .exit.irq1
;--------------------------------------
.nohotkey:
popad
 
cmp [keyboard_mode], 0; return from keymap
jne .scancode
test bh, bh
jnz .exit.irq1
test bl, bl
jz .exit.irq1
 
cmp cl, 0xE0 ; extended keycode
jne @f
 
cmp ch, 53
jne .dowrite
mov bl, '/'
jmp .dowrite
@@:
 
cmp ch, 55
jne @f
mov bl, '*'
jmp .dowrite
@@:
 
cmp ch, 74
jne @f
mov bl, '-'
jmp .dowrite
@@:
 
cmp ch, 78
jne @f
mov bl, '+'
jmp .dowrite
@@:
 
test [kb_state], VKEY_NUMLOCK
jz .dowrite
 
cmp ch, 71
jb .dowrite
cmp ch, 83
ja .dowrite
movzx eax, ch
mov bl, [numlock_map + eax - 71]
jmp .dowrite
;--------------------------------------
.scancode:
mov bl, ch
.dowrite:
movzx eax, byte[KEY_COUNT]
cmp al, 120
jae .exit.irq1
inc eax
mov [KEY_COUNT], al
; store ascii or scancode
mov [KEY_BUFF+eax-1], bl
; store original scancode
add eax, 120+2
push ecx
cmp [keyboard_mode], 0; return from keymap
je @f
 
xor ch, ch
@@:
mov [KEY_BUFF+eax-1], ch
pop ecx
sub eax, 120+2
.exit.irq1:
ret
;---------------------------------------------------------------------
set_lights:
push ebx esi
mov ecx, keyboard_list_mutex
call mutex_lock
mov esi, keyboards
.loop:
mov esi, [esi+KEYBOARD.next]
cmp esi, keyboards
jz .done
mov eax, [esi+KEYBOARD.functions]
cmp dword [eax], KBDFUNC.setlights
jbe .loop
mov eax, [eax+KBDFUNC.setlights]
test eax, eax
jz .loop
stdcall eax, [esi+KEYBOARD.userdata], dword [kb_lights]
jmp .loop
.done:
mov ecx, keyboard_list_mutex
call mutex_unlock
pop esi ebx
ret
 
ps2_set_lights:
stdcall disable_irq, 1
mov al, 0xED
call kb_write_wait_ack
mov al, [esp+8]
call kb_write_wait_ack
stdcall enable_irq, 1
ret 8
 
;// mike.dld ]
proc check_lights_state_has_work?
mov al, [kb_lights]
cmp al, [old_kb_lights]
ret
endp
 
check_lights_state:
call check_lights_state_has_work?
jz .nothing
mov [old_kb_lights], al
call set_lights
.nothing:
ret
;---------------------------------------------------------------------
iglobal
numlock_map db '789-456+1230.'
endg
;---------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/hid/mousedrv.inc
0,0 → 1,567
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
; check mouse
;
;
; FB00 -> FB0F mouse memory 00 chunk count - FB0A-B x - FB0C-D y
; FB10 -> FB17 mouse color mem
; FB21 x move
; FB22 y move
; FB30 color temp
; FB28 high bits temp
; FB4A -> FB4D FB4A-B x-under - FB4C-D y-under
; FC00 -> FCFE com1/ps2 buffer
; FCFF com1/ps2 buffer count starting from FC00
 
uglobal
;--------------------------------------
align 4
mousecount dd ?
mousedata dd ?
Y_UNDER_sub_CUR_hot_y_add_curh dw ?
Y_UNDER_subtraction_CUR_hot_y dw ?
X_UNDER_sub_CUR_hot_x_add_curh dw ?
X_UNDER_subtraction_CUR_hot_x dw ?
endg
 
iglobal
;--------------------------------------
align 4
mouse_speed_factor dw 4
mouse_delay db 3
mouse_doubleclick_delay db 64
endg
 
;-----------------------------------------------------------------------------
 
align 4
draw_mouse_under:
 
; return old picture
cmp [_display.restore_cursor], 0
je @F
 
pushad
movzx eax, word [X_UNDER]
movzx ebx, word [Y_UNDER]
stdcall [_display.restore_cursor], eax, ebx
popad
ret
 
@@:
pushad
xor ecx, ecx
xor edx, edx
 
mres:
movzx eax, word [X_UNDER]
movzx ebx, word [Y_UNDER]
add eax, ecx
add ebx, edx
push ecx
push edx
push eax
push ebx
mov eax, edx
shl eax, 6
shl ecx, 2
add eax, ecx
add eax, mouseunder
mov ecx, [eax]
pop ebx
pop eax
mov edi, 1 ; force
or ecx, 0x04000000 ; don't save to mouseunder area
; call [putpixel]
call __sys_putpixel
pop edx
pop ecx
inc ecx
cmp ecx, 16
jnz mres
xor ecx, ecx
inc edx
cmp edx, 24
jnz mres
popad
ret
 
;-----------------------------------------------------------------------------
 
align 4
save_draw_mouse:
cmp [_display.move_cursor], 0
je .no_hw_cursor
pushad
 
mov [X_UNDER], ax
mov [Y_UNDER], bx
movzx eax, word [MOUSE_Y]
movzx ebx, word [MOUSE_X]
push eax
push ebx
 
; mov ecx, [Screen_Max_X]
; inc ecx
; mul ecx
mov eax, [d_width_calc_area + eax*4]
 
add eax, [_display.win_map]
movzx edx, byte [ebx+eax]
shl edx, 8
mov esi, [edx+SLOT_BASE+APPDATA.cursor]
 
cmp esi, [current_cursor]
je .draw
 
mov eax, [thread_count]
movzx eax, word [WIN_POS+eax*2]
shl eax, 8
 
cmp eax, edx
je @F
 
mov esi, [def_cursor]
cmp esi, [current_cursor]
je .draw
 
@@:
push esi
call [_display.select_cursor]
mov [current_cursor], esi
;--------------------------------------
align 4
.draw:
stdcall [_display.move_cursor], esi
popad
ret
;--------------------------------------
;align 4
;.fail:
; mov ecx, [def_cursor]
; mov [edx+SLOT_BASE+APPDATA.cursor], ecx
; stdcall [_display.move_cursor], ecx ; stdcall: [esp]=ebx,eax
; popad
; ret
;--------------------------------------
align 4
.no_hw_cursor:
pushad
; save & draw
mov [X_UNDER], ax
mov [Y_UNDER], bx
push eax
push ebx
mov ecx, 0
mov edx, 0
;--------------------------------------
align 4
drm:
push eax
push ebx
push ecx
push edx
; helloworld
push ecx
add eax, ecx ; save picture under mouse
add ebx, edx
push ecx
or ecx, 0x04000000 ; don't load to mouseunder area
push eax ebx edx edi
call [GETPIXEL]
pop edi edx ebx eax
mov [COLOR_TEMP], ecx
pop ecx
mov eax, edx
shl eax, 6
shl ecx, 2
add eax, ecx
add eax, mouseunder
mov ebx, [COLOR_TEMP]
and ebx, 0xffffff
mov [eax], ebx
pop ecx
mov edi, edx ; y cycle
shl edi, 4 ; *16 bytes per row
add edi, ecx ; x cycle
mov esi, edi
add edi, esi
add edi, esi ; *3
add edi, [MOUSE_PICTURE] ; we have our str address
mov esi, edi
add esi, 16*24*3
push ecx
mov ecx, [COLOR_TEMP]
call combine_colors
and ecx, 0xffffff
mov [MOUSE_COLOR_MEM], ecx
pop ecx
pop edx
pop ecx
pop ebx
pop eax
add eax, ecx ; we have x coord+cycle
add ebx, edx ; and y coord+cycle
push ecx
mov ecx, [MOUSE_COLOR_MEM]
mov edi, 1 ; force
or ecx, 0x04000000 ; don't save to mouseunder area
; call [putpixel]
call __sys_putpixel
pop ecx
mov ebx, [esp+0] ; pure y coord again
mov eax, [esp+4] ; and x
inc ecx ; +1 cycle
cmp ecx, 16 ; if more than 16
jnz drm
xor ecx, ecx
inc edx
cmp edx, 24
jnz drm
add esp, 8
popad
ret
 
;-----------------------------------------------------------------------------
 
align 4
combine_colors:
; in
; ecx - color ( 00 RR GG BB )
; edi - ref to new color byte
; esi - ref to alpha byte
;
; out
; ecx - new color ( roughly (ecx*[esi]>>8)+([edi]*[esi]>>8) )
push eax
push ebx
push edx
push ecx
xor ecx, ecx
; byte 0
mov eax, 0xff
sub al, [esi+0]
mov ebx, [esp]
shr ebx, 16
and ebx, 0xff
mul ebx
shr eax, 8
add ecx, eax
xor eax, eax
xor ebx, ebx
mov al, [edi+0]
mov bl, [esi+0]
mul ebx
shr eax, 8
add ecx, eax
shl ecx, 8
; byte 1
mov eax, 0xff
sub al, [esi+1]
mov ebx, [esp]
shr ebx, 8
and ebx, 0xff
mul ebx
shr eax, 8
add ecx, eax
xor eax, eax
xor ebx, ebx
mov al, [edi+1]
mov bl, [esi+1]
mul ebx
shr eax, 8
add ecx, eax
shl ecx, 8
; byte 2
mov eax, 0xff
sub al, [esi+2]
mov ebx, [esp]
and ebx, 0xff
mul ebx
shr eax, 8
add ecx, eax
xor eax, eax
xor ebx, ebx
mov al, [edi+2]
mov bl, [esi+2]
mul ebx
shr eax, 8
add ecx, eax
pop eax
pop edx
pop ebx
pop eax
ret
 
;-----------------------------------------------------------------------------
 
align 4
check_mouse_area_for_getpixel:
; in:
; eax = x
; ebx = y
; out:
; ecx = new color
push eax ebx
; check for Y
xor ecx, ecx
mov cx, [Y_UNDER] ; [MOUSE_Y]
 
cmp ebx, ecx
jb .no_mouse_area
add ecx, 23 ; mouse cursor Y size
cmp ebx, ecx
ja .no_mouse_area
; offset Y
sub bx, [Y_UNDER] ; [MOUSE_Y]
;--------------------------------------
; check for X
xor ecx, ecx
mov cx, [X_UNDER] ; [MOUSE_X]
cmp eax, ecx
jb .no_mouse_area
add ecx, 15 ; mouse cursor X size
cmp eax, ecx
ja .no_mouse_area
; offset X
sub ax, [X_UNDER] ; [MOUSE_X]
;--------------------------------------
; eax = offset x
; ebx = offset y
shl ebx, 6 ;y
shl eax, 2 ;x
add eax, ebx
add eax, mouseunder
mov ecx, [eax]
and ecx, 0xffffff
or ecx, 0xff000000
pop ebx eax
ret
 
.no_mouse_area:
xor ecx, ecx
pop ebx eax
ret
 
;-----------------------------------------------------------------------------
 
align 4
check_mouse_area_for_putpixel:
; in:
; ecx = x shl 16 + y
; eax = color
; out:
; eax = new color
push eax
; check for Y
mov ax, [Y_UNDER] ; [MOUSE_Y]
cmp cx, ax
jb .no_mouse_area
add ax, 23 ; mouse cursor Y size
cmp cx, ax
ja .no_mouse_area
; offset Y
sub cx, [Y_UNDER] ; [MOUSE_Y]
mov ax, cx
shl eax, 16
 
; check for X
mov ax, [X_UNDER] ; [MOUSE_X]
shr ecx, 16
cmp cx, ax
jb .no_mouse_area
add ax, 15 ; mouse cursor X size
cmp cx, ax
ja .no_mouse_area
; offset X
sub cx, [X_UNDER] ; [MOUSE_X]
mov ax, cx
 
; eax = (offset y) shl 16 + (offset x)
 
pop ecx
 
push eax ebx
 
mov ebx, eax
shr ebx, 16 ; y
and eax, 0xffff ; x
 
shl ebx, 6
shl eax, 2
add eax, ebx
add eax, mouseunder
and ecx, 0xFFFFFF
mov [eax], ecx
 
pop ebx eax
 
push esi edi
rol eax, 16
movzx edi, ax ; y cycle
shl edi, 4 ; *16 bytes per row
shr eax, 16
add edi, eax ; x cycle
lea edi, [edi*3]
add edi, [MOUSE_PICTURE] ; we have our str address
mov esi, edi
add esi, 16*24*3
call combine_colors
pop edi esi
mov eax, ecx
ret
 
.no_mouse_area:
pop eax
ret
 
;-----------------------------------------------------------------------------
 
align 4
__sys_draw_pointer:
pushad
movzx ecx, word [X_UNDER]
movzx edx, word [Y_UNDER]
movzx ebx, word [MOUSE_Y]
movzx eax, word [MOUSE_X]
cmp [redrawmouse_unconditional], 0
je @f
mov [redrawmouse_unconditional], 0
jmp redrawmouse
@@:
cmp eax, ecx
jne redrawmouse
cmp ebx, edx
je nodmp
 
;--------------------------------------
 
align 4
redrawmouse:
pushfd
cli
call draw_mouse_under
call save_draw_mouse
 
; mov eax, [_display.select_cursor]
; test eax, eax
; jz @f
cmp [_display.select_cursor], select_cursor
jne @f
 
xor eax, eax
mov esi, [current_cursor]
 
mov ax, [Y_UNDER]
sub eax, [esi+CURSOR.hot_y]
mov [Y_UNDER_subtraction_CUR_hot_y], ax
add eax, [cur.h]
mov [Y_UNDER_sub_CUR_hot_y_add_curh], ax
 
mov ax, [X_UNDER]
sub eax, [esi+CURSOR.hot_x]
mov [X_UNDER_subtraction_CUR_hot_x], ax
add eax, [cur.w]
mov [X_UNDER_sub_CUR_hot_x_add_curh], ax
@@:
popfd
nodmp:
popad
ret
 
;-----------------------------------------------------------------------------
 
align 4
proc set_mouse_data stdcall uses ecx edx, BtnState:dword, XMoving:dword, YMoving:dword, VScroll:dword, HScroll:dword
 
mov eax, [BtnState]
and eax, 0x3FFFFFFF ; Top 2 bits are used to flag absolute movements
mov [BTN_DOWN], eax
;--------------------------------------
mov eax, [XMoving]
test [BtnState], 0x80000000
jnz .absolute_x
test eax, eax
jz @f
call mouse_acceleration
add ax, [MOUSE_X]
jns .check_x
xor eax, eax
jmp .set_x
.absolute_x:
mov edx, [_display.width]
mul edx
shr eax, 15
.check_x:
cmp ax, word[_display.width]
jl .set_x
mov ax, word[_display.width]
dec ax
.set_x:
mov [MOUSE_X], ax
;--------------------------------------
@@:
mov eax, [YMoving]
test [BtnState], 0x40000000
jnz .absolute_y
test eax, eax
jz @f
neg eax
call mouse_acceleration
add ax, [MOUSE_Y]
jns .check_y
xor eax, eax
jmp .set_y
.absolute_y:
mov edx, [_display.height]
mul edx
shr eax, 15
.check_y:
cmp ax, word[_display.height]
jl .set_y
mov ax, word[_display.height]
dec ax
.set_y:
mov [MOUSE_Y], ax
;--------------------------------------
@@:
mov eax, [VScroll]
test eax, eax
jz @f
add [MOUSE_SCROLL_V], ax
bts word [BTN_DOWN], 15
@@:
mov eax, [HScroll]
test eax, eax
jz @f
add [MOUSE_SCROLL_H], ax
bts dword [BTN_DOWN], 23
@@:
mov [mouse_active], 1
call wakeup_osloop
ret
endp
 
;-----------------------------------------------------------------------------
mouse_acceleration:
neg ax
jl mouse_acceleration
add al, [mouse_delay]
mul al
mov cx, [mouse_speed_factor]
dec ax
shr ax, cl
inc ax
test eax, eax
jns @f
neg ax
@@:
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/hid/set_dtc.inc
0,0 → 1,203
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
;setting date,time,clock and alarm-clock
;add sys_settime at servetable as for ex. 22 fcn:
; 22 - SETTING DATE TIME, CLOCK AND ALARM-CLOCK
; ebx =0 - set time ecx - 00SSMMHH
; ebx =1 - set date ecx=00DDMMYY
; ebx =2 - set day of week ecx- 1-7
; ebx =3 - set alarm-clock ecx - 00SSMMHH
; out: 0 -Ok 1 -wrong format 2 -battery low
sys_settime:
cli
mov al, 0x0d
out 0x70, al
in al, 0x71
bt ax, 7
jnc bat_low
cmp ebx, 2;day of week
jne nosetweek
test ecx, ecx ;test day of week
je wrongtime
cmp ecx, 7
ja wrongtime
mov edx, 0x70
call startstopclk
dec edx
mov al, 6
out dx, al
inc edx
mov al, cl
out dx, al
jmp endsettime
nosetweek: ;set date
cmp ebx, 1
jne nosetdate
cmp cl, 0x99;test year
ja wrongtime
shl ecx, 4
cmp cl, 0x90
ja wrongtime
cmp ch, 0x99;test month
ja wrongtime
shr ecx, 4
test ch, ch
je wrongtime
cmp ch, 0x12
ja wrongtime
shl ecx, 8
bswap ecx ;ebx=00YYMMDD
test cl, cl ;test day
je wrongtime
shl ecx, 4
cmp cl, 0x90
ja wrongtime
shr ecx, 4
cmp ch, 2 ;February
jne testday
cmp cl, 0x29
ja wrongtime
jmp setdate
testday:
cmp ch, 8
jb testday1;Aug-Dec
bt cx, 8
jnc days31
jmp days30
testday1:
bt cx, 8 ;Jan-Jul ex.Feb
jnc days30
days31:
cmp cl, 0x31
ja wrongtime
jmp setdate
days30:
cmp cl, 0x30
ja wrongtime
setdate:
mov edx, 0x70
call startstopclk
dec edx
mov al, 7 ;set days
out dx, al
inc edx
mov al, cl
out dx, al
dec edx
mov al, 8 ;set months
out dx, al
inc edx
mov al, ch
out dx, al
dec edx
mov al, 9 ;set years
out dx, al
inc edx
shr ecx, 8
mov al, ch
out dx, al
jmp endsettime
nosetdate: ;set time or alarm-clock
cmp ebx, 3
ja wrongtime
cmp cl, 0x23
ja wrongtime
cmp ch, 0x59
ja wrongtime
shl ecx, 4
cmp cl, 0x90
ja wrongtime
cmp ch, 0x92
ja wrongtime
shl ecx, 4
bswap ecx ;00HHMMSS
cmp cl, 0x59
ja wrongtime
shl ecx, 4
cmp cl, 0x90
ja wrongtime
shr ecx, 4
 
mov edx, 0x70
call startstopclk
dec edx
cmp ebx, 3
je setalarm
xor eax, eax;al=0-set seconds
out dx, al
inc edx
mov al, cl
out dx, al
dec edx
mov al, 2 ;set minutes
out dx, al
inc edx
mov al, ch
out dx, al
dec edx
mov al, 4 ;set hours
out dx, al
inc edx
shr ecx, 8
mov al, ch
out dx, al
jmp endsettime
setalarm:
mov al, 1;set seconds for al.
out dx, al
inc edx
mov al, cl
out dx, al
dec edx
mov al, 3;set minutes for al.
out dx, al
inc edx
mov al, ch
out dx, al
dec edx
mov al, 5;set hours for al.
out dx, al
inc edx
shr ecx, 8
mov al, ch
out dx, al
dec edx
mov al, 0x0b;enable irq's
out dx, al
inc dx
in al, dx
bts ax, 5;set bit 5
out dx, al
endsettime:
dec edx
call startstopclk
sti
and [esp+36-4], dword 0
ret
bat_low:
sti
mov [esp+36-4], dword 2
ret
wrongtime:
sti
mov [esp+36-4], dword 1
ret
 
startstopclk:
mov al, 0x0b
out dx, al
inc dx
in al, dx
btc ax, 7
out dx, al
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/hid
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/posix/futex.inc
0,0 → 1,245
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
align 4
;struct futex* __fastcall create_futex(int *ptr)
create_futex:
push ecx
mov ecx, sizeof.FUTEX
call create_object
pop ecx
test eax, eax
jz .fail
 
mov [eax+FUTEX.magic], 'FUTX'
mov [eax+FUTEX.destroy], 0
mov [eax+FUTEX.pointer], ecx
lea ecx, [eax+FUTEX.wait_list]
list_init ecx
mov [eax+FUTEX.flags], 0
.fail:
ret
 
align 4
;int __fastcall destroy_futex(struct futex *futex)
destroy_futex:
push esi
mov esi, [current_process]
mov edx, [ecx+FUTEX.handle]
 
pushfd
cli
 
lea eax, [ecx+FUTEX.wait_list]
cmp eax, [eax+LHEAD.next]
jne .fail
 
mov eax, [esi+PROC.ht_next]
mov [esi+PROC.htab+edx*4], eax
mov [esi+PROC.ht_next], edx
inc [esi+PROC.ht_free]
 
popfd
pop esi
 
mov eax, ecx
call free
xor eax, eax
ret
 
.fail:
popfd
pop esi
mov eax, -1
ret
 
align 4
sys_futex:
cmp ecx, STDERR_FILENO
jbe .fail
cmp ecx, (PROC.pdt_0 - PROC.htab)/4
jae .fail
 
mov edi, [current_process]
mov ebp, [edi+PROC.htab+ecx*4]
 
cmp [ebp+FUTEX.magic], 'FUTX'
jne .fail
cmp [ebp+FUTEX.handle], ecx
jne .fail
 
jmp dword [sys_futex_call+ebx*4-4]
 
.fail:
.requeue:
.cmp_requeue:
.wait_bitset:
.wake_bitset:
mov [esp+SYSCALL_STACK._eax], -1
ret
 
align 4
.init:
call create_futex
test eax, eax
jz @F
mov eax, [eax+FUTEX.handle]
@@:
mov [esp+SYSCALL_STACK._eax], eax
ret
 
align 4
;ecx futex handle
;edi current process
;ebp futex object
.destroy:
mov ecx, ebp
call destroy_futex
mov [esp+SYSCALL_STACK._eax], eax
ret
 
align 4
;ecx futex handle
;edx control value
;esi timeout
;edi current process
;ebp futex object
.wait:
test esi, esi
jnz .wait_timeout
mov ecx, [ebp+FUTEX.pointer]
mov eax, edx
lock cmpxchg [ecx], edx
je .wait_slow
 
mov [esp+SYSCALL_STACK._eax], -2
ret
 
.wait_slow:
pushfd
cli
 
sub esp, sizeof.MUTEX_WAITER
mov ebx, [TASK_BASE]
mov [esp+MUTEX_WAITER.task], ebx
lea esi, [ebp+FUTEX.wait_list]
 
list_add_tail esp, esi ;esp= new waiter, esi= list head
mov eax, edx
.again:
mov [ebx+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task
 
lock cmpxchg [ecx], edx
je .again
 
list_del esp
add esp, sizeof.MUTEX_WAITER
 
popfd
mov [esp+SYSCALL_STACK._eax], 0
ret
 
align 4
;ecx futex handle
;edx control value
;esi timeout
;edi current process
;ebp futex object
 
.wait_timeout:
mov ecx, [ebp+FUTEX.pointer]
mov eax, edx
lock cmpxchg [ecx], edx ;wait until old_value == new_value
je .wait_slow_timeout
 
mov [esp+SYSCALL_STACK._eax], -2
ret
 
align 4
.wait_test:
xor eax, eax
ret
 
.wait_slow_timeout:
pushfd
cli
 
sub esp, sizeof.MUTEX_WAITER
 
mov ebx, [current_slot]
mov [ebx+APPDATA.wait_test], sys_futex.wait_test
mov [ebx+APPDATA.wait_timeout], esi
mov [ebx+APPDATA.wait_param], ebp
mov eax, [timer_ticks]
mov [ebx+APPDATA.wait_begin], eax
mov eax, [TASK_BASE]
mov [eax+TASKDATA.state], TSTATE_WAITING
 
mov [esp+MUTEX_WAITER.task], eax
lea esi, [ebp+FUTEX.wait_list]
 
list_add_tail esp, esi ;esp= new waiter, esi= list head
 
.again_timeout:
call change_task
mov eax, [ebx+APPDATA.wait_param]
test eax, eax
jz .timeout
 
mov eax, edx
lock cmpxchg [ecx], edx
jz .again_timeout
@@:
list_del esp
add esp, sizeof.MUTEX_WAITER
 
popfd
mov [esp+SYSCALL_STACK._eax], 0
ret
 
.timeout:
list_del esp
add esp, sizeof.MUTEX_WAITER
 
popfd
mov [esp+SYSCALL_STACK._eax], -1
ret
 
 
align 4
;ecx futex handle
;edx number of threads
;edi current process
;ebp futex object
.wake:
 
xor ecx, ecx
 
pushfd
cli
 
lea ebx, [ebp+FUTEX.wait_list]
mov esi, [ebx+LHEAD.next]
.again_wake:
cmp esi, ebx
je .done
 
mov eax, [esi+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], TSTATE_RUNNING
 
mov esi, [esi+MUTEX_WAITER.list.next]
inc ecx
cmp ecx, edx
jb .again_wake
.done:
popfd
mov [esp+SYSCALL_STACK._eax], ecx
ret
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/posix/pipe.inc
0,0 → 1,339
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
F_READ = 0x0001 ; file opened for reading
F_WRITE = 0x0002 ; file opened for writing
 
O_CLOEXEC = 0x40000
PIPE_BUFFER_SIZE = 4096
 
 
iglobal
align 4
pipe_file_ops:
dd pipe_close ;0
dd pipe_read ;1
dd pipe_write ;2
endg
 
;int pipe2(int pipefd[2], int flags);
;ecx pipefd
;edx flags
 
align 4
sys_pipe2:
.pipeflags equ esp+16
.pipefd equ esp+12
.fdread equ esp+8
.fdwrite equ esp+4
.intpipe equ esp
 
push ebp
test ecx, ecx
mov ebp, -EFAULT
js .fail
 
test edx, not O_CLOEXEC
mov ebp, -EINVAL
jnz .fail
 
push edx
push ecx
sub esp, (5-2)*4
 
mov ecx, sizeof.FILED
call create_object
mov [.fdread], eax
test eax, eax
mov ebp, -EMFILE
jz .err_0
 
mov ecx, sizeof.FILED
call create_object
mov [.fdwrite], eax
test eax, eax
jz .err_1
 
mov eax, sizeof.PIPE
call malloc
test eax, eax
mov ebp, -ENFILE
jz .err_2
 
mov ebp, eax
 
stdcall create_ring_buffer, PIPE_BUFFER_SIZE, PG_SWR
test eax, eax
jz .err_3
 
mov [ebp+PIPE.pipe_ops], pipe_file_ops
mov [ebp+PIPE.buffer], eax
 
xor eax, eax
mov [ebp+PIPE.count], eax
mov [ebp+PIPE.read_end], eax
mov [ebp+PIPE.write_end], eax
 
inc eax
mov [ebp+PIPE.readers], eax
mov [ebp+PIPE.writers], eax
 
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_init
 
lea ecx, [ebp+PIPE.rlist]
list_init ecx
 
lea ecx, [ebp+PIPE.wlist]
list_init ecx
 
mov eax, [.fdread]
mov edx, [.fdwrite]
mov ecx, [.pipefd]
 
mov [eax+FILED.magic], 'PIPE'
mov [eax+FILED.destroy], 0
mov [eax+FILED.mode], F_READ
mov [eax+FILED.file], ebp
 
mov [edx+FILED.magic], 'PIPE'
mov [edx+FILED.destroy], 0
mov [edx+FILED.mode], F_WRITE
mov [edx+FILED.file], ebp
 
mov eax, [eax+FILED.handle]
mov edx, [edx+FILED.handle]
 
mov [ecx], eax
mov [ecx+4], edx
add esp, 5*4
pop ebp
xor eax, eax
mov [esp+SYSCALL_STACK._eax], eax
ret
.err_3:
mov eax, ebp
call free
mov ebp, -ENFILE
.err_2:
mov ecx, [.fdwrite]
call destroy_object
.err_1:
mov ecx, [.fdread]
call destroy_object
.err_0:
add esp, 5*4
.fail:
mov eax, ebp
pop ebp
mov [esp+SYSCALL_STACK._eax], eax
ret
 
purge .pipeflags
purge .filefd
purge .fdread
purge .fdwrite
purge .intpipe
 
 
; edx dst_buf
; esi read count
; ebp pipe
 
align 4
pipe_read:
 
mov edi, edx
 
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_lock
.again:
xor eax, eax
cmp eax, [ebp+PIPE.writers]
je .eof
 
mov ecx, [ebp+PIPE.count]
test ecx, ecx
jz .wait
 
.check_count:
cmp ecx, esi
jb .read
mov ecx, esi
.read:
mov esi, [ebp+PIPE.buffer]
add esi, [ebp+PIPE.read_end]
mov [esp+SYSCALL_STACK._eax], ecx
sub [ebp+PIPE.count], ecx
cld
rep movsb
and esi, 0xFFF
mov [ebp+PIPE.read_end], esi
 
lea ecx, [ebp+PIPE.wlist]
cmp ecx, [ebp+PIPE.wlist.next]
je @F
 
mov ecx, [ecx+MUTEX_WAITER.task]
mov [ecx+TASKDATA.state], TSTATE_RUNNING ;activate writer task
@@:
cmp [ebp+PIPE.count], 0
je @F
 
lea eax, [ebp+PIPE.rlist]
cmp eax, [ebp+PIPE.rlist.next]
je @F
 
mov eax, [eax+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], TSTATE_RUNNING ;activate reader task
@@:
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
ret
 
.wait:
pushfd
cli
 
sub esp, sizeof.MUTEX_WAITER
mov ebx, [TASK_BASE]
mov [esp+MUTEX_WAITER.task], ebx
lea edx, [ebp+PIPE.rlist]
 
list_add_tail esp, edx ;esp= new waiter, edx= list head
 
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
 
mov [ebx+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task
 
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_lock
 
list_del esp
add esp, sizeof.MUTEX_WAITER
popfd
jmp .again
 
.eof:
mov [esp+SYSCALL_STACK._eax], eax
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
ret
 
; edx src_buf
; esi write count
; ebp pipe
 
align 4
pipe_write:
 
.written equ esp
 
push 0 ;written
mov ebx, esi ;ebx = write count
mov esi, edx ;esi = src
 
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_lock
.again:
xor eax, eax
cmp eax, [ebp+PIPE.readers]
je .epipe
 
mov ecx, 4096
sub ecx, [ebp+PIPE.count]
jz .wait ;wait if buffer full
 
.check_count:
cmp ecx, ebx
jb .write
mov ecx, ebx
.write:
mov edi, [ebp+PIPE.buffer]
add edi, [ebp+PIPE.write_end]
add [.written], ecx
sub ebx, ecx
add [ebp+PIPE.count], ecx
 
cld
rep movsb
and edi, 0xFFF
mov [ebp+PIPE.write_end], edi
 
pushfd
cli
 
lea eax, [ebp+PIPE.rlist]
cmp eax, [ebp+PIPE.rlist.next]
je @F
 
mov eax, [eax+MUTEX_WAITER.task]
mov [eax+TASKDATA.state], TSTATE_RUNNING ;activate reader task
@@:
cmp [ebp+PIPE.count], 4096
je @F
 
lea ecx, [ebp+PIPE.wlist]
cmp ecx, [ebp+PIPE.wlist.next]
je @F
 
mov ecx, [eax+MUTEX_WAITER.task]
mov [ecx+TASKDATA.state], TSTATE_RUNNING ;activate writer task
@@:
popfd
 
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
 
test ebx, ebx
jnz .again
 
pop eax ; written
mov [esp+SYSCALL_STACK._eax], eax
ret
 
.wait:
pushfd
cli
 
sub esp, sizeof.MUTEX_WAITER
mov ecx, [TASK_BASE]
mov [esp+MUTEX_WAITER.task], ecx
lea edx, [ebp+PIPE.wlist]
 
list_add_tail esp, edx ;esp= new waiter, edx= list head
 
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
 
mov [ecx+TASKDATA.state], TSTATE_RUN_SUSPENDED
call change_task
 
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_lock
 
list_del esp
add esp, sizeof.MUTEX_WAITER
popfd
jmp .again
 
.epipe:
lea ecx, [ebp+PIPE.pipe_lock]
call mutex_unlock
 
add esp, 4
mov [esp+SYSCALL_STACK._eax], -EPIPE
ret
 
align 4
pipe_close:
mov [esp+SYSCALL_STACK._eax], -EBADF
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/posix/posix.inc
0,0 → 1,129
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
ENOENT = 2
EBADF = 9
EFAULT = 14
;EINVAL = 22 11 defined in stack.inc
ENFILE = 23
EMFILE = 24
EPIPE = 32
 
FILEOP_CLOSE = 0
FILEOP_READ = 1
FILEOP_WRITE = 2
 
 
include "futex.inc"
 
iglobal
align 4
sys_futex_call:
dd sys_futex.destroy ;1
dd sys_futex.wait ;2
dd sys_futex.wake ;3
dd sys_futex.requeue ;4
dd sys_futex.cmp_requeue ;5
dd sys_futex.wait_bitset ;6
dd sys_futex.wake_bitset ;7
endg
 
include "pipe.inc"
 
iglobal
align 4
sys_posix_call:
dd sys_futex.init ;0 futex_init
dd sys_futex ;1 futex_destroy
dd sys_futex ;2 futex_wait
dd sys_futex ;3 futex_wake
dd sys_futex ;4 reserved
dd sys_futex ;5 reserved
dd sys_futex ;6 reserved
dd sys_futex ;7 reserved
dd sys_posix.fail ;8 sys_open
dd sys_posix.fail ;9 sys_close
dd sys_read ;10 read()
dd sys_write ;11 write()
dd sys_posix.fail ;12 sys_dup3
dd sys_pipe2 ;13
.end:
endg
 
align 4
sys_posix:
cmp ebx, (sys_posix_call.end-sys_posix_call)/4
jae .fail
 
jmp dword [sys_posix_call+ebx*4]
 
.fail:
mov [esp+SYSCALL_STACK._eax], -EBADF
ret
 
 
;ssize_t read(int fd, void *buf, size_t count);
; ecx fd
; edx buf
; esi count
 
align 4
sys_read:
cmp ecx, STDERR_FILENO
jbe .fail
cmp ecx, (PROC.pdt_0 - PROC.htab)/4
jae .fail
 
mov edi, [current_process]
mov ebp, [edi+PROC.htab+ecx*4]
 
cmp [ebp+FILED.magic], 'PIPE'
jne .fail
cmp [ebp+FILED.handle], ecx
jne .fail
 
test [ebp+FILED.mode], F_READ
jz .fail
 
mov ebp, [ebp+FILED.file]
mov eax, [ebp]
jmp dword [eax+FILEOP_READ*4]
.fail:
mov [esp+SYSCALL_STACK._eax], -EBADF
ret
 
;ssize_t write(int fd, const void *buf, size_t count);
; ecx fd
; edx buf
; esi count
 
align 4
sys_write:
cmp ecx, STDERR_FILENO
jbe .fail
cmp ecx, (PROC.pdt_0 - PROC.htab)/4
jae .fail
 
mov edi, [current_process]
mov ebp, [edi+PROC.htab+ecx*4]
 
cmp [ebp+FILED.magic], 'PIPE'
jne .fail
cmp [ebp+FILED.handle], ecx
jne .fail
test [ebp+FILED.mode], F_WRITE
jz .fail
 
mov ebp, [ebp+FILED.file]
mov eax, [ebp]
jmp dword [eax+FILEOP_WRITE*4]
.fail:
mov [esp+SYSCALL_STACK._eax], -EBADF
ret
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/data32.inc
0,0 → 1,559
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
keymap:
 
db '6',27
db '1234567890-=',8,9
db 'qwertyuiop[]',13
db '~asdfghjkl;',39,96,0,'\zxcvbnm,./',0,'45 '
db '@234567890123',180,178,184,'6',176,'7'
db 179,'8',181,177,183,185,182
db 'AB<D',255,'FGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
keymap_shift:
db '6',27
db '!@#$%^&*()_+',8,9
db 'QWERTYUIOP{}',13
db '~ASDFGHJKL:"~',0,'|ZXCVBNM<>?',0,'45 '
db '@234567890123',180,178,184,'6',176,'7'
db 179,'8',181,177,183,185,182
db 'AB>D',255,'FGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
 
keymap_alt:
db ' ',27
db ' @ $ {[]}\ ',8,9
db ' ',13
db ' ',0,' ',0,'4',0,' '
db ' ',180,178,184,'6',176,'7'
db 179,'8',181,177,183,185,182
db 'ABCD',255,'FGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
db 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
 
 
 
if lang eq ru
boot_initirq cp866 'Инициализация IRQ',0
boot_picinit cp866 'Инициализация PIC',0
boot_v86machine cp866 'Инициализация системной V86 машины',0
boot_inittimer cp866 'Инициализация системного таймера (IRQ0)',0
boot_initapic cp866 'Попытка инициализации APIC',0
boot_enableirq cp866 'Включить прерывания 2, 13',0
boot_disabling_ide cp866 'Запрещение прерываний в контроллере IDE',0
boot_enabling_ide cp866 'Разрешение прерываний в контроллере IDE',0
boot_set_int_IDE cp866 'Установка обработчиков прерываний IDE',0
boot_detectfloppy cp866 'Поиск floppy дисководов',0
boot_detecthdcd cp866 'Поиск жестких дисков и ATAPI приводов',0
boot_getcache cp866 'Получение памяти для кэша',0
boot_detectpart cp866 'Поиск разделов на дисковых устройствах',0
boot_init_sys cp866 'Инициализация системного каталога /sys',0
boot_loadlibs cp866 'Загрузка библиотек (.obj)',0
boot_memdetect cp866 'Количество оперативной памяти',' ',' Мб',0
boot_tss cp866 'Установка TSSs',0
boot_cpuid cp866 'Чтение CPUIDs',0
; boot_devices cp866 'Поиск устройств',0
boot_timer cp866 'Установка таймера',0
boot_initramdisk cp866 'Инициализация рамдиска',0
boot_irqs cp866 'Переопределение IRQ',0
boot_setmouse cp866 'Установка мыши',0
boot_windefs cp866 'Установка настроек окон по умолчанию',0
boot_bgr cp866 'Установка фона',0
boot_resirqports cp866 'Резервирование IRQ и портов',0
boot_setrports cp866 'Установка адресов IRQ',0
boot_setostask cp866 'Создание процесса ядра',0
boot_allirqs cp866 'Открытие всех IRQ',0
boot_tsc cp866 'Чтение TSC',0
boot_cpufreq cp866 'Частота процессора ',' ',' МГц',0
boot_pal_ega cp866 'Установка EGA/CGA 320x200 палитры',0
boot_pal_vga cp866 'Установка VGA 640x480 палитры',0
boot_failed cp866 'Загрузка первого приложения не удалась',0
boot_mtrr cp866 'Установка MTRR',0
 
boot_APIC_found cp866 'APIC включен', 0
boot_APIC_nfound cp866 'APIC не найден', 0
if preboot_blogesc
boot_tasking cp866 'Все готово для запуска, нажмитре ESC для старта',0
end if
else if lang eq sp
include 'data32sp.inc'
else if lang eq et
include 'data32et.inc'
else
boot_initirq db 'Initialize IRQ',0
boot_picinit db 'Initialize PIC',0
boot_v86machine db 'Initialize system V86 machine',0
boot_inittimer db 'Initialize system timer (IRQ0)',0
boot_initramdisk db 'Initialize ramdisk',0
boot_initapic db 'Try to initialize APIC',0
boot_enableirq db 'Enable interrupts 2, 13',0
boot_disabling_ide db 'Disable interrupts in IDE controller',0
boot_enabling_ide db 'Enable interrupts in IDE controller',0
boot_set_int_IDE db 'Set handler of interrupts for IDE',0
boot_detectfloppy db 'Search floppy drives',0
boot_detecthdcd db 'Search hard drives and ATAPI drives',0
boot_getcache db 'Get memory for cache',0
boot_detectpart db 'Search partitions on disk devices',0
boot_init_sys db 'Initialize system directory /sys',0
boot_loadlibs db 'Loading librares (.obj)',0
boot_memdetect db 'Determining amount of memory',0
boot_tss db 'Setting TSSs',0
boot_cpuid db 'Reading CPUIDs',0
; boot_devices db 'Detecting devices',0
boot_setmouse db 'Setting mouse',0
boot_windefs db 'Setting window defaults',0
boot_bgr db 'Calculating background',0
boot_resirqports db 'Reserving IRQs & ports',0
boot_setostask db 'Setting OS task',0
boot_allirqs db 'Unmasking IRQs',0
boot_tsc db 'Reading TSC',0
boot_cpufreq db 'CPU frequency is ',' ',' MHz',0
boot_pal_ega db 'Setting EGA/CGA 320x200 palette',0
boot_pal_vga db 'Setting VGA 640x480 palette',0
boot_failed db 'Failed to start first app',0
boot_mtrr db 'Setting MTRR',0
 
boot_APIC_found db 'APIC enabled', 0
boot_APIC_nfound db 'APIC not found', 0
if preboot_blogesc
boot_tasking db 'All set - press ESC to start',0
end if
end if
 
;new_process_loading db 'K : New Process - loading',13,10,0
;new_process_running db 'K : New Process - done',13,10,0
start_not_enough_memory db 'K : New Process - not enough memory',13,10,0
 
msg_unresolved db 'unresolved ',0
;msg_module db 'in module ',0
;if ~ lang eq sp
;msg_version db 'incompatible driver version',13,10,0
;msg_www db 'please visit www.kolibrios.org',13,10,0
;end if
msg_CR db 13,10,0
 
szPS2MDriver db '/sys/drivers/PS2MOUSE.SYS',0
;szCOM_MDriver db 'COM_MOUSE',0
szVidintel db '/sys/drivers/vidintel.sys',0
szUSB db 'USB',0
 
szEXPORTS db 'EXPORTS',0
sz_EXPORTS db '_EXPORTS',0
 
szIMPORTS db 'IMPORTS',0
 
read_firstapp db '/sys/'
firstapp db '/sys/LAUNCHER',0
notifyapp db '/sys/@notify',0
if lang eq ru
ud_user_message cp866 'Ошибка: неподдерживаемая инструкция процессора',0
mtrr_user_message cp866 '"Обнаружена проблема с конфигурацией MTRR.\nПроизводительность может быть пониженной" -dW',0
else if ~ lang eq sp
ud_user_message db 'Error: unsupported processor instruction',0
mtrr_user_message db '"There is a problem with MTRR configuration.\nPerformance can be low" -dW',0
end if
 
kernel_file_load:
; load kernel.mnt to _CLEAN_ZONE
dd 0 ; subfunction
dq 0 ; offset in file
dd 0x31000 ; number of bytes to read
dd _CLEAN_ZONE ; buffer for data
db '/sys/KERNEL.MNT',0
 
dev_data_path db '/RD/1/DRIVERS/DEVICES.DAT',0
; { Patch by Coldy, For DLL autoload
dll_lib_path db '/RD/1/LIB/DLL.OBJ',0
dll_error_msg db '"DLL.OBJ not found!\nTerminate application!" -dE',0
; } End patch by Coldy, For DLL autoload
align 4
 
shmem_list:
.bk dd shmem_list
.fd dd shmem_list
 
dll_list:
.bk dd dll_list
.fd dd dll_list
 
pcidev_list:
.bk dd pcidev_list
.fd dd pcidev_list
 
MAX_DEFAULT_DLL_ADDR = 0x80000000
MIN_DEFAULT_DLL_ADDR = 0x70000000
dll_cur_addr dd MIN_DEFAULT_DLL_ADDR
 
; supported videomodes
 
 
; mike.dld {
;db 0
;dd servetable-0x10000
;align 4
;draw_line dd __sys_draw_line
;draw_pointer dd __sys_draw_pointer
;//mike.dld, 2006-08-02 [
;;drawbar dd __sys_drawbar
;;drawbar dd __sys_drawbar.forced
;drawbar dd vesa20_drawbar
;//mike.dld, 2006-08-02 ]
;putpixel dd __sys_putpixel
; } mike.dld
 
 
align 4
keyboard dd 1
 
if lang eq en
SYSLANG = 1
else if lang eq fi
SYSLANG = 2
else if lang eq de
SYSLANG = 3
else if lang eq ru
SYSLANG = 4
else if lang eq fr
SYSLANG = 5
else if lang eq et
SYSLANG = 6
else if lang eq sp
SYSLANG = 7
else if lang eq it
SYSLANG = 8
else if lang eq ca
SYSLANG = 9
else
display 'unsupported language specified',13,10
end if
syslang dd SYSLANG
 
boot_y dd 10
 
pci_bios_entry dd 0
dw pci_code_sel
 
if __DEBUG__ eq 1
include_debug_strings
end if
 
IncludeIGlobals
 
align 16
gdts:
 
dw gdte-$-1
dd gdts
dw 0
 
; Attention! Do not change the order of the first four selectors. They are used in Fast System Call
; must be : os_code, os_data, app_code, app_data, ....
 
int_code_l:
os_code_l:
dw 0xffff
dw 0x0000
db 0x00
dw 11011111b *256 +10011010b
db 0x00
 
int_data_l:
os_data_l:
dw 0xffff
dw 0x0000
db 0x00
dw 11011111b *256 +10010010b
db 0x00
 
app_code_l:
dw 0xFFFF
dw 0
db 0
db cpl3
dw G32+D32+0xF;
 
app_data_l:
dw 0xFFFF
dw 0
db 0
db drw3
dw G32+D32+0xF;
 
; ------------- PCI BIOS ------------------
 
pci_code_32:
dw 0 ;lim 0-15
dw 0 ;base 0-15
db 0 ;base 16-23
db cpl0 ;type
db D32 ;lim 16-19+props
db 0 ;base 24-31
 
pci_data_32:
dw 0 ;lim 0-15
dw 0 ;base 0-15
db 0 ;base 16-23
db dpl0 ;type
db D32 ;lim 16-19+props
db 0 ;base 24-31
 
; --------------- APM ---------------------
apm_code_32:
dw 0x0f ; limit 64kb
db 0, 0, 0
dw 11010000b *256 +10011010b
db 0x00
apm_code_16:
dw 0x0f
db 0, 0, 0
dw 10010000b *256 +10011010b
db 0x00
apm_data_16:
dw 0x0f
db 0, 0, 0
dw 10010000b *256 +10010010b
db 0x00
; -----------------------------------------
 
graph_data_l:
 
dw 0x7ff
dw 0x0000
db 0x00
dw 11010000b *256 +11110010b
db 0x00
tss0_l:
dw sizeof.TSS-1
dw tss and 0xFFFF
db (tss shr 16) and 0xFF
db 10001001b
dw (tss shr 16) and 0xFF00
 
tls_data_l:
dw 0x0FFF
dw 0
db 0
db drw3
dw D32
 
gdte:
 
diff16 "end of .data segment",0,$
endofcode:
 
align 16
cur_saved_data:
rb 4096
align 64
fpu_data:
rb 0xa80 ; bochs avx512
fpu_data_size = $ - fpu_data
draw_data:
rb 32*256
BPSLine_calc_area rd MAX_SCREEN_HEIGHT
d_width_calc_area rd MAX_SCREEN_HEIGHT
mouseunder rd 16*24
 
mem_block_list rd 64*2
mem_used_list rd 64*2
mem_hash_cnt rd 64
 
thr_slot_map rd 8
 
_display display_t
bios_fb FRB
 
mst MEM_STATE
 
cpu_freq dq ?
 
heap_mutex MUTEX
heap_size dd ?
heap_free dd ?
heap_blocks dd ?
free_blocks dd ?
mem_block_mask rd 2
next_memblock dd ?
 
pte_valid_mask dd ?
page_start dd ?
page_end dd ?
sys_page_map dd ?
os_stack_seg dd ?
 
srv.fd dd ?
srv.bk dd ?
 
LFBAddress dd ?
 
PUTPIXEL dd ?
GETPIXEL dd ?
 
if VESA_1_2_VIDEO
BANK_SWITCH dd ? ; reserved for vesa 1.2
BANK_RW dd ?
end if
 
MOUSE_PICTURE dd ?
 
def_cursor dd ?
def_cursor_clock dd ?
current_cursor dd ?
hw_cursor dd ?
cur_saved_base dd ?
 
cur.lock dd ? ; 1 - lock update, 2- hide
cur.left dd ? ; cursor clip box
cur.top dd ?
cur.w dd ?
cur.h dd ?
 
ipc_tmp dd ?
ipc_pdir dd ?
ipc_ptab dd ?
 
proc_mem_map dd ?
proc_mem_pdir dd ?
proc_mem_tab dd ?
 
tmp_task_ptab dd ?
 
default_io_map dd ?
 
LFBSize dd ?
 
current_process dd ?
current_slot dd ? ; pointer to APPDATA of current thread
current_slot_idx dd ? ; index of current thread slot
thread_count dd ?
 
; device addresses
mididp dd ?
midisp dd ?
 
cdbase dd ?
cdid dd ?
 
hdbase dd ? ; for boot 0x1f0
hdid dd ?
hdpos dd ? ; for boot 0x1
cdpos dd ?
 
;CPUID information
cpu_vendor rd 3
cpu_sign dd ?
cpu_info dd ?
cpu_caps rd 4
 
xsave_area_size dd ?
xsave_eax dd ?
xsave_edx dd ?
 
pg_data PG_DATA
heap_test dd ?
 
skin_data dd ?
 
mouse_active dd ?
mouse_pause dd ?
 
BgrDrawMode dd ?
BgrDataWidth dd ?
BgrDataHeight dd ?
 
buttontype dd ?
windowtypechanged dd ?
 
debug_step_pointer dd ?
 
lba_read_enabled dd ? ; 0 = disabled , 1 = enabled
pci_access_enabled dd ? ; 0 = disabled , 1 = enabled
 
NumBiosDisks dd ?
BiosDisksData rb 200h ; struct BiosDiskData
BiosDiskCaches rb 80h*(cache_ide1-cache_ide0)
BiosDiskPartitions rd 80h
 
img_background dd ?
mem_BACKGROUND dd ?
static_background_data dd ?
 
hd1_status dd ? ; 0 - free : other - pid
application_table_owner dd ? ; 0 - free : other - pid
application_table_mutex MUTEX
 
redrawmouse_unconditional dd ?
 
MOUSE_SCROLL_H rw 1
MOUSE_X: rw 1
MOUSE_Y: rw 1
MOUSE_SCROLL_V rw 1
 
X_UNDER rw 1
Y_UNDER rw 1
COLOR_TEMP dd ?
MOUSE_COLOR_MEM dd ?
 
SCR_MODE rw 2
 
BTN_DOWN: rb 4
 
cpu_phys_addr_width db ? ; also known as MAXPHYADDR in Intel manuals
hdd_appl_data db ? ; 0 = system cache, 1 - application cache
cd_appl_data db ? ; 0 = system cache, 1 - application cache
 
timer_ticks_enable db ? ; for cd driver
 
REDRAW_BACKGROUND db ?
 
align 16
DRIVE_DATA: rb DRIVE_DATA_SIZE
 
IncludeUGlobals
 
uglobals_size = $ - endofcode
 
if ~ lang eq sp
diff16 "end of .bss",0,$
end if
 
; check if kernel fits memmap
assert $-OS_BASE+0x1000 < TMP_STACK_TOP
 
org (OS_BASE+0x0100000)
 
; Currently size of memory allocated for the ramdisk is fixed.
; This should be revisited when/if memory map would become more dynamic.
RAMDISK_CAPACITY = 2880 ; in sectors
 
RAMDISK:
rb RAMDISK_CAPACITY*512
 
_CLEAN_ZONE:
CLEAN_ZONE = _CLEAN_ZONE - OS_BASE
 
BgrAuxTable rb 32768
align 65536
SB16Buffer rb 65536
 
align 4096
BUTTON_INFO rb 64*1024
RESERVED_PORTS:
rb 64*1024
sys_pgmap:
rb 1024*1024/8
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video/blitter.inc
0,0 → 1,536
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2011-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
struct BLITTER_BLOCK
xmin dd ?
ymin dd ?
xmax dd ?
ymax dd ?
ends
 
 
struct BLITTER
dc RECT
sc RECT
dst_x dd ? ; 32
dst_y dd ? ; 36
src_x dd ? ; 40
src_y dd ? ; 44
w dd ? ; 48
h dd ? ; 52
 
bitmap dd ? ; 56
stride dd ? ; 60
ends
 
 
 
align 4
block_clip:
;esi= clip RECT ptr
;edi= RECT ptr
;return code:
;CF= 0 - draw, 1 - don't draw
 
push ebx
 
mov eax, [edi+RECT.left]
mov ebx, [edi+RECT.right]
mov ecx, [esi+RECT.left] ;clip.left
mov edx, [esi+RECT.right] ;clip.right
 
cmp eax, edx ;left >= clip.right
jge .fail
 
cmp ebx, ecx ;right < clip.left
jl .fail
 
cmp eax, ecx ;left >= clip.left
jge @F
 
mov [edi+RECT.left], ecx
@@:
cmp ebx, edx ;right <= clip.right
jle @f
 
mov [edi+RECT.right], edx
@@:
mov eax, [edi+RECT.top]
mov ebx, [edi+RECT.bottom]
mov ecx, [esi+RECT.top] ;clip.top
mov edx, [esi+RECT.bottom] ;clip.bottom
 
cmp eax, edx ;top >= clip.bottom
jge .fail
 
cmp ebx, ecx ;bottom < clip.top
jl .fail
 
cmp eax, ecx ;top >= clip.top
jge @F
 
mov [edi+RECT.top], ecx
@@:
cmp ebx, edx ;bottom <= clip.bottom
jle @f
 
mov [edi+RECT.bottom], edx
@@:
pop ebx
clc
ret
.fail:
pop ebx
stc
ret
 
 
align 4
blit_clip:
 
;return code:
;CF= 0 - draw, 1 - don't draw
 
.sx0 = 8
.sy0 = 12
.sx1 = 16
.sy1 = 20
 
.dx0 = 24
.dy0 = 28
.dx1 = 32
.dy1 = 36
 
 
push edi
push esi
push ebx
sub esp, 40
 
mov ebx, ecx
mov edx, [ecx+BLITTER.src_x]
mov [esp+.sx0], edx
mov eax, [ecx+BLITTER.src_y]
mov [esp+.sy0], eax
add edx, [ecx+BLITTER.w]
add eax, [ecx+BLITTER.h]
mov [esp+.sx1], edx
mov [esp+.sy1], eax
 
lea edi, [esp+.sx0]
lea esi, [ebx+BLITTER.sc]
 
call block_clip
jc .done
 
mov edi, [esp+.sx0]
mov edx, [ebx+BLITTER.dst_x]
add edx, edi
sub edx, [ebx+BLITTER.src_x]
mov [esp+.dx0], edx
 
mov ecx, [esp+.sy0]
mov eax, [ebx+BLITTER.dst_y]
add eax, ecx
sub eax, [ebx+BLITTER.src_y]
mov [esp+.dy0], eax
 
sub edx, edi
add edx, [esp+.sx1]
mov [esp+.dx1], edx
 
sub eax, ecx
add eax, [esp+.sy1]
mov [esp+.dy1], eax
 
lea edi, [esp+.dx0]
lea esi, [ebx+BLITTER.dc]
call block_clip
jc .done
 
mov edx, [esp+.dx0]
mov eax, [esp+.dx1]
sub eax, edx
mov [ebx+BLITTER.w], eax
 
mov eax, [esp+.dy0]
mov ecx, [esp+.dy1]
sub ecx, eax
mov [ebx+BLITTER.h], ecx
 
mov ecx, [ebx+BLITTER.src_x]
add ecx, edx
sub ecx, [ebx+BLITTER.dst_x]
mov [ebx+BLITTER.src_x], ecx
 
mov ecx, [ebx+BLITTER.src_y]
add ecx, eax
sub ecx, [ebx+BLITTER.dst_y]
mov [ebx+BLITTER.src_y], ecx
mov [ebx+BLITTER.dst_x], edx
mov [ebx+BLITTER.dst_y], eax
clc
.done:
add esp, 40
pop ebx
pop esi
pop edi
 
 
purge .sx0
purge .sy0
purge .sx1
purge .sy1
 
purge .dx0
purge .dy0
purge .dx1
purge .dy1
 
ret
 
align 4
blit_32:
push ebp
push edi
push esi
push ebx
virtual at sizeof.BLITTER
.position dd ? ; (x shl 16) + y
; ???
.extra_var1 dd ?
.flags dd ?
.local_vars_size = $
end virtual
sub esp, .local_vars_size
mov [esp+.flags], ebx
mov eax, [TASK_BASE]
mov ebx, [eax-twdw + WDATA.box.width]
mov edx, [eax-twdw + WDATA.box.height]
inc ebx
inc edx
 
xor eax, eax
 
mov [esp+BLITTER.dc.left], eax
mov [esp+BLITTER.dc.top], eax
mov [esp+BLITTER.dc.right], ebx
mov [esp+BLITTER.dc.bottom], edx
 
mov [esp+BLITTER.sc.left], eax
mov [esp+BLITTER.sc.top], eax
mov eax, [ecx+24]
 
mov [esp+BLITTER.sc.right], eax
mov eax, [ecx+28]
 
mov [esp+BLITTER.sc.bottom], eax
 
mov eax, [ecx]
mov [esp+BLITTER.dst_x], eax
mov eax, [ecx+4]
mov [esp+BLITTER.dst_y], eax
 
mov eax, [ecx+16]
mov [esp+BLITTER.src_x], eax
mov eax, [ecx+20]
mov [esp+BLITTER.src_y], eax
mov eax, [ecx+8]
mov [esp+BLITTER.w], eax
mov eax, [ecx+12]
mov [esp+BLITTER.h], eax
 
 
mov eax, [ecx+32]
mov [esp+BLITTER.bitmap], eax
mov eax, [ecx+36]
mov [esp+BLITTER.stride], eax
 
mov ecx, esp
call blit_clip
jc .L57
 
mov eax, [TASK_BASE]
 
mov ebx, [esp+BLITTER.dst_x]
mov ebp, [esp+BLITTER.dst_y]
add ebx, [eax-twdw + WDATA.box.left]
add ebp, [eax-twdw + WDATA.box.top]
test [esp+.flags], BLIT_CLIENT_RELATIVE
jz .no_client_relative
 
mov eax, [current_slot]
add ebx, [eax + APPDATA.wnd_clientbox.left]
add ebp, [eax + APPDATA.wnd_clientbox.top]
.no_client_relative:
 
mov ecx, ebx
add ecx, [esp+BLITTER.w]
shl ecx, 16
mov cx, bp
add ecx, [esp+BLITTER.h]
 
mov eax, ebx
shl eax, 16
mov ax, bp
mov [esp+.position], eax
 
mov edi, ebp
 
; imul edi, [_display.pitch]
mov edi, [BPSLine_calc_area+edi*4]
; imul ebp, [_display.width]
mov ebp, [d_width_calc_area+ebp*4]
 
add ebp, ebx
add ebp, [_display.win_map]
 
mov eax, [esp+BLITTER.src_y]
imul eax, [esp+BLITTER.stride]
mov esi, [esp+BLITTER.src_x]
lea esi, [eax+esi*4]
add esi, [esp+BLITTER.bitmap]
 
mov eax, ecx
mov ecx, [esp+BLITTER.h]
mov edx, [esp+BLITTER.w]
 
test ecx, ecx ;FIXME check clipping
jz .L57
 
test edx, edx
jz .L57
 
cmp [_display.bits_per_pixel], 32
jne .core_24
 
lea edi, [edi+ebx*4]
 
mov ebx, [current_slot_idx]
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je .core_32.software_cursor
cmp [_display.select_cursor], 0
jne .core_32.hardware_cursor
;--------------------------------------
.core_32.software_cursor:
align 4
.outer32:
 
align 4
.inner32:
cmp [ebp], bl
jne .skip
;--------------------------------------
mov eax, [esi]
 
mov ecx, [esp+.position]
 
; check mouse area for putpixel
call [_display.check_mouse]
;--------------------------------------
; store to real LFB
mov [LFB_BASE+edi], eax
;--------------------------------------
align 4
.skip:
add esi, 4
add edi, 4
inc ebp
add [esp+.position], 1 shl 16
dec edx
jnz .inner32
 
add esi, [esp+BLITTER.stride]
add edi, [_display.lfb_pitch]
add ebp, [_display.width]
 
mov edx, [esp+BLITTER.w]
mov eax, edx
inc [esp+.position]
sub ebp, edx
shl eax, 2
sub esi, eax
sub edi, eax
shl eax, 16-2
sub [esp+.position], eax
dec [esp+BLITTER.h]
jnz .outer32
jmp .done
.core_32.hardware_cursor:
align 4
.hw.outer32:
xor ecx, ecx
 
align 4
.hw.inner32:
cmp [ebp+ecx], bl
jne .hw.skip
mov eax, [esi+ecx*4]
mov [LFB_BASE+edi+ecx*4], eax
 
align 4
.hw.skip:
inc ecx
dec edx
jnz .hw.inner32
 
add esi, [esp+BLITTER.stride]
add edi, [_display.lfb_pitch]
add ebp, [_display.width]
 
mov edx, [esp+BLITTER.w]
dec [esp+BLITTER.h]
jnz .hw.outer32
 
.done:
; call [draw_pointer]
; call __sys_draw_pointer
.L57:
add esp, .local_vars_size
pop ebx
pop esi
pop edi
pop ebp
ret
 
.core_24:
cmp [_display.bits_per_pixel], 24
jne .core_16
 
lea ebx, [ebx+ebx*2]
lea edi, [LFB_BASE+edi+ebx]
mov ebx, [current_slot_idx]
 
align 4
.outer24:
mov [esp+.extra_var1], edi
xor ecx, ecx
 
align 4
.inner24:
cmp [ebp+ecx], bl ; Does the process own this pixel?
jne .skip_1
;--------------------------------------
push eax
mov eax, [esi+ecx*4]
 
lea edi, [edi+ecx*2]
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je @f
cmp [_display.select_cursor], 0
jne .no_mouseunder_1
;--------------------------------------
align 4
@@:
push ecx
 
mov ecx, [esp+4]
ror ecx, 16
sub ecx, edx
rol ecx, 16
sub ecx, [esp+BLITTER.h + 8]
 
; check mouse area for putpixel
call [_display.check_mouse]
pop ecx
;--------------------------------------
align 4
.no_mouseunder_1:
mov [edi+ecx], ax
shr eax, 16
mov [edi+ecx+2], al
 
pop eax
;--------------------------------------
align 4
.skip_1:
mov edi, [esp+.extra_var1]
inc ecx
dec edx
jnz .inner24
 
add esi, [esp+BLITTER.stride]
add edi, [_display.lfb_pitch]
add ebp, [_display.width]
 
mov edx, [esp+BLITTER.w]
dec [esp+BLITTER.h]
jnz .outer24
 
jmp .done
 
 
.core_16:
lea edi, [LFB_BASE+edi+ebx*2]
mov ebx, [current_slot_idx]
 
.outer16:
mov [esp+.extra_var1], edi
xor ecx, ecx
 
.inner16:
cmp [ebp+ecx], bl ; Does the process own this pixel?
jne .skip_2
;--------------------------------------
push eax
mov eax, [esi+ecx*4]
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je @f
cmp [_display.select_cursor], 0
jne .no_mouseunder_2
;--------------------------------------
@@:
push ecx
 
mov ecx, [esp+4]
ror ecx, 16
sub ecx, edx
rol ecx, 16
sub ecx, [esp+BLITTER.h + 8]
 
; check mouse area for putpixel
call [_display.check_mouse]
pop ecx
;--------------------------------------
.no_mouseunder_2:
; convert to 16 bpp and store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [edi+ecx*2], ax
pop eax
;--------------------------------------
.skip_2:
mov edi, [esp+.extra_var1]
inc ecx
dec edx
jnz .inner16
 
add esi, [esp+BLITTER.stride]
add edi, [_display.lfb_pitch]
add ebp, [_display.width]
 
mov edx, [esp+BLITTER.w]
dec [esp+BLITTER.h]
jnz .outer16
 
jmp .done
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video/cursors.inc
0,0 → 1,1238
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2018. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
LOAD_FROM_FILE = 0
LOAD_FROM_MEM = 1
LOAD_INDIRECT = 2
LOAD_SYSTEM = 3
 
struct BITMAPINFOHEADER
Size dd ?
Width dd ?
Height dd ?
Planes dw ?
BitCount dw ?
Compression dd ?
SizeImage dd ?
XPelsPerMeter dd ?
YPelsPerMeter dd ?
ClrUsed dd ?
ClrImportant dd ?
ends
;------------------------------------------------------------------------------
align 4
proc init_cursor stdcall, dst:dword, src:dword
locals
rBase dd ?
pQuad dd ?
pBits dd ?
pAnd dd ?
width dd ?
height dd ?
counter dd ?
endl
 
mov esi, [src]
add esi, [esi+18]
mov eax, esi
 
cmp [esi+BITMAPINFOHEADER.BitCount], 24
je .img_24
cmp [esi+BITMAPINFOHEADER.BitCount], 8
je .img_8
cmp [esi+BITMAPINFOHEADER.BitCount], 4
je .img_4
;--------------------------------------
align 4
.img_2:
add eax, [esi]
mov [pQuad], eax
add eax, 8
mov [pBits], eax
add eax, 128
mov [pAnd], eax
mov eax, [esi+4]
mov [width], eax
mov ebx, [esi+8]
shr ebx, 1
mov [height], ebx
 
mov edi, [dst]
add edi, 32*31*4
mov [rBase], edi
 
mov esi, [pQuad]
;--------------------------------------
align 4
.l21:
mov ebx, [pBits]
mov ebx, [ebx]
bswap ebx
mov eax, [pAnd]
mov eax, [eax]
bswap eax
mov [counter], 32
;--------------------------------------
align 4
@@:
xor edx, edx
shl eax, 1
setc dl
dec edx
 
xor ecx, ecx
shl ebx, 1
setc cl
mov ecx, [esi+ecx*4]
and ecx, edx
and edx, 0xFF000000
or edx, ecx
mov [edi], edx
 
add edi, 4
dec [counter]
jnz @B
 
add [pBits], 4
add [pAnd], 4
mov edi, [rBase]
sub edi, 128
mov [rBase], edi
sub [height], 1
jnz .l21
ret
;--------------------------------------
align 4
.img_4:
add eax, [esi]
mov [pQuad], eax
add eax, 64
mov [pBits], eax
add eax, 0x200
mov [pAnd], eax
mov eax, [esi+4]
mov [width], eax
mov ebx, [esi+8]
shr ebx, 1
mov [height], ebx
 
mov edi, [dst]
add edi, 32*31*4
mov [rBase], edi
 
mov esi, [pQuad]
mov ebx, [pBits]
;--------------------------------------
align 4
.l4:
mov eax, [pAnd]
mov eax, [eax]
bswap eax
mov [counter], 16
;--------------------------------------
align 4
@@:
xor edx, edx
shl eax, 1
setc dl
dec edx
 
movzx ecx, byte [ebx]
and cl, 0xF0
shr ecx, 2
mov ecx, [esi+ecx]
and ecx, edx
and edx, 0xFF000000
or edx, ecx
mov [edi], edx
 
xor edx, edx
shl eax, 1
setc dl
dec edx
 
movzx ecx, byte [ebx]
and cl, 0x0F
mov ecx, [esi+ecx*4]
and ecx, edx
and edx, 0xFF000000
or edx, ecx
mov [edi+4], edx
 
inc ebx
add edi, 8
dec [counter]
jnz @B
 
add [pAnd], 4
mov edi, [rBase]
sub edi, 128
mov [rBase], edi
sub [height], 1
jnz .l4
ret
;--------------------------------------
align 4
.img_8:
add eax, [esi]
mov [pQuad], eax
add eax, 1024
mov [pBits], eax
add eax, 1024
mov [pAnd], eax
mov eax, [esi+4]
mov [width], eax
mov ebx, [esi+8]
shr ebx, 1
mov [height], ebx
 
mov edi, [dst]
add edi, 32*31*4
mov [rBase], edi
 
mov esi, [pQuad]
mov ebx, [pBits]
;--------------------------------------
align 4
.l81:
mov eax, [pAnd]
mov eax, [eax]
bswap eax
mov [counter], 32
;--------------------------------------
align 4
@@:
xor edx, edx
shl eax, 1
setc dl
dec edx
 
movzx ecx, byte [ebx]
mov ecx, [esi+ecx*4]
and ecx, edx
and edx, 0xFF000000
or edx, ecx
mov [edi], edx
 
inc ebx
add edi, 4
dec [counter]
jnz @B
 
add [pAnd], 4
mov edi, [rBase]
sub edi, 128
mov [rBase], edi
sub [height], 1
jnz .l81
ret
;--------------------------------------
align 4
.img_24:
add eax, [esi]
mov [pQuad], eax
add eax, 0xC00
mov [pAnd], eax
mov eax, [esi+BITMAPINFOHEADER.Width]
mov [width], eax
mov ebx, [esi+BITMAPINFOHEADER.Height]
shr ebx, 1
mov [height], ebx
 
mov edi, [dst]
add edi, 32*31*4
mov [rBase], edi
 
mov esi, [pAnd]
mov ebx, [pQuad]
;--------------------------------------
align 4
.row_24:
mov eax, [esi]
bswap eax
mov [counter], 32
;--------------------------------------
align 4
@@:
xor edx, edx
shl eax, 1
setc dl
dec edx
 
mov ecx, [ebx]
and ecx, 0x00FFFFFF
and ecx, edx
and edx, 0xFF000000
or edx, ecx
mov [edi], edx
add ebx, 3
add edi, 4
dec [counter]
jnz @B
 
add esi, 4
mov edi, [rBase]
sub edi, 128
mov [rBase], edi
sub [height], 1
jnz .row_24
ret
endp
;------------------------------------------------------------------------------
align 4
proc set_cursor stdcall, hcursor:dword
mov eax, [hcursor]
cmp [eax+CURSOR.magic], 'CURS'
jne .fail
; cmp [eax+CURSOR.size], CURSOR_SIZE
; jne .fail
mov ebx, [current_slot]
xchg eax, [ebx+APPDATA.cursor]
jmp .end
;--------------------------------------
align 4
.fail:
mov eax, [def_cursor]
mov ebx, [current_slot]
xchg eax, [ebx+APPDATA.cursor]
align 4
.end:
mov [redrawmouse_unconditional], 1
call __sys_draw_pointer
ret
endp
;------------------------------------------------------------------------------
align 4
; param
; eax= pid
; ebx= src
; ecx= flags
 
create_cursor:
.src equ esp
.flags equ esp+4
.hcursor equ esp+8
 
sub esp, 4 ;space for .hcursor
push ecx
push ebx
 
mov ebx, eax
mov eax, sizeof.CURSOR
call create_kernel_object
test eax, eax
jz .fail
 
mov [.hcursor], eax
 
xor ebx, ebx
mov [eax+CURSOR.magic], 'CURS'
mov [eax+CURSOR.destroy], destroy_cursor
mov [eax+CURSOR.hot_x], ebx
mov [eax+CURSOR.hot_y], ebx
 
stdcall kernel_alloc, 0x1000
test eax, eax
jz .fail
 
mov edi, [.hcursor]
mov [edi+CURSOR.base], eax
 
mov esi, [.src]
mov ebx, [.flags]
cmp bx, LOAD_INDIRECT
je .indirect
 
movzx ecx, word [esi+10]
movzx edx, word [esi+12]
mov [edi+CURSOR.hot_x], ecx
mov [edi+CURSOR.hot_y], edx
 
stdcall init_cursor, eax, esi
 
align 4
.add_cursor:
mov ecx, [.hcursor]
lea ecx, [ecx+CURSOR.list_next]
lea edx, [_display.cr_list.next]
 
pushfd
cli
list_add ecx, edx ;list_add_tail(new, head)
popfd
 
mov eax, [.hcursor]
cmp [_display.init_cursor], 0
je .fail
 
push eax
call [_display.init_cursor]
add esp, 4
 
mov eax, [.hcursor]
;--------------------------------------
align 4
.fail:
add esp, 12
ret
;--------------------------------------
align 4
.indirect:
shr ebx, 16
movzx ecx, bh
movzx edx, bl
mov [edi+CURSOR.hot_x], ecx
mov [edi+CURSOR.hot_y], edx
 
xchg edi, eax
mov ecx, 1024
cld
rep movsd
jmp .add_cursor
;------------------------------------------------------------------------------
align 4
proc load_cursor stdcall, src:dword, flags:dword
locals
handle dd ?
endl
 
xor eax, eax
cmp [create_cursor], eax
je .fail2
 
mov [handle], eax
cmp word [flags], LOAD_FROM_FILE
jne @F
 
stdcall load_file, [src]
test eax, eax
jz .fail
mov [src], eax
;--------------------------------------
align 4
@@:
push ebx
push esi
push edi
 
mov eax, [current_slot_idx]
shl eax, 5
mov eax, [TASK_TABLE+eax+4]
mov ebx, [src]
mov ecx, [flags]
call create_cursor ;eax, ebx, ecx
mov [handle], eax
 
cmp word [flags], LOAD_FROM_FILE
jne .exit
stdcall kernel_free, [src]
;--------------------------------------
align 4
.exit:
pop edi
pop esi
pop ebx
;--------------------------------------
align 4
.fail:
mov eax, [handle]
;--------------------------------------
align 4
.fail2:
ret
endp
;------------------------------------------------------------------------------
align 4
proc delete_cursor stdcall, hcursor:dword
 
; DEBUGF 1,'K : delete_cursor %x\n', [hcursor]
 
mov esi, [hcursor]
 
cmp [esi+CURSOR.magic], 'CURS'
jne .fail
 
mov ebx, [current_slot_idx]
shl ebx, 5
mov ebx, [TASK_TABLE+ebx+4]
cmp ebx, [esi+CURSOR.pid]
jne .fail
 
mov ebx, [current_slot]
cmp esi, [ebx+APPDATA.cursor]
jne @F
mov eax, [def_cursor]
mov [ebx+APPDATA.cursor], eax
;--------------------------------------
align 4
@@:
mov eax, [hcursor]
call [eax+APPOBJ.destroy]
;--------------------------------------
align 4
.fail:
ret
endp
;------------------------------------------------------------------------------
align 4
; param
; eax= cursor
destroy_cursor:
 
push eax
stdcall kernel_free, [eax+CURSOR.base]
 
mov eax, [esp]
lea eax, [eax+CURSOR.list_next]
 
pushfd
cli
list_del eax
popfd
 
pop eax
call destroy_kernel_object
ret
;------------------------------------------------------------------------------
align 4
select_cursor:
mov eax, [esp+4]
mov [_display.cursor], eax
ret 4
;------------------------------------------------------------------------------
align 4
proc restore_24 stdcall, x:dword, y:dword
 
push ebx
 
mov ebx, [cur_saved_base]
mov edx, [cur.h]
test edx, edx
jz .ret
 
push esi
push edi
 
mov esi, cur_saved_data
mov ecx, [cur.w]
lea ecx, [ecx+ecx*2]
push ecx
;--------------------------------------
align 4
@@:
mov edi, ebx
add ebx, [_display.lfb_pitch]
 
mov ecx, [esp]
rep movsb
dec edx
jnz @B
 
pop ecx
pop edi
pop esi
;--------------------------------------
align 4
.ret:
pop ebx
ret
endp
;------------------------------------------------------------------------------
align 4
proc restore_32 stdcall, x:dword, y:dword
 
push ebx
 
mov ebx, [cur_saved_base]
mov edx, [cur.h]
test edx, edx
jz .ret
 
push esi
push edi
 
mov esi, cur_saved_data
;--------------------------------------
align 4
@@:
mov edi, ebx
add ebx, [_display.lfb_pitch]
 
mov ecx, [cur.w]
rep movsd
dec edx
jnz @B
 
pop edi
pop esi
 
;--------------------------------------
align 4
.ret:
pop ebx
ret
endp
;------------------------------------------------------------------------------
align 4
proc restore_16 stdcall, x:dword, y:dword
 
push ebx
 
mov ebx, [cur_saved_base]
mov edx, [cur.h]
test edx, edx
jz .ret
 
push esi
push edi
 
mov esi, cur_saved_data
;--------------------------------------
align 4
@@:
mov edi, ebx
add ebx, [_display.lfb_pitch]
 
mov ecx, [cur.w]
rep movsw
dec edx
jnz @B
 
pop edi
pop esi
 
;--------------------------------------
align 4
.ret:
pop ebx
ret
endp
;------------------------------------------------------------------------------
align 4
proc move_cursor_24 stdcall, hcursor:dword, x:dword, y:dword
locals
h dd ?
_dx dd ?
_dy dd ?
endl
 
mov esi, [hcursor]
mov ecx, [x]
mov eax, [y]
; mov ebx, [BytesPerScanLine]
 
xor edx, edx
sub ecx, [esi+CURSOR.hot_x]
lea ebx, [ecx+32-1]
mov [x], ecx
sets dl
dec edx
and ecx, edx ;clip x to 0<=x
mov [cur.left], ecx
mov edi, ecx
sub edi, [x]
mov [_dx], edi
 
xor edx, edx
sub eax, [esi+CURSOR.hot_y]
lea edi, [eax+32-1]
mov [y], eax
sets dl
dec edx
and eax, edx ;clip y to 0<=y
mov [cur.top], eax
mov edx, eax
sub edx, [y]
mov [_dy], edx
 
; mul dword [BytesPerScanLine]
mov eax, [BPSLine_calc_area+eax*4]
lea edx, [LFB_BASE+ecx*3]
add edx, eax
mov [cur_saved_base], edx
 
cmp ebx, [_display.width]
jb @F
mov ebx, [_display.width]
;--------------------------------------
align 4
@@:
cmp edi, [_display.height]
jb @F
mov edi, [_display.height]
;--------------------------------------
align 4
@@:
 
sub ebx, [x]
sub edi, [y]
sub ebx, [_dx]
sub edi, [_dy]
 
mov [cur.w], ebx
mov [cur.h], edi
mov [h], edi
 
mov eax, edi
mov edi, cur_saved_data
;--------------------------------------
align 4
@@:
mov esi, edx
add edx, [_display.lfb_pitch]
mov ecx, [cur.w]
lea ecx, [ecx+ecx*2]
rep movsb
dec eax
jnz @B
 
;draw cursor
mov ebx, [cur_saved_base]
mov eax, [_dy]
shl eax, 5
add eax, [_dx]
 
mov esi, [hcursor]
mov esi, [esi+CURSOR.base]
lea edx, [esi+eax*4]
;--------------------------------------
align 4
.row:
mov ecx, [cur.w]
mov esi, edx
mov edi, ebx
add edx, 32*4
add ebx, [_display.lfb_pitch]
;--------------------------------------
align 4
.pix:
lodsd
test eax, 0xFF000000
jz @F
mov [edi], ax
shr eax, 16
mov [edi+2], al
;--------------------------------------
align 4
@@:
add edi, 3
dec ecx
jnz .pix
 
dec [h]
jnz .row
ret
endp
;------------------------------------------------------------------------------
align 4
proc move_cursor_32 stdcall, hcursor:dword, x:dword, y:dword
locals
h dd ?
_dx dd ?
_dy dd ?
endl
 
mov esi, [hcursor]
mov ecx, [x]
mov eax, [y]
 
xor edx, edx
sub ecx, [esi+CURSOR.hot_x]
lea ebx, [ecx+32-1]
mov [x], ecx
sets dl
dec edx
and ecx, edx ;clip x to 0<=x
mov [cur.left], ecx
mov edi, ecx
sub edi, [x]
mov [_dx], edi
 
xor edx, edx
sub eax, [esi+CURSOR.hot_y]
lea edi, [eax+32-1]
mov [y], eax
sets dl
dec edx
and eax, edx ;clip y to 0<=y
mov [cur.top], eax
mov edx, eax
sub edx, [y]
mov [_dy], edx
 
; mul dword [BytesPerScanLine]
mov eax, [BPSLine_calc_area+eax*4]
lea edx, [LFB_BASE+eax+ecx*4]
mov [cur_saved_base], edx
 
cmp ebx, [_display.width]
jb @F
mov ebx, [_display.width]
;--------------------------------------
align 4
@@:
cmp edi, [_display.height]
jb @F
mov edi, [_display.height]
;--------------------------------------
align 4
@@:
sub ebx, [x]
sub edi, [y]
sub ebx, [_dx]
sub edi, [_dy]
 
mov [cur.w], ebx
mov [cur.h], edi
mov [h], edi
 
mov eax, edi
mov edi, cur_saved_data
;--------------------------------------
align 4
@@:
mov esi, edx
add edx, [_display.lfb_pitch]
mov ecx, [cur.w]
rep movsd
dec eax
jnz @B
 
;draw cursor
mov ebx, [cur_saved_base]
mov eax, [_dy]
shl eax, 5
add eax, [_dx]
 
mov esi, [hcursor]
mov esi, [esi+CURSOR.base]
lea edx, [esi+eax*4]
;--------------------------------------
align 4
.row:
mov ecx, [cur.w]
mov esi, edx
mov edi, ebx
add edx, 32*4
add ebx, [_display.lfb_pitch]
;--------------------------------------
align 4
.pix:
lodsd
test eax, 0xFF000000
jz @F
mov [edi], eax
;--------------------------------------
align 4
@@:
add edi, 4
dec ecx
jnz .pix
 
dec [h]
jnz .row
ret
endp
;------------------------------------------------------------------------------
align 4
proc move_cursor_16 stdcall, hcursor:dword, x:dword, y:dword
locals
h dd ?
_dx dd ?
_dy dd ?
endl
 
mov esi, [hcursor]
mov ecx, [x]
mov eax, [y]
 
xor edx, edx
sub ecx, [esi+CURSOR.hot_x]
lea ebx, [ecx+32-1]
mov [x], ecx
sets dl
dec edx
and ecx, edx ;clip x to 0<=x
mov [cur.left], ecx
mov edi, ecx
sub edi, [x]
mov [_dx], edi
 
xor edx, edx
sub eax, [esi+CURSOR.hot_y]
lea edi, [eax+32-1]
mov [y], eax
sets dl
dec edx
and eax, edx ;clip y to 0<=y
mov [cur.top], eax
mov edx, eax
sub edx, [y]
mov [_dy], edx
 
; mul dword [BytesPerScanLine]
mov eax, [BPSLine_calc_area+eax*4]
lea edx, [LFB_BASE+eax+ecx*2]
mov [cur_saved_base], edx
 
cmp ebx, [_display.width]
jb @F
mov ebx, [_display.width]
;--------------------------------------
align 4
@@:
cmp edi, [_display.height]
jb @F
mov edi, [_display.height]
;--------------------------------------
align 4
@@:
sub ebx, [x]
sub edi, [y]
sub ebx, [_dx]
sub edi, [_dy]
 
mov [cur.w], ebx
mov [cur.h], edi
mov [h], edi
 
mov eax, edi
mov edi, cur_saved_data
;--------------------------------------
align 4
@@:
mov esi, edx
add edx, [_display.lfb_pitch]
mov ecx, [cur.w]
 
rep movsw
dec eax
jnz @B
 
;draw cursor
mov ebx, [cur_saved_base]
mov eax, [_dy]
shl eax, 5
add eax, [_dx]
 
mov esi, [hcursor]
mov esi, [esi+CURSOR.base]
lea edx, [esi+eax*4]
;--------------------------------------
align 4
.row:
mov ecx, [cur.w]
mov esi, edx
mov edi, ebx
add edx, 32*4
add ebx, [_display.lfb_pitch]
;--------------------------------------
align 4
.pix:
lodsd
test eax, 0xFF000000
jz @F
; convert to 16 bpp and store to real LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [edi], ax
;--------------------------------------
align 4
@@:
add edi, 2
dec ecx
jnz .pix
 
dec [h]
jnz .row
ret
endp
;------------------------------------------------------------------------------
align 4
check_mouse_area_for_getpixel_new:
; in:
; eax = x
; ebx = y
; out:
; ecx = new color
;--------------------------------------
; check for Y
cmp bx, [Y_UNDER_subtraction_CUR_hot_y]
jb .no_mouse_area
 
cmp bx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae .no_mouse_area
;--------------------------------------
; check for X
cmp ax, [X_UNDER_subtraction_CUR_hot_x]
jb .no_mouse_area
 
cmp ax, [X_UNDER_sub_CUR_hot_x_add_curh]
jae .no_mouse_area
;--------------------------------------
push eax ebx
; offset X
movzx ecx, word [X_UNDER_subtraction_CUR_hot_x]
sub eax, ecx ; x1
; offset Y
movzx ecx, word [Y_UNDER_subtraction_CUR_hot_y]
sub ebx, ecx ; y1
;--------------------------------------
; ebx = offset y
; eax = offset x
imul ebx, [cur.w] ;y
add eax, ebx
mov ebx, eax
shl eax, 2
cmp byte [_display.bits_per_pixel], 32
je @f
sub eax, ebx
cmp byte [_display.bits_per_pixel], 24
je @f
sub eax, ebx
add eax, cur_saved_data
mov ecx, [eax]
shl ecx, 3
ror ecx, 8
shl cx, 2
ror ecx, 8
shl cl, 3
rol ecx, 16
or ecx, 0xff000000
pop ebx eax
ret
 
;--------------------------------------
align 4
@@:
add eax, cur_saved_data
mov ecx, [eax]
or ecx, 0xff000000
pop ebx eax
ret
;--------------------------------------
align 4
.no_mouse_area:
xor ecx, ecx
ret
;-----------------------------------------------------------------------------
align 4
check_mouse_area_for_putpixel_new:
; in:
; ecx = x shl 16 + y
; eax = color
; out:
; eax = new color
;--------------------------------------
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae .no_mouse_area
 
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb .no_mouse_area
 
rol ecx, 16
;--------------------------------------
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae .no_mouse_area
 
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb .no_mouse_area
 
ror ecx, 16
;--------------------------------------
align 4
.1:
push eax
;--------------------------------------
; ecx = (offset x) shl 16 + (offset y)
push ebx
mov ebx, ecx
shr ebx, 16 ; x
and ecx, 0xffff ; y
 
cmp ecx, [cur.h]
jae @f
 
cmp ebx, [cur.w]
jb .ok
;--------------------------------------
align 4
@@:
; DEBUGF 1, "K : SHIT HAPPENS: %x %x \n", ecx,ebx
pop ebx
jmp .sh ; SORRY! SHIT HAPPENS!
;--------------------------------------
align 4
.ok:
; ecx = offset y
; ebx = offset x
push ebx ecx
imul ecx, [cur.w] ;y
add ecx, ebx
mov ebx, ecx
shl ecx, 2
cmp byte [_display.bits_per_pixel], 16
je .16
cmp byte [_display.bits_per_pixel], 24
je .24
and eax, 0xFFFFFF
mov [ecx + cur_saved_data], eax ;store new color to
jmp @f
;--------------------------------------
align 4
.16:
sub ecx, ebx
sub ecx, ebx
; convert to 16 bpp and store to real LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [ecx + cur_saved_data], ax ;store new color to
jmp @f
;--------------------------------------
align 4
.24:
sub ecx, ebx
mov [ecx + cur_saved_data], ax ;store new color to
shr eax, 16
mov [ecx + cur_saved_data + 2], al ;store new color to
;--------------------------------------
align 4
@@:
pop ecx ebx
 
shl ecx, 5
add ecx, ebx
 
mov eax, [current_cursor]
mov eax, [eax+CURSOR.base]
lea eax, [eax+ecx*4]
mov eax, [eax]
 
pop ebx
 
test eax, 0xFF000000
jz @f
 
add esp, 4
ret
;--------------------------------------
align 4
.sh:
mov ecx, -1
;--------------------------------------
align 4
@@:
pop eax
;--------------------------------------
align 4
.no_mouse_area:
ret
;------------------------------------------------------------------------------
align 4
get_display:
mov eax, _display
ret
;------------------------------------------------------------------------------
align 4
init_display:
xor eax, eax
mov edi, _display
 
mov [edi+display_t.init_cursor], eax
mov [edi+display_t.select_cursor], eax
mov [edi+display_t.show_cursor], eax
mov [edi+display_t.move_cursor], eax
mov [edi+display_t.restore_cursor], eax
 
lea ecx, [edi+display_t.cr_list.next]
mov [edi+display_t.cr_list.next], ecx
mov [edi+display_t.cr_list.prev], ecx
 
if ~defined UEFI
cmp [SCR_MODE], word 0x13
jbe .fail
 
test word [SCR_MODE], 0x4000
jz .fail
end if
mov ebx, restore_32
mov ecx, move_cursor_32
mov edx, Vesa20_putpixel32_new
mov eax, [_display.bits_per_pixel]
cmp al, 32
jne .not_32bpp
 
.set:
mov [_display.select_cursor], select_cursor
mov [_display.move_cursor], ecx
mov [_display.restore_cursor], ebx
mov [_display.check_mouse], check_mouse_area_for_putpixel_new
mov [_display.check_m_pixel], check_mouse_area_for_getpixel_new
 
cmp [PUTPIXEL], dword VGA_putpixel
je @f
mov [PUTPIXEL], edx
@@:
stdcall load_cursor, clock_arrow, dword LOAD_FROM_MEM
mov [def_cursor_clock], eax
stdcall load_cursor, def_arrow, dword LOAD_FROM_MEM
mov [def_cursor], eax
ret
 
.not_32bpp:
cmp al, 24
jne .not_24bpp
 
mov ebx, restore_24
mov ecx, move_cursor_24
mov edx, Vesa20_putpixel24_new
jmp .set
 
.not_24bpp:
cmp al, 16
jne .not_16bpp
mov ebx, restore_16
mov ecx, move_cursor_16
mov edx, Vesa20_putpixel16_new
jmp .set
 
.not_16bpp:
; cmp al, 15
; jne .fail
; mov ebx, restore_15
; mov ecx, move_cursor_15
; mov edx, Vesa20_putpixel15_new
; jmp .set
 
.fail:
xor eax, eax
mov [_display.select_cursor], eax
mov [_display.move_cursor], eax
ret
;------------------------------------------------------------------------------
align 4
def_arrow:
file 'arrow.cur'
;------------------------------------------------------------------------------
align 4
clock_arrow:
file 'arrow_clock.cur'
;------------------------------------------------------------------------------
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video/vesa20.inc
0,0 → 1,2518
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; VESA20.INC ;;
;; ;;
;; Vesa 2.0 functions for MenuetOS ;;
;; ;;
;; Copyright 2002 Ville Turjanmaa ;;
;; Alexey, kgaz@crosswindws.net ;;
;; - Voodoo compatible graphics ;;
;; Juan M. Caravaca ;;
;; - Graphics optimimizations eg. drawline ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
uglobal
align 4
bgr_cur_line rd MAX_SCREEN_WIDTH
bgr_next_line rd MAX_SCREEN_WIDTH
endg
 
iglobal
align 4
overlapping_of_points_ptr dd overlapping_of_points
endg
 
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_getpixel16:
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je @f
cmp [_display.select_cursor], 0
jne .no_mouseunder
@@:
 
; check mouse area for putpixel
test ecx, 0x04000000 ; don't load to mouseunder area
jnz .no_mouseunder
call [_display.check_m_pixel]
test ecx, ecx ; 0xff000000
jnz @f
 
.no_mouseunder:
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [eax*2] ; edi = x*2
add edi, ebx ; edi = x*2+(y*y multiplier)
 
movzx ecx, word[LFB_BASE+edi]
shl ecx, 3
ror ecx, 8
shl cx, 2
ror ecx, 8
shl cl, 3
rol ecx, 16
@@:
and ecx, 0x00ffffff
ret
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_getpixel24:
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je @f
cmp [_display.select_cursor], 0
jne .no_mouseunder
@@:
 
; check mouse area for putpixel
test ecx, 0x04000000 ; don't load to mouseunder area
jnz .no_mouseunder
call [_display.check_m_pixel]
test ecx, ecx ; 0xff000000
jnz @f
 
.no_mouseunder:
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [eax+eax*2] ; edi = x*3
add edi, ebx ; edi = x*3+(y*y multiplier)
 
mov ecx, [LFB_BASE+edi]
@@:
and ecx, 0x00ffffff
ret
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_getpixel32:
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je @f
cmp [_display.select_cursor], 0
jne .no_mouseunder
@@:
 
; check mouse area for putpixel
test ecx, 0x04000000 ; don't load to mouseunder area
jnz .no_mouseunder
call [_display.check_m_pixel]
test ecx, ecx ; 0xff000000
jnz @f
 
.no_mouseunder:
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [ebx+eax*4] ; edi = x*4+(y*y multiplier)
 
mov ecx, [LFB_BASE+edi]
@@:
and ecx, 0x00ffffff
ret
 
;-----------------------------------------------------------------------------
; ebx = pointer
; ecx = size [x|y]
; edx = coordinates [x|y]
; ebp = pointer to 'get' function
; esi = pointer to 'init' function
; edi = parameter for 'get' function
 
align 16
vesa20_putimage:
 
virtual at esp
putimg:
.real_sx dd ?
.real_sy dd ?
.image_sx dd ?
.image_sy dd ?
.image_cx dd ?
.image_cy dd ?
.pti dd ?
.abs_cx dd ?
.abs_cy dd ?
.line_increment dd ?
.winmap_newline dd ?
.screen_newline dd ?
.real_sx_and_abs_cx dd ?
.real_sy_and_abs_cy dd ?
.stack_data = 4*14
.edi dd ?
.esi dd ?
.ebp dd ?
.esp dd ?
.ebx dd ?
.edx dd ?
.ecx dd ?
.eax dd ?
.ret_addr dd ?
.arg_0 dd ?
end virtual
 
pushad
sub esp, putimg.stack_data
; save pointer to image
mov [putimg.pti], ebx
; unpack the size
mov eax, ecx
and ecx, 0xFFFF
shr eax, 16
mov [putimg.image_sx], eax
mov [putimg.image_sy], ecx
; unpack the coordinates
mov eax, edx
and edx, 0xFFFF
shr eax, 16
mov [putimg.image_cx], eax
mov [putimg.image_cy], edx
; calculate absolute (i.e. screen) coordinates
mov eax, [TASK_BASE]
mov ebx, [eax-twdw + WDATA.box.left]
add ebx, [putimg.image_cx]
mov [putimg.abs_cx], ebx
mov ebx, [eax-twdw + WDATA.box.top]
add ebx, [putimg.image_cy]
mov [putimg.abs_cy], ebx
; real_sx = MIN(wnd_sx-image_cx, image_sx);
mov ebx, [eax-twdw + WDATA.box.width] ; ebx = wnd_sx
inc ebx ; WDATA.box.width is one pixel less than real window x-size
sub ebx, [putimg.image_cx]
ja @f
add esp, putimg.stack_data
popad
ret
 
@@:
cmp ebx, [putimg.image_sx]
jbe .end_x
mov ebx, [putimg.image_sx]
.end_x:
mov [putimg.real_sx], ebx
; init real_sy
mov ebx, [eax-twdw + WDATA.box.height] ; ebx = wnd_sy
inc ebx
sub ebx, [putimg.image_cy]
ja @f
add esp, putimg.stack_data
popad
ret
 
@@:
cmp ebx, [putimg.image_sy]
jbe .end_y
mov ebx, [putimg.image_sy]
.end_y:
mov [putimg.real_sy], ebx
; line increment
mov eax, [putimg.image_sx]
mov ecx, [putimg.real_sx]
sub eax, ecx
;; imul eax, [putimg.source_bpp]
; lea eax, [eax + eax * 2]
call esi
add eax, [putimg.arg_0]
mov [putimg.line_increment], eax
; winmap new line increment
mov eax, [_display.width]
sub eax, [putimg.real_sx]
mov [putimg.winmap_newline], eax
; screen new line increment
mov eax, [_display.lfb_pitch]
mov ebx, [_display.bytes_per_pixel]
imul ecx, ebx
sub eax, ecx
mov [putimg.screen_newline], eax
; pointer to image
mov esi, [putimg.pti]
; pointer to screen
mov edx, [putimg.abs_cy]
; imul edx, [BytesPerScanLine]
mov edx, [BPSLine_calc_area+edx*4]
mov eax, [putimg.abs_cx]
imul eax, ebx
add edx, eax
; pointer to pixel map
mov eax, [putimg.abs_cy]
; imul eax, [Screen_Max_X]
; add eax, [putimg.abs_cy]
mov eax, [d_width_calc_area + eax*4]
 
add eax, [putimg.abs_cx]
add eax, [_display.win_map]
xchg eax, ebp
 
mov ecx, [putimg.real_sx]
add ecx, [putimg.abs_cx]
mov [putimg.real_sx_and_abs_cx], ecx
mov ecx, [putimg.real_sy]
add ecx, [putimg.abs_cy]
mov [putimg.real_sy_and_abs_cy], ecx
 
; get process number
mov ebx, [current_slot_idx]
 
cmp byte [_display.bits_per_pixel], 16
je put_image_end_16
cmp byte [_display.bits_per_pixel], 24
je put_image_end_24
cmp byte [_display.bits_per_pixel], 32
je put_image_end_32
 
;------------------------------------------------------------------------------
 
put_image_end_16:
 
mov edi, [putimg.real_sy]
 
; check for hardware cursor
mov ecx, [_display.select_cursor]
cmp ecx, select_cursor
je put_image_end_16_new
cmp ecx, 0
je put_image_end_16_old
.new_line:
mov ecx, [putimg.real_sx]
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
cmp [ebp], bl
jne .skip
; convert to 16 bpp and store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [LFB_BASE+edx], ax
.skip:
add edx, 2
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
@@:
dec edi
jnz .new_line
.finish:
add esp, putimg.stack_data
popad
ret
 
;------------------------------------------------------------------------------
 
align 4
put_image_end_16_old:
 
.new_line:
mov ecx, [putimg.real_sx]
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
cmp [ebp], bl
jne .skip
 
push ecx
neg ecx
add ecx, [putimg.real_sx_and_abs_cx + 4]
shl ecx, 16
add ecx, [putimg.real_sy_and_abs_cy + 4]
sub ecx, edi
 
; check mouse area for putpixel
call check_mouse_area_for_putpixel
pop ecx
 
; convert to 16 bpp and store to LFB
;; and eax, 00000000111110001111110011111000b
;; shr ah, 2
;; shr ax, 3
;; ror eax, 8
;; add al, ah
;; rol eax, 8
mov [LFB_BASE+edx], ax
.skip:
inc edx
inc edx
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
@@:
dec edi
jnz .new_line
jmp put_image_end_16.finish
 
;------------------------------------------------------------------------------
 
align 4
put_image_end_16_new:
 
.new_line:
mov ecx, [putimg.real_sx]
 
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
 
cmp [ebp], bl
jne .skip
 
push ecx
.sh:
neg ecx
add ecx, [putimg.real_sx_and_abs_cx + 4]
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae .no_mouse_area
 
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb .no_mouse_area
 
shl ecx, 16
add ecx, [putimg.real_sy_and_abs_cy + 4]
sub ecx, edi
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae .no_mouse_area
 
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb .no_mouse_area
 
; check mouse area for putpixel
call check_mouse_area_for_putpixel_new.1
cmp ecx, -1 ; SHIT HAPPENS?
jne .no_mouse_area
 
mov ecx, [esp]
jmp .sh
 
.no_mouse_area:
pop ecx
; convert to 16 bpp and store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [LFB_BASE+edx], ax
 
.skip:
add edx, 2
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
 
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
 
@@:
dec edi
jnz .new_line
jmp put_image_end_16.finish
 
;------------------------------------------------------------------------------
 
align 4
put_image_end_24:
 
mov edi, [putimg.real_sy]
 
; check for hardware cursor
mov ecx, [_display.select_cursor]
cmp ecx, select_cursor
je put_image_end_24_new
cmp ecx, 0
je put_image_end_24_old
.new_line:
mov ecx, [putimg.real_sx]
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
cmp [ebp], bl
jne .skip
 
; store to LFB
mov [LFB_BASE+edx], ax
shr eax, 16
mov [LFB_BASE+edx+2], al
 
.skip:
add edx, 3
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
@@:
dec edi
jnz .new_line
.finish:
add esp, putimg.stack_data
popad
ret
 
;------------------------------------------------------------------------------
 
align 4
put_image_end_24_old:
 
.new_line:
mov ecx, [putimg.real_sx]
;--------------------------------------
align 4
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
cmp [ebp], bl
jne .skip
 
push ecx
neg ecx
add ecx, [putimg.real_sx_and_abs_cx + 4]
shl ecx, 16
add ecx, [putimg.real_sy_and_abs_cy + 4]
sub ecx, edi
 
; check mouse area for putpixel
call check_mouse_area_for_putpixel
pop ecx
; store to LFB
mov [LFB_BASE+edx], ax
shr eax, 16
mov [LFB_BASE+edx+2], al
 
.skip:
add edx, 3
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
 
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
 
@@:
dec edi
jnz .new_line
jmp put_image_end_24.finish
 
;------------------------------------------------------------------------------
 
align 4
put_image_end_24_new:
 
.new_line:
mov ecx, [putimg.real_sx]
 
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
cmp [ebp], bl
jne .skip
 
push ecx
.sh:
neg ecx
add ecx, [putimg.real_sx_and_abs_cx + 4]
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae .no_mouse_area
 
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb .no_mouse_area
 
shl ecx, 16
 
add ecx, [putimg.real_sy_and_abs_cy + 4]
sub ecx, edi
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae .no_mouse_area
 
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb .no_mouse_area
 
; check mouse area for putpixel
call check_mouse_area_for_putpixel_new.1
cmp ecx, -1 ; SHIT HAPPENS?
jne .no_mouse_area
 
mov ecx, [esp]
jmp .sh
 
.no_mouse_area:
pop ecx
 
; store to LFB
mov [LFB_BASE+edx], ax
shr eax, 16
mov [LFB_BASE+edx+2], al
 
.skip:
add edx, 3
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
 
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
 
@@:
dec edi
jnz .new_line
jmp put_image_end_24.finish
 
;------------------------------------------------------------------------------
 
align 4
put_image_end_32:
 
mov edi, [putimg.real_sy]
 
; check for hardware cursor
mov ecx, [_display.select_cursor]
cmp ecx, select_cursor
je put_image_end_32_new
cmp ecx, 0
je put_image_end_32_old
 
.new_line:
mov ecx, [putimg.real_sx]
 
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
cmp [ebp], bl
jne .skip
 
; store to LFB
mov [LFB_BASE+edx], eax
 
.skip:
add edx, 4
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
 
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
 
@@:
dec edi
jnz .new_line
 
.finish:
add esp, putimg.stack_data
popad
cmp [SCR_MODE], 0x12
jne @f
call VGA__putimage
@@:
mov [EGA_counter], 1
ret
 
;------------------------------------------------------------------------------
 
align 4
put_image_end_32_old:
 
.new_line:
mov ecx, [putimg.real_sx]
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
cmp [ebp], bl
jne .skip
 
push ecx
neg ecx
add ecx, [putimg.real_sx_and_abs_cx + 4]
shl ecx, 16
add ecx, [putimg.real_sy_and_abs_cy + 4]
sub ecx, edi
 
; check mouse area for putpixel
call check_mouse_area_for_putpixel
pop ecx
; store to LFB
mov [LFB_BASE+edx], eax
 
.skip:
add edx, 4
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
 
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
 
@@:
dec edi
jnz .new_line
jmp put_image_end_32.finish
 
;------------------------------------------------------------------------------
 
align 4
put_image_end_32_new:
 
.new_line:
mov ecx, [putimg.real_sx]
 
.new_x:
push [putimg.edi]
mov eax, [putimg.ebp+4]
call eax
cmp [ebp], bl
jne .skip
 
push ecx
 
.sh:
neg ecx
add ecx, [putimg.real_sx_and_abs_cx + 4]
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae .no_mouse_area
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb .no_mouse_area
shl ecx, 16
 
add ecx, [putimg.real_sy_and_abs_cy + 4]
sub ecx, edi
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae .no_mouse_area
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb .no_mouse_area
 
; check mouse area for putpixel
call check_mouse_area_for_putpixel_new.1
cmp ecx, -1 ; SHIT HAPPENS?
jne .no_mouse_area
 
mov ecx, [esp]
jmp .sh
 
.no_mouse_area:
pop ecx
 
; store to LFB
mov [LFB_BASE+edx], eax
 
.skip:
add edx, 4
inc ebp
dec ecx
jnz .new_x
 
add esi, [putimg.line_increment]
add edx, [putimg.screen_newline]
add ebp, [putimg.winmap_newline]
 
cmp [putimg.ebp], putimage_get1bpp
jz .correct
cmp [putimg.ebp], putimage_get2bpp
jz .correct
cmp [putimg.ebp], putimage_get4bpp
jnz @f
 
.correct:
mov eax, [putimg.edi]
mov byte [eax], 80h
 
@@:
dec edi
jnz .new_line
jmp put_image_end_32.finish
 
;------------------------------------------------------------------------------
; eax = x coordinate
; ebx = y coordinate
; ecx = xx RR GG BB
; xx flags:
; 0x01000000 color inversion
; 0x02000000 used for draw_rectangle without top line (for drawwindow_III and drawwindow_IV)
; edi = 0x00000001 force
 
align 4
__sys_putpixel:
 
pushad
cmp eax, [_display.width]
jge .exit
cmp ebx, [_display.height]
jge .exit
test edi, 1 ; force ?
jnz .forced
 
; not forced
mov edx, [d_width_calc_area + ebx*4]
add edx, [_display.win_map]
movzx edx, byte [eax+edx]
cmp edx, [current_slot_idx]
jne .exit
 
.forced:
; check for color inversion
test ecx, 0x01000000
jz .no_inv
 
push eax ebx edx edi
call [GETPIXEL]
pop edi edx ebx eax
 
not ecx
rol ecx, 8
mov cl, [esp+32-8+3]
ror ecx, 8
mov [esp+32-8], ecx
.no_inv:
call [PUTPIXEL] ; call the real put_pixel function
.exit:
popad
ret
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_putpixel16:
 
mov ecx, eax
shl ecx, 16
mov cx, bx
 
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [eax*2]; edi = x*2
mov eax, [esp+32-8+4]
 
; check for hardware cursor
cmp [_display.select_cursor], 0
jne @f
; check mouse area for putpixel
test eax, 0x04000000
jnz @f
call check_mouse_area_for_putpixel
@@:
; store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
 
mov [LFB_BASE+ebx+edi], ax
ret
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_putpixel16_new:
 
mov ecx, eax
shl ecx, 16
mov cx, bx
 
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [eax*2]; edi = x*2
mov eax, [esp+32-8+4]
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
jne @f
; check mouse area for putpixel
test eax, 0x04000000
jnz @f
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae @f
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb @f
rol ecx, 16
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae @f
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb @f
ror ecx, 16
 
call check_mouse_area_for_putpixel_new.1
@@:
; store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
 
mov [LFB_BASE+ebx+edi], ax
ret
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_putpixel24:
 
mov ecx, eax
shl ecx, 16
mov cx, bx
 
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [eax+eax*2]; edi = x*3
mov eax, [esp+32-8+4]
 
; check for hardware cursor
cmp [_display.select_cursor], 0
jne @f
; check mouse area for putpixel
test eax, 0x04000000
jnz @f
call check_mouse_area_for_putpixel
@@:
 
; store to LFB
mov [LFB_BASE+ebx+edi], ax
shr eax, 16
mov [LFB_BASE+ebx+edi+2], al
ret
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_putpixel24_new:
 
mov ecx, eax
shl ecx, 16
mov cx, bx
 
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [eax+eax*2]; edi = x*3
mov eax, [esp+32-8+4]
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
jne @f
; check mouse area for putpixel
test eax, 0x04000000
jnz @f
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae @f
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb @f
rol ecx, 16
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae @f
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb @f
ror ecx, 16
 
call check_mouse_area_for_putpixel_new.1
@@:
; store to LFB
mov [LFB_BASE+ebx+edi], ax
shr eax, 16
mov [LFB_BASE+ebx+edi+2], al
ret
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_putpixel32:
 
mov ecx, eax
shl ecx, 16
mov cx, bx
 
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [ebx+eax*4] ; edi = x*4+(y*y multiplier)
mov eax, [esp+32-8+4] ; eax = color
 
; check for hardware cursor
cmp [_display.select_cursor], 0
jne @f
; check mouse area for putpixel
test eax, 0x04000000
jnz @f
call check_mouse_area_for_putpixel
@@:
and eax, 0xffffff
; store to LFB
mov [LFB_BASE+edi], eax
ret
 
;-----------------------------------------------------------------------------
; eax = x
; ebx = y
 
align 4
Vesa20_putpixel32_new:
 
mov ecx, eax
shl ecx, 16
mov cx, bx
 
; imul ebx, [BytesPerScanLine] ; ebx = y * y multiplier
mov ebx, [BPSLine_calc_area+ebx*4]
lea edi, [ebx+eax*4] ; edi = x*4+(y*y multiplier)
mov eax, [esp+32-8+4] ; eax = color
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
jne @f
; check mouse area for putpixel
test eax, 0x04000000
jnz @f
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae @f
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb @f
rol ecx, 16
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae @f
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb @f
ror ecx, 16
 
call check_mouse_area_for_putpixel_new.1
@@:
and eax, 0x00ffffff
; store to LFB
mov [LFB_BASE+edi], eax
ret
 
;-----------------------------------------------------------------------------
 
align 4
calculate_edi:
; mov edi, ebx
; imul edi, [Screen_Max_X]
; add edi, ebx
mov edi, [d_width_calc_area + ebx*4]
add edi, eax
ret
 
 
;-----------------------------------------------------------------------------
; DRAWLINE
;-----------------------------------------------------------------------------
; eax = x1 shl 16 + x2
; ebx = y1 shl 16 + y2
; ecx = color
; edi = force ?
 
align 4
__sys_draw_line:
 
dl_x1 equ esp+20
dl_y1 equ esp+16
dl_x2 equ esp+12
dl_y2 equ esp+8
dl_dx equ esp+4
dl_dy equ esp+0
 
pusha
 
xor edx, edx ; clear edx
xor esi, esi ; unpack arguments
xor ebp, ebp
mov si, ax ; esi = x2
mov bp, bx ; ebp = y2
shr eax, 16 ; eax = x1
shr ebx, 16 ; ebx = y1
push eax ; save x1
push ebx ; save y1
push esi ; save x2
push ebp ; save y2
; checking x-axis...
sub esi, eax ; esi = x2-x1
push esi ; save y2-y1
jl .x2lx1 ; is x2 less than x1 ?
jg .no_vline ; x1 > x2 ?
mov edx, ebp ; else (if x1=x2)
call vline
push edx ; necessary to rightly restore stack frame at .exit
jmp .exit
 
.x2lx1:
neg esi ; get esi absolute value
 
.no_vline:
; checking y-axis...
sub ebp, ebx ; ebp = y2-y1
push ebp ; save y2-y1
jl .y2ly1 ; is y2 less than y1 ?
jg .no_hline ; y1 > y2 ?
mov edx, [dl_x2] ; else (if y1=y2)
call hline
jmp .exit
 
.y2ly1:
neg ebp ; get ebp absolute value
 
.no_hline:
cmp ebp, esi
jle .x_rules ; |y2-y1| < |x2-x1| ?
cmp [dl_y2], ebx ; make sure y1 is at the begining
jge .no_reverse1
neg dword [dl_dx]
mov edx, [dl_x2]
mov [dl_x2], eax
mov [dl_x1], edx
mov edx, [dl_y2]
mov [dl_y2], ebx
mov [dl_y1], edx
 
.no_reverse1:
mov eax, [dl_dx]
cdq ; extend eax sing to edx
shl eax, 16 ; using 16bit fix-point maths
idiv ebp ; eax = ((x2-x1)*65536)/(y2-y1)
 
; correction for the remainder of the division
shl edx, 1
cmp ebp, edx
jb @f
inc eax
@@:
mov edx, ebp ; edx = counter (number of pixels to draw)
mov ebp, 1 shl 16 ; ebp = dy = 1.0
mov esi, eax ; esi = dx
jmp .y_rules
.x_rules:
cmp [dl_x2], eax ; make sure x1 is at the begining
jge .no_reverse2
neg dword [dl_dy]
mov edx, [dl_x2]
mov [dl_x2], eax
mov [dl_x1], edx
mov edx, [dl_y2]
mov [dl_y2], ebx
mov [dl_y1], edx
.no_reverse2:
xor edx, edx
mov eax, [dl_dy]
cdq ; extend eax sing to edx
shl eax, 16 ; using 16bit fix-point maths
idiv esi ; eax = ((y2-y1)*65536)/(x2-x1)
; correction for the remainder of the division
shl edx, 1
cmp esi, edx
jb @f
inc eax
@@:
mov edx, esi ; edx = counter (number of pixels to draw)
mov esi, 1 shl 16 ; esi = dx = 1.0
mov ebp, eax ; ebp = dy
 
.y_rules:
mov eax, [dl_x1]
mov ebx, [dl_y1]
shl eax, 16
shl ebx, 16
 
and ecx, 0xFBFFFFFF ; negate 0x04000000 save to mouseunder area
.draw:
push eax ebx
 
; correction for the remainder of the division
test ah, 0x80
jz @f
add eax, 1 shl 16
@@:
shr eax, 16
; correction for the remainder of the division
test bh, 0x80
jz @f
add ebx, 1 shl 16
@@:
shr ebx, 16
; and ecx, 0xFBFFFFFF ; negate 0x04000000 save to mouseunder area
; call [putpixel]
call __sys_putpixel
pop ebx eax
add ebx, ebp ; y = y+dy
add eax, esi ; x = x+dx
dec edx
jnz .draw
; force last drawn pixel to be at (x2,y2)
mov eax, [dl_x2]
mov ebx, [dl_y2]
; and ecx, 0xFBFFFFFF ;n egate 0x04000000 save to mouseunder area
; call [putpixel]
call __sys_putpixel
 
.exit:
add esp, 6*4
popa
; call [draw_pointer]
ret
 
;------------------------------------------------------------------------------
; draw an horizontal line
; eax = x1
; edx = x2
; ebx = y
; ecx = color
; edi = force ?
 
align 4
hline:
 
push eax edx
cmp edx, eax ; make sure x2 is above x1
jge @f
xchg eax, edx
@@:
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area
@@:
; call [putpixel]
call __sys_putpixel
inc eax
cmp eax, edx
jle @b
pop edx eax
ret
 
;------------------------------------------------------------------------------
; draw a vertical line
; eax = x
; ebx = y1
; edx = y2
; ecx = color
; edi = force ?
 
align 4
vline:
 
push ebx edx
cmp edx, ebx ; make sure y2 is above y1
jge @f
xchg ebx, edx
@@:
and ecx, 0xFBFFFFFF ;negate 0x04000000 save to mouseunder area
@@:
; call [putpixel]
call __sys_putpixel
inc ebx
cmp ebx, edx
jle @b
pop edx ebx
ret
 
;------------------------------------------------------------------------------
; eax cx
; ebx cy
; ecx xe
; edx ye
; edi color
 
align 4
vesa20_drawbar:
 
virtual at esp
drbar:
.bar_sx dd ?
.bar_sy dd ?
.bar_cx dd ?
.bar_cy dd ?
.abs_cx dd ?
.abs_cy dd ?
.real_sx dd ?
.real_sy dd ?
.color dd ?
.line_inc_scr dd ?
.line_inc_map dd ?
.real_sx_and_abs_cx dd ?
.real_sy_and_abs_cy dd ?
.stack_data = 4*13
end virtual
 
pushad
sub esp, drbar.stack_data
mov [drbar.color], edi
sub edx, ebx
jle .exit
sub ecx, eax
jle .exit
mov [drbar.bar_sy], edx
mov [drbar.bar_sx], ecx
mov [drbar.bar_cx], eax
mov [drbar.bar_cy], ebx
mov edi, [TASK_BASE]
add eax, [edi-twdw + WDATA.box.left] ; win_cx
add ebx, [edi-twdw + WDATA.box.top] ; win_cy
mov [drbar.abs_cx], eax
mov [drbar.abs_cy], ebx
; real_sx = MIN(wnd_sx-bar_cx, bar_sx);
mov ebx, [edi-twdw + WDATA.box.width] ; ebx = wnd_sx
inc ebx ; WDATA.box.width is one pixel less than real window x-size
sub ebx, [drbar.bar_cx]
ja @f
.exit:
add esp, drbar.stack_data
popad
xor eax, eax
inc eax
ret
@@:
cmp ebx, [drbar.bar_sx]
jbe .end_x
mov ebx, [drbar.bar_sx]
.end_x:
mov [drbar.real_sx], ebx
; real_sy = MIN(wnd_sy-bar_cy, bar_sy);
mov ebx, [edi-twdw + WDATA.box.height] ; ebx = wnd_sy
inc ebx
sub ebx, [drbar.bar_cy]
ja @f
add esp, drbar.stack_data
popad
xor eax, eax
inc eax
ret
@@:
cmp ebx, [drbar.bar_sy]
jbe .end_y
mov ebx, [drbar.bar_sy]
.end_y:
mov [drbar.real_sy], ebx
; line_inc_map
mov eax, [_display.width]
sub eax, [drbar.real_sx]
mov [drbar.line_inc_map], eax
; line_inc_scr
mov eax, [drbar.real_sx]
mov ebx, [_display.bytes_per_pixel]
imul eax, ebx
neg eax
add eax, [_display.lfb_pitch]
mov [drbar.line_inc_scr], eax
; pointer to screen
mov edx, [drbar.abs_cy]
; imul edx, [BytesPerScanLine]
mov edx, [BPSLine_calc_area+edx*4]
mov eax, [drbar.abs_cx]
imul eax, ebx
add edx, eax
; pointer to pixel map
mov eax, [drbar.abs_cy]
; imul eax, [Screen_Max_X]
; add eax, [drbar.abs_cy]
mov eax, [d_width_calc_area + eax*4]
 
add eax, [drbar.abs_cx]
add eax, [_display.win_map]
xchg eax, ebp
 
mov ebx, [drbar.real_sx]
add ebx, [drbar.abs_cx]
mov [drbar.real_sx_and_abs_cx], ebx
mov ebx, [drbar.real_sy]
add ebx, [drbar.abs_cy]
mov [drbar.real_sy_and_abs_cy], ebx
 
add edx, LFB_BASE
 
; get process number
mov ebx, [current_slot_idx] ; bl - process num
mov esi, [drbar.real_sy]
mov eax, [drbar.color] ; BBGGRR00
rol eax, 8
mov bh, al ; 0x80 drawing gradient bars
ror eax, 8
 
cmp byte [_display.bits_per_pixel], 16
je draw_bar_end_16
cmp byte [_display.bits_per_pixel], 24
je draw_bar_end_24
cmp byte [_display.bits_per_pixel], 32
je draw_bar_end_32
 
;--------------------------------------
; eax - color high RRGGBB
; bl - process num
; ecx - temp
; edx - pointer to screen
; esi - counter
; edi - counter
 
align 4
draw_bar_end_24:
 
; check for hardware cursor
mov ecx, [_display.select_cursor]
cmp ecx, select_cursor
je draw_bar_end_24_new
cmp ecx, 0
je draw_bar_end_24_old
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
 
; store to LFB
mov [edx], ax
shr eax, 16
mov [edx + 2], al
.skip:
; add pixel
add edx, 3
inc ebp
dec edi
jnz .new_x
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
.end:
add esp, drbar.stack_data
popad
xor eax, eax
ret
 
;------------------------------------------------------------------------------
 
align 4
draw_bar_end_24_old:
 
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
 
mov ecx, [drbar.real_sx_and_abs_cx]
sub ecx, edi
shl ecx, 16
add ecx, [drbar.real_sy_and_abs_cy]
sub ecx, esi
; check mouse area for putpixel
call check_mouse_area_for_putpixel
; store to LFB
mov [edx], ax
shr eax, 16
mov [edx + 2], al
mov eax, [drbar.color]
.skip:
; add pixel
add edx, 3
inc ebp
dec edi
jnz .new_x
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
jmp draw_bar_end_24.end
 
;------------------------------------------------------------------------------
 
align 4
draw_bar_end_24_new:
 
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
 
mov ecx, [drbar.real_sy_and_abs_cy]
sub ecx, esi
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae .no_mouse_area
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb .no_mouse_area
rol ecx, 16
add ecx, [drbar.real_sx_and_abs_cx]
sub ecx, edi
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae .no_mouse_area
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb .no_mouse_area
ror ecx, 16
 
; check mouse area for putpixel
push eax
call check_mouse_area_for_putpixel_new.1
mov [edx], ax
shr eax, 16
mov [edx + 2], al
pop eax
jmp .skip
 
.no_mouse_area:
; store to LFB
mov [edx], ax
ror eax, 16
mov [edx + 2], al
rol eax, 16
.skip:
 
; add pixel
add edx, 3
inc ebp
dec edi
jnz .new_x
 
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
 
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
jmp draw_bar_end_24.end
 
;------------------------------------------------------------------------------
; eax - color high RRGGBB
; bl - process num
; ecx - temp
; edx - pointer to screen
; esi - counter
; edi - counter
 
draw_bar_end_32:
 
; check for hardware cursor
mov ecx, [_display.select_cursor]
cmp ecx, select_cursor
je draw_bar_end_32_new
cmp ecx, 0
je draw_bar_end_32_old
 
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
 
; store to LFB
mov [edx], eax
mov eax, [drbar.color]
.skip:
 
; add pixel
add edx, 4
inc ebp
dec edi
jnz .new_x
 
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
 
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
.end:
add esp, drbar.stack_data
popad
cmp [SCR_MODE], 0x12
jne @f
call VGA_draw_bar
@@:
xor eax, eax
mov [EGA_counter], 1
ret
 
draw_bar_end_32_old:
 
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
 
mov ecx, [drbar.real_sx_and_abs_cx]
sub ecx, edi
shl ecx, 16
add ecx, [drbar.real_sy_and_abs_cy]
sub ecx, esi
 
; check mouse area for putpixel
call check_mouse_area_for_putpixel
; store to LFB
mov [edx], eax
mov eax, [drbar.color]
.skip:
; add pixel
add edx, 4
inc ebp
dec edi
jnz .new_x
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
jmp draw_bar_end_32.end
 
;------------------------------------------------------------------------------
 
align 4
draw_bar_end_32_new:
 
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
 
mov ecx, [drbar.real_sy_and_abs_cy]
sub ecx, esi
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae .no_mouse_area
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb .no_mouse_area
rol ecx, 16
add ecx, [drbar.real_sx_and_abs_cx]
sub ecx, edi
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae .no_mouse_area
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb .no_mouse_area
ror ecx, 16
 
; check mouse area for putpixel
push eax
call check_mouse_area_for_putpixel_new.1
mov [edx], eax
pop eax
jmp .skip
.no_mouse_area:
 
; store to LFB
mov [edx], eax
.skip:
 
; add pixel
add edx, 4
inc ebp
dec edi
jnz .new_x
 
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
 
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
jmp draw_bar_end_32.end
 
;------------------------------------------------------------------------------
; eax - color high RRGGBB
; bl - process num
; ecx - temp
; edx - pointer to screen
; esi - counter
; edi - counter
 
align 4
draw_bar_end_16:
 
; check for hardware cursor
mov ecx, [_display.select_cursor]
cmp ecx, select_cursor
je draw_bar_end_16_new
cmp ecx, 0
je draw_bar_end_16_old
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
; convert to 16 bpp and store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [edx], ax
mov eax, [drbar.color]
.skip:
 
; add pixel
add edx, 2
inc ebp
dec edi
jnz .new_x
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
.end:
add esp, drbar.stack_data
popad
cmp [SCR_MODE], 0x12
jne @f
call VGA_draw_bar
@@:
xor eax, eax
mov [EGA_counter], 1
ret
 
;------------------------------------------------------------------------------
 
align 4
draw_bar_end_16_old:
 
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
 
mov ecx, [drbar.real_sx_and_abs_cx]
sub ecx, edi
shl ecx, 16
add ecx, [drbar.real_sy_and_abs_cy]
sub ecx, esi
 
; check mouse area for putpixel
call check_mouse_area_for_putpixel
; convert to 16 bpp and store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [edx], ax
mov eax, [drbar.color]
.skip:
 
; add pixel
add edx, 2
inc ebp
dec edi
jnz .new_x
 
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
 
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
jmp draw_bar_end_16.end
 
;------------------------------------------------------------------------------
 
align 4
draw_bar_end_16_new:
 
.new_y:
mov edi, [drbar.real_sx]
.new_x:
cmp byte [ebp], bl
jne .skip
 
mov ecx, [drbar.real_sy_and_abs_cy]
sub ecx, esi
 
; check for Y
cmp cx, [Y_UNDER_sub_CUR_hot_y_add_curh]
jae .no_mouse_area
sub cx, [Y_UNDER_subtraction_CUR_hot_y]
jb .no_mouse_area
rol ecx, 16
add ecx, [drbar.real_sx_and_abs_cx]
sub ecx, edi
 
; check for X
cmp cx, [X_UNDER_sub_CUR_hot_x_add_curh]
jae .no_mouse_area
sub cx, [X_UNDER_subtraction_CUR_hot_x]
jb .no_mouse_area
ror ecx, 16
 
; check mouse area for putpixel
push eax
call check_mouse_area_for_putpixel_new.1
push eax
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [edx], ax
pop eax
pop eax
jmp .skip
 
.no_mouse_area:
; convert to 16 bpp and store to LFB
push eax
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [edx], ax
pop eax
.skip:
 
; add pixel
add edx, 2
inc ebp
dec edi
jnz .new_x
 
; add line
add edx, [drbar.line_inc_scr]
add ebp, [drbar.line_inc_map]
 
; drawing gradient bars
test bh, 0x80
jz @f
test al, al
jz @f
dec al
@@:
dec esi
jnz .new_y
jmp draw_bar_end_16.end
 
;------------------------------------------------------------------------------
 
align 4
vesa20_drawbackground_tiled:
 
pushad
; External loop for all y from start to end
mov ebx, [draw_data+32+RECT.top] ; y start
dp2:
mov ebp, [draw_data+32+RECT.left] ; x start
; 1) Calculate pointers in WinMapAddress (does pixel belong to OS thread?) [ebp]
; and LFB data (output for our function) [edi]
; mov eax, [BytesPerScanLine]
; mul ebx
mov eax, [BPSLine_calc_area+ebx*4]
xchg ebp, eax
add ebp, eax
add ebp, eax
cmp byte [_display.bytes_per_pixel], 2
je @f
add ebp, eax
cmp byte [_display.bytes_per_pixel], 3
je @f
add ebp, eax
 
@@:
add ebp, LFB_BASE
; ebp:=Y*BytesPerScanLine+X*BytesPerPixel+AddrLFB
call calculate_edi
xchg edi, ebp
add ebp, [_display.win_map]
; Now eax=x, ebx=y, edi->output, ebp=offset in WinMapAddress
; 2) Calculate offset in background memory block
push eax
xor edx, edx
mov eax, ebx
div dword [BgrDataHeight] ; edx := y mod BgrDataHeight
pop eax
push eax
mov ecx, [BgrDataWidth]
mov esi, edx
imul esi, ecx ; esi := (y mod BgrDataHeight) * BgrDataWidth
xor edx, edx
div ecx ; edx := x mod BgrDataWidth
sub ecx, edx
add esi, edx ; esi := (y mod BgrDataHeight)*BgrDataWidth + (x mod BgrDataWidth)
pop eax
lea esi, [esi*3]
add esi, [img_background]
xor edx, edx
inc edx
; 3) Loop through redraw rectangle and copy background data
; Registers meaning:
; eax = x, ebx = y (screen coordinates)
; ecx = deltax - number of pixels left in current tile block
; edx = 1
; esi -> bgr memory, edi -> output
; ebp = offset in WinMapAddress
dp3:
cmp [ebp], dl
jnz .next_pix
 
push eax ecx
mov ecx, eax
shl ecx, 16
add ecx, ebx
 
mov eax, [esi]
 
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je @f
cmp [_display.select_cursor], 0
jne .no_mouseunder
@@:
and eax, 0xffffff
; check mouse area for putpixel
call [_display.check_mouse]
.no_mouseunder:
 
cmp byte [_display.bits_per_pixel], 16
je .16bpp
; store to LFB
mov [edi], ax
shr eax, 16
mov [edi+2], al
pop ecx eax
jmp .next_pix
 
.16bpp:
; convert to 16 bpp and store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [edi], ax
pop ecx eax
 
; Advance to next pixel
.next_pix:
add esi, 3
add edi, [_display.bytes_per_pixel]
 
add ebp, edx
add eax, edx
cmp eax, [draw_data+32+RECT.right]
ja dp4
sub ecx, edx
jnz dp3
 
; next tile block on x-axis
mov ecx, [BgrDataWidth]
sub esi, ecx
sub esi, ecx
sub esi, ecx
jmp dp3
 
dp4:
; next scan line
inc ebx
cmp ebx, [draw_data+32+RECT.bottom]
jbe dp2
popad
mov [EGA_counter], 1
cmp [SCR_MODE], 0x12
jne @f
call VGA_drawbackground
@@:
ret
 
;------------------------------------------------------------------------------
 
align 4
vesa20_drawbackground_stretch:
 
pushad
; Helper variables
; calculate 2^32*(BgrDataWidth-1) mod (ScreenWidth-1)
mov eax, [BgrDataWidth]
dec eax
xor edx, edx
div dword [_display.width]
push eax ; high
xor eax, eax
div dword [_display.width]
push eax ; low
 
; the same for height
mov eax, [BgrDataHeight]
dec eax
xor edx, edx
div dword [_display.height]
push eax ; high
xor eax, eax
div dword [_display.height]
push eax ; low
 
; External loop for all y from start to end
mov ebx, [draw_data+32+RECT.top] ; y start
mov ebp, [draw_data+32+RECT.left] ; x start
; 1) Calculate pointers in WinMapAddress (does pixel belong to OS thread?) [ebp]
; and LFB data (output for our function) [edi]
; mov eax, [BytesPerScanLine]
; mul ebx
mov eax, [BPSLine_calc_area+ebx*4]
xchg ebp, eax
add ebp, eax
add ebp, eax
cmp byte [_display.bytes_per_pixel], 2
jz @f
add ebp, eax
cmp byte [_display.bytes_per_pixel], 3
jz @f
add ebp, eax
@@:
 
; ebp:=Y*BytesPerScanLine+X*BytesPerPixel+AddrLFB
call calculate_edi
xchg edi, ebp
 
; Now eax=x, ebx=y, edi->output, ebp=offset in WinMapAddress
push ebx
push eax
; 2) Calculate offset in background memory block
mov eax, ebx
imul ebx, dword [esp+12]
mul dword [esp+8]
add edx, ebx ; edx:eax = y * 2^32*(BgrDataHeight-1)/(ScreenHeight-1)
mov esi, edx
imul esi, [BgrDataWidth]
push edx
push eax
mov eax, [esp+8]
mul dword [esp+28]
push eax
mov eax, [esp+12]
mul dword [esp+28]
add [esp], edx
pop edx ; edx:eax = x * 2^32*(BgrDataWidth-1)/(ScreenWidth-1)
add esi, edx
lea esi, [esi*3]
add esi, [img_background]
push eax
push edx
push esi
 
; 3) Smooth horizontal
bgr_resmooth0:
mov ecx, [esp+8]
mov edx, [esp+4]
mov esi, [esp]
push edi
mov edi, bgr_cur_line
call smooth_line
 
bgr_resmooth1:
mov eax, [esp+16+4]
inc eax
cmp eax, [BgrDataHeight]
jae bgr.no2nd
mov ecx, [esp+8+4]
mov edx, [esp+4+4]
mov esi, [esp+4]
add esi, [BgrDataWidth]
add esi, [BgrDataWidth]
add esi, [BgrDataWidth]
mov edi, bgr_next_line
call smooth_line
 
bgr.no2nd:
pop edi
 
sdp3:
xor esi, esi
mov ecx, [esp+12]
 
; 4) Loop through redraw rectangle and copy background data
; Registers meaning:
; esi = offset in current line, edi -> output
; ebp = offset in WinMapAddress
; dword [esp] = offset in bgr data
; qword [esp+4] = x * 2^32 * (BgrDataWidth-1) / (ScreenWidth-1)
; qword [esp+12] = y * 2^32 * (BgrDataHeight-1) / (ScreenHeight-1)
; dword [esp+20] = x
; dword [esp+24] = y
; precalculated constants:
; qword [esp+28] = 2^32*(BgrDataHeight-1)/(ScreenHeight-1)
; qword [esp+36] = 2^32*(BgrDataWidth-1)/(ScreenWidth-1)
 
sdp3a:
mov eax, [_display.win_map]
cmp [ebp+eax], byte 1
jnz snbgp
mov eax, [bgr_cur_line+esi]
test ecx, ecx
jz .novert
mov ebx, [bgr_next_line+esi]
call [overlapping_of_points_ptr]
 
.novert:
push ecx
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je @f
cmp [_display.select_cursor], 0
jne .no_mouseunder
@@:
mov ecx, [esp+20+4] ;x
shl ecx, 16
add ecx, [esp+24+4] ;y
; check mouse area for putpixel
call [_display.check_mouse]
.no_mouseunder:
 
cmp [_display.bits_per_pixel], 16
jne .not_16bpp
; convert to 16 bpp and store to LFB
and eax, 00000000111110001111110011111000b
shr ah, 2
shr ax, 3
ror eax, 8
add al, ah
rol eax, 8
mov [LFB_BASE+edi], ax
pop ecx
jmp snbgp
.not_16bpp:
 
; store to LFB
mov [LFB_BASE+edi], ax
shr eax, 16
mov [LFB_BASE+edi+2], al
pop ecx
 
snbgp:
add edi, [_display.bytes_per_pixel]
add ebp, 1
mov eax, [esp+20]
add eax, 1
mov [esp+20], eax
add esi, 4
cmp eax, [draw_data+32+RECT.right]
jbe sdp3a
 
sdp4:
; next y
mov ebx, [esp+24]
add ebx, 1
mov [esp+24], ebx
cmp ebx, [draw_data+32+RECT.bottom]
ja sdpdone
 
; advance edi, ebp to next scan line
sub eax, [draw_data+32+RECT.left]
sub ebp, eax
add ebp, [_display.width]
sub edi, eax
sub edi, eax
cmp byte [_display.bytes_per_pixel], 2
jz @f
sub edi, eax
cmp byte [_display.bytes_per_pixel], 3
jz @f
sub edi, eax
 
@@:
add edi, [_display.lfb_pitch]
; restore ecx,edx; advance esi to next background line
mov eax, [esp+28]
mov ebx, [esp+32]
add [esp+12], eax
mov eax, [esp+16]
adc [esp+16], ebx
sub eax, [esp+16]
mov ebx, eax
lea eax, [eax*3]
imul eax, [BgrDataWidth]
sub [esp], eax
mov eax, [draw_data+32+RECT.left]
mov [esp+20], eax
test ebx, ebx
jz sdp3
cmp ebx, -1
jnz bgr_resmooth0
push edi
mov esi, bgr_next_line
mov edi, bgr_cur_line
mov ecx, [_display.width]
rep movsd
jmp bgr_resmooth1
 
sdpdone:
add esp, 44
popad
mov [EGA_counter], 1
cmp [SCR_MODE], 0x12
jne @f
call VGA_drawbackground
@@:
ret
 
;--------------------------------------
 
align 4
smooth_line:
mov al, [esi+2]
shl eax, 16
mov ax, [esi]
test ecx, ecx
jz @f
mov ebx, [esi+2]
shr ebx, 8
call [overlapping_of_points_ptr]
@@:
stosd
mov eax, [esp+20+8]
add eax, 1
mov [esp+20+8], eax
cmp eax, [draw_data+32+RECT.right]
ja @f
add ecx, [esp+36+8]
mov eax, edx
adc edx, [esp+40+8]
sub eax, edx
lea eax, [eax*3]
sub esi, eax
jmp smooth_line
@@:
mov eax, [draw_data+32+RECT.left]
mov [esp+20+8], eax
ret
 
;------------------------------------------------------------------------------
 
align 16
overlapping_of_points:
if 0
; this version of procedure works, but is slower than next version
push ecx edx
mov edx, eax
push esi
shr ecx, 24
mov esi, ecx
mov ecx, ebx
movzx ebx, dl
movzx eax, cl
sub eax, ebx
movzx ebx, dh
imul eax, esi
add dl, ah
movzx eax, ch
sub eax, ebx
imul eax, esi
add dh, ah
ror ecx, 16
ror edx, 16
movzx eax, cl
movzx ebx, dl
sub eax, ebx
imul eax, esi
pop esi
add dl, ah
mov eax, edx
pop edx
ror eax, 16
pop ecx
ret
else
push ecx edx
mov edx, eax
push esi
shr ecx, 26
mov esi, ecx
mov ecx, ebx
shl esi, 9
movzx ebx, dl
movzx eax, cl
sub eax, ebx
movzx ebx, dh
add dl, [BgrAuxTable+(eax+0x100)+esi]
movzx eax, ch
sub eax, ebx
add dh, [BgrAuxTable+(eax+0x100)+esi]
ror ecx, 16
ror edx, 16
movzx eax, cl
movzx ebx, dl
sub eax, ebx
add dl, [BgrAuxTable+(eax+0x100)+esi]
pop esi
mov eax, edx
pop edx
ror eax, 16
pop ecx
ret
end if
 
 
;------------------------------------------------------------------------------
 
align 4
init_background:
 
mov edi, BgrAuxTable
xor edx, edx
 
.loop2:
mov eax, edx
shl eax, 8
neg eax
mov ecx, 0x200
 
.loop1:
mov byte [edi], ah
inc edi
add eax, edx
loop .loop1
add dl, 4
jnz .loop2
test byte [cpu_caps+(CAPS_MMX/8)], 1 shl (CAPS_MMX mod 8)
jz @f
mov [overlapping_of_points_ptr], overlapping_of_points_mmx
@@:
ret
 
;------------------------------------------------------------------------------
 
align 16
overlapping_of_points_mmx:
 
movd mm0, eax
movd mm4, eax
movd mm1, ebx
pxor mm2, mm2
punpcklbw mm0, mm2
punpcklbw mm1, mm2
psubw mm1, mm0
movd mm3, ecx
psrld mm3, 24
packuswb mm3, mm3
packuswb mm3, mm3
pmullw mm1, mm3
psrlw mm1, 8
packuswb mm1, mm2
paddb mm4, mm1
movd eax, mm4
 
ret
 
;------------------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video/framebuffer.inc
0,0 → 1,250
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; Synhronization for MenuetOS. ;;
;; Author: Halyavin Andrey, halyavin@land.ru ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
struct FRB
list LHEAD
magic rd 1
handle rd 1
destroy rd 1
 
width rd 1
height rd 1
pitch rd 1
format rd 1
private rd 1
pde rd 8
ends
 
align 4
create_framebuffer:
mov ecx, sizeof.FRB
call create_object
test eax, eax
jz .fail
 
mov [eax+FRB.magic], 'FRMB'
mov [eax+FRB.destroy], 0
.fail:
ret
 
 
align 4
init_video:
mov ebp, bios_fb
 
movzx eax, byte [BOOT.bpp] ; bpp
mov [_display.bits_per_pixel], eax
mov [_display.vrefresh], 60
 
movzx eax, word [BOOT.x_res]; X max
cmp eax, MAX_SCREEN_WIDTH
ja $
mov [_display.width], eax
mov [ebp+FRB.width], eax
mov [display_width_standard], eax
dec eax
mov [screen_workarea.right], eax
 
movzx eax, word [BOOT.y_res]; Y max
cmp eax, MAX_SCREEN_HEIGHT
ja $
mov [_display.height], eax
mov [ebp+FRB.height], eax
mov [display_height_standard], eax
dec eax
mov [screen_workarea.bottom], eax
 
movzx eax, word [BOOT.vesa_mode] ; screen mode
mov dword [SCR_MODE], eax
mov eax, 640 *4 ; Bytes PerScanLine
cmp [SCR_MODE], word 0x13 ; 320x200
je @f
cmp [SCR_MODE], word 0x12 ; VGA 640x480
je @f
movzx eax, word[BOOT.pitch] ; for other modes
@@:
mov [_display.lfb_pitch], eax
mov [ebp+FRB.pitch], eax
 
mov eax, [BOOT.lfb]
mov [LFBAddress], eax
 
mov eax, [_display.width]
mul [_display.height]
mov [_display.win_map_size], eax
 
cmp word [SCR_MODE], 0x0012 ; VGA (640x480 16 colors)
je .vga
cmp word [SCR_MODE], 0x0013 ; MCGA (320*200 256 colors)
je .32bpp
cmp byte [_display.bits_per_pixel], 32
je .32bpp
cmp byte [_display.bits_per_pixel], 24
je .24bpp
cmp byte [_display.bits_per_pixel], 16
je .16bpp
 
.vga:
mov [PUTPIXEL], VGA_putpixel
mov [GETPIXEL], Vesa20_getpixel32 ; Conversion buffer is 32 bpp
mov [_display.bytes_per_pixel], 4 ; Conversion buffer is 32 bpp
jmp .finish
 
.16bpp:
mov [PUTPIXEL], Vesa20_putpixel16
mov [GETPIXEL], Vesa20_getpixel16
mov [_display.bytes_per_pixel], 2
jmp .finish
 
.24bpp:
mov [PUTPIXEL], Vesa20_putpixel24
mov [GETPIXEL], Vesa20_getpixel24
mov [_display.bytes_per_pixel], 3
jmp .finish
 
.32bpp:
mov [PUTPIXEL], Vesa20_putpixel32
mov [GETPIXEL], Vesa20_getpixel32
mov [_display.bytes_per_pixel], 4
 
.finish:
mov [MOUSE_PICTURE], mousepointer
mov [_display.check_mouse], check_mouse_area_for_putpixel
mov [_display.check_m_pixel], check_mouse_area_for_getpixel
 
mov ax, word [SCR_MODE]
cmp ax, 0x0012
je .fake
cmp ax, 0x0013
je .fake
 
mov esi, [LFBAddress]
bt [cpu_caps], CAPS_PSE
jnc .create_page_tables
 
mov edx, 0x00400000
or esi, PG_GLOBAL+PAT_WC+PG_UWR
and esi, [pte_valid_mask]
or esi, PDE_LARGE
mov [ebp+FRB.pde], esi
add esi, edx
mov [ebp+FRB.pde+4], esi
add esi, edx
mov [ebp+FRB.pde+8], esi
add esi, edx
mov [ebp+FRB.pde+12], esi
add esi, edx
.ok:
call calculate_fast_getting_offset_for_WinMapAddress
; for Qemu or non standart video cards
; Unfortunately [BytesPerScanLine] does not always
; equal to [_display.width] * [ScreenBPP] / 8
call calculate_fast_getting_offset_for_LFB
ret
 
.create_page_tables:
 
add ebp, FRB.pde
or esi, PG_GLOBAL+PAT_WC+PG_UWR
and esi, [pte_valid_mask]
 
stdcall alloc_kernel_space, 0x1000
mov edi, eax
mov ebx, 4
 
.new_pd:
call alloc_page
lea edx, [eax+PG_UWR]
mov [ebp], edx
 
stdcall map_page, edi, eax, PG_SWR
 
mov eax, esi
mov ecx, 1024
@@:
stosd
add eax, 0x1000
loop @B
 
add esi, 0x400000
add ebp, 4
sub edi, 4096
dec ebx
jnz .new_pd
stdcall free_kernel_space, edi
jmp .ok
 
.fake:
mov [BOOT.mtrr], byte 2
 
stdcall alloc_kernel_space, 0x1000
push eax ;store in stack for subsequent
mov edi, eax ;free_kernel_space call
 
call alloc_page
lea edx, [eax+PG_UWR]
mov [ebp+FRB.pde], edx
 
stdcall map_page, edi, eax, PG_SWR
 
; max VGA=640*480*4=1228800 bytes
; + 32*640*4=81920 bytes for mouse pointer
stdcall alloc_pages, ((1228800+81920)/4096)
or eax, PG_GLOBAL+PG_UWR
and eax, [pte_valid_mask]
mov ecx, (1228800+81920)/4096
@@:
stosd
add eax, 0x1000
loop @B
 
call free_kernel_space
jmp .ok
 
align 4
set_framebuffer:
push esi
push edi
lea esi, [ecx+FRB.pde]
mov eax, sys_proc
 
cld
pushfd
cli
mov [_display.current_lfb], ecx
.patch_pde:
lea edi, [eax+PROC.pdt_0+4096-32] ;last 8 pd entries up to 32Mb framebuffer
mov ecx, 4
rep movsd ;patch pde
sub esi, 16
mov eax, [eax+PROC.list.next] ;next process/address space
cmp eax, sys_proc
jne .patch_pde
 
bt [cpu_caps], CAPS_PGE
jnc .cr3_flush
 
mov eax, cr4
btr eax, 7 ;clear cr4.PGE
mov cr4, eax ;flush TLB
bts eax, 7
mov cr4, eax ;flush TLB
.exit:
popfd
pop edi
pop esi
ret
 
.cr3_flush:
mov eax, cr3
mov cr3, eax ;flush TLB
jmp .exit
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video/vga.inc
0,0 → 1,534
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; VGA.INC ;;
;; ;;
;; 640x480 mode 0x12 VGA functions for MenuetOS ;;
;; ;;
;; Paul Butcher, paul.butcher@asa.co.uk ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
;------------------------------------------------------------------------------
align 4
paletteVGA:
 
;16 colour palette
mov dx, 0x3c8
mov al, 0
out dx, al
 
mov ecx, 16
mov dx, 0x3c9
xor eax, eax
;--------------------------------------
align 4
palvganew:
mov al, 0
test ah, 4
jz palvgalbl1
add al, 31
test ah, 8
jz palvgalbl1
add al, 32
;--------------------------------------
align 4
palvgalbl1:
out dx, al; red 0,31 or 63
mov al, 0
test ah, 2
jz palvgalbl2
add al, 31
test ah, 8
jz palvgalbl2
add al, 32
;--------------------------------------
align 4
palvgalbl2:
out dx, al; blue 0,31 or 63
mov al, 0
test ah, 1
jz palvgalbl3
add al, 31
test ah, 8
jz palvgalbl3
add al, 32
;--------------------------------------
align 4
palvgalbl3:
out dx, al; green 0,31 or 63
add ah, 1
loop palvganew
; mov dx, 3ceh
; mov ax, 0005h
; out dx, ax
ret
;------------------------------------------------------------------------------
align 4
palette320x200:
mov edx, 0x3c8
xor eax, eax
out dx, al
mov ecx, 256
mov edx, 0x3c9
xor eax, eax
;--------------------------------------
align 4
palnew:
mov al, 0
test ah, 64
jz pallbl1
add al, 21
;--------------------------------------
align 4
pallbl1:
test ah, 128
jz pallbl2
add al, 42
;--------------------------------------
align 4
pallbl2:
out dx, al
mov al, 0
test ah, 8
jz pallbl3
add al, 8
;--------------------------------------
align 4
pallbl3:
test ah, 16
jz pallbl4
add al, 15
;--------------------------------------
align 4
pallbl4:
test ah, 32
jz pallbl5
add al, 40
;--------------------------------------
align 4
pallbl5:
out dx, al
mov al, 0
test ah, 1
jz pallbl6
add al, 8
;--------------------------------------
align 4
pallbl6:
test ah, 2
jz pallbl7
add al, 15
;--------------------------------------
align 4
pallbl7:
test ah, 4
jz pallbl8
add al, 40
;--------------------------------------
align 4
pallbl8:
out dx, al
add ah, 1
loop palnew
ret
;------------------------------------------------------------------------------
align 4
uglobal
novesachecksum dd 0x0
EGA_counter db 0
VGA_drawing_screen db 0
VGA_8_pixels:
rb 16
temp:
.cx dd 0
endg
;------------------------------------------------------------------------------
align 4
checkVga_N13:
cmp [SCR_MODE], 0x13
jne @f
 
pushad
cmp [EGA_counter], 1
je novesal
mov ecx, [MOUSE_X]
cmp ecx, [novesachecksum]
jne novesal
popad
;--------------------------------------
align 4
@@:
ret
;--------------------------------------
align 4
novesal:
mov [novesachecksum], ecx
mov ecx, 0
movzx eax, word [MOUSE_Y]
cmp eax, 100
jge m13l3
mov eax, 100
;--------------------------------------
align 4
m13l3:
cmp eax, 480-100
jbe m13l4
mov eax, 480-100
;--------------------------------------
align 4
m13l4:
sub eax, 100
imul eax, 640*4
add ecx, eax
movzx eax, word [MOUSE_X]
cmp eax, 160
jge m13l1
mov eax, 160
;--------------------------------------
align 4
m13l1:
cmp eax, 640-160
jbe m13l2
mov eax, 640-160
;--------------------------------------
align 4
m13l2:
sub eax, 160
shl eax, 2
add ecx, eax
mov esi, [LFBAddress]
add esi, ecx
mov edi, VGABasePtr
mov edx, 200
mov ecx, 320
cld
;--------------------------------------
align 4
m13pix:
lodsd
test eax, eax
jz .save_pixel
push eax
mov ebx, eax
and eax, (128+64+32) ; blue
shr eax, 5
and ebx, (128+64+32)*256; green
shr ebx, 8+2
add eax, ebx
pop ebx
and ebx, (128+64)*256*256; red
shr ebx, 8+8
add eax, ebx
;--------------------------------------
align 4
.save_pixel:
stosb
loop m13pix
mov ecx, 320
add esi, 4*(640-320)
dec edx
jnz m13pix
mov [EGA_counter], 0
popad
ret
;------------------------------------------------------------------------------
align 4
VGA_drawbackground:
; draw all
pushad
mov esi, [LFBAddress]
mov edi, VGABasePtr
mov ebx, 640/32; 640*480/(8*4)
mov edx, 480
;--------------------------------------
align 4
@@:
push ebx edx esi edi
shl edx, 9
lea edx, [edx+edx*4]
add esi, edx
shr edx, 5
add edi, edx
call VGA_draw_long_line
pop edi esi edx ebx
dec edx
jnz @r
call VGA_draw_long_line_1
popad
ret
;------------------------------------------------------------------------------
align 4
VGA_draw_long_line:
mov dx, 3ceh
mov ax, 0ff08h
cli
out dx, ax
mov ax, 0005h
out dx, ax
;--------------------------------------
align 4
m12pix:
call VGA_draw_32_pixels
dec ebx
jnz m12pix
mov dx, 3c4h
mov ax, 0ff02h
out dx, ax
mov dx, 3ceh
mov ax, 0205h
out dx, ax
mov dx, 3ceh
mov al, 08h
out dx, al
sti
ret
;------------------------------------------------------------------------------
align 4
VGA_draw_32_pixels:
xor eax, eax
mov ebp, VGA_8_pixels
mov [ebp], eax
mov [ebp+4], eax
mov [ebp+8], eax
mov [ebp+12], eax
mov ch, 4
;--------------------------------------
align 4
.main_loop:
mov cl, 8
;--------------------------------------
align 4
.convert_pixels_to_VGA:
lodsd ; eax = 24bit colour
test eax, eax
jz .end
rol eax, 8
mov al, ch
ror eax, 8
mov ch, 1
dec cl
shl ch, cl
cmp al, 85
jbe .p13green
or [ebp], ch
cmp al, 170
jbe .p13green
or [ebp+12], ch
;--------------------------------------
align 4
.p13green:
cmp ah, 85
jbe .p13red
or [ebp+4], ch
cmp ah, 170
jbe .p13red
or [ebp+12], ch
;--------------------------------------
align 4
.p13red:
shr eax, 8
cmp ah, 85
jbe .p13cont
or [ebp+8], ch
cmp ah, 170
jbe .p13cont
or [ebp+12], ch
;--------------------------------------
align 4
.p13cont:
ror eax, 8
mov ch, ah
inc cl
;--------------------------------------
align 4
.end:
dec cl
jnz .convert_pixels_to_VGA
inc ebp
dec ch
jnz .main_loop
push esi
sub ebp, 4
mov esi, ebp
mov dx, 3c4h
mov ah, 1h
;--------------------------------------
align 4
@@:
mov al, 02h
out dx, ax
xchg ax, bp
lodsd
mov [edi], eax
xchg ax, bp
shl ah, 1
cmp ah, 10h
jnz @r
add edi, 4
pop esi
ret
;------------------------------------------------------------------------------
align 4
VGA_putpixel:
; eax = x
; ebx = y
mov ecx, eax
mov eax, [esp+32-8+4] ; color
;--------------------------------------
; check for hardware cursor
cmp [_display.select_cursor], select_cursor
je @f
cmp [_display.select_cursor], 0
jne .no_mouseunder
;--------------------------------------
align 4
@@:
push ecx
shl ecx, 16
mov cx, bx
; check mouse area for putpixel
test eax, 0x04000000
jnz @f
call [_display.check_mouse]
;--------------------------------------
align 4
@@:
pop ecx
;--------------------------------------
align 4
.no_mouseunder:
shl ebx, 9
lea ebx, [ebx+ebx*4] ; multiply by 5
lea edx, [ebx+ecx*4] ; + x*BytesPerPixel (Vesa2.0 32)
mov edi, edx
add edi, [LFBAddress] ; + LFB address
mov [edi], eax ; write to LFB for Vesa2.0
shr edx, 5 ; change BytesPerPixel to 1/8
mov edi, edx
add edi, VGABasePtr ; address of pixel in VGA area
and ecx, 0x07 ; bit no. (modulo 8)
pushfd
; edi = address, eax = 24bit colour, ecx = bit no. (modulo 8)
xor edx, edx
test eax, eax
jz .p13cont
cmp al, 85
jbe .p13green
or dl, 0x01
cmp al, 170
jbe .p13green
or dl, 0x08
;--------------------------------------
align 4
.p13green:
cmp ah, 85
jbe .p13red
or dl, 0x02
cmp ah, 170
jbe .p13red
or dl, 0x08
;--------------------------------------
align 4
.p13red:
shr eax, 8
cmp ah, 85
jbe .p13cont
or dl, 0x04
cmp ah, 170
jbe .p13cont
or dl, 0x08
;--------------------------------------
align 4
.p13cont:
ror edx, 8
inc cl
xor eax, eax
inc ah
shr ax, cl
mov dx, 3cfh
cli
out dx, al
mov al, [edi] ; dummy read
rol edx, 8
mov [edi], dl
popfd
ret
;------------------------------------------------------------------------------
align 4
VGA__putimage:
; ecx = size [x|y]
; edx = coordinates [x|y]
pushad
rol edx, 16
movzx eax, dx
rol edx, 16
movzx ebx, dx
movzx edx, cx
rol ecx, 16
movzx ecx, cx
call VGA_draw_bar_1
popad
ret
;------------------------------------------------------------------------------
align 4
VGA_draw_bar:
; eax cx
; ebx cy
; ecx xe
; edx ye
pushad
sub ecx, eax
sub edx, ebx
and eax, 0xffff
and ebx, 0xffff
and ecx, 0xffff
and edx, 0xffff
call VGA_draw_bar_1
popad
ret
;------------------------------------------------------------------------------
align 4
VGA_draw_bar_1:
mov [temp.cx], eax
mov eax, [TASK_BASE]
add ebx, [eax-twdw + 4]
mov eax, [eax-twdw + 0]
add eax, [temp.cx]
and eax, 0xfff8
shl ebx, 9
lea ebx, [ebx+ebx*4] ; multiply by 5
lea ebx, [ebx+eax*4] ; + x*BytesPerPixel (Vesa2.0 32)
mov esi, ebx
add esi, [LFBAddress] ; + LFB address
shr ebx, 5 ; change BytesPerPixel to 1/8
mov edi, ebx
add edi, VGABasePtr ; address of pixel in VGA area
mov ebx, ecx
shr ebx, 5
inc ebx
;--------------------------------------
align 4
.main_loop:
call VGA_draw_long_line_1
dec edx
jnz .main_loop
call VGA_draw_long_line_1
ret
;------------------------------------------------------------------------------
align 4
VGA_draw_long_line_1:
push ebx edx esi edi
shl edx, 9
lea edx, [edx+edx*4]
add esi, edx
shr edx, 5
add edi, edx
call VGA_draw_long_line
pop edi esi edx ebx
ret
;------------------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video/vesa12.inc
0,0 → 1,1004
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; VESA12.INC ;;
;; ;;
;; Vesa 1.2 functions for MenuetOS ;;
;; ;;
;; Copyright 2002 Ville Turjanmaa ;;
;; ;;
;; quickcode@mail.ru - bankswitch for S3 cards ;;
;; ;;
;; See file COPYING for details ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
TRIDENT = 0
S3_VIDEO = 0
INTEL_VIDEO = 0
 
if TRIDENT
if S3_VIDEO or INTEL_VIDEO
stop
end if
end if
 
if S3_VIDEO
if TRIDENT or INTEL_VIDEO
stop
end if
end if
 
if INTEL_VIDEO
if S3_VIDEO or TRIDENT
stop
end if
end if
 
 
; A complete video driver should include the following types of function
;
; Putpixel
; Getpixel
;
; Drawimage
; Drawbar
;
; Drawbackground
;
;
; Modifying the set_bank -function is mostly enough
; for different Vesa 1.2 setups.
 
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; set_bank for Trident videocards, work on Trident 9440
; modified by Mario79
 
if TRIDENT
set_bank:
pushfd
cli
cmp al, [BANK_RW]
je .retsb
 
mov [BANK_RW], al
push dx
mov dx, 3D8h
out dx, al
pop dx
.retsb:
popfd
ret
end if
 
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; set_bank for S3 videocards, work on S3 ViRGE PCI (325)
; modified by kmeaw
 
if S3_VIDEO
set_bank:
pushfd
cli
cmp al, [BANK_RW]
je .retsb
 
mov [BANK_RW], al
push ax
push dx
push cx
mov cl, al
mov dx, 0x3D4
mov al, 0x38
out dx, al ;CR38 Register Lock 1 ;Note: Traditionally 48h is used to
;unlock and 00h to lock
inc dx
mov al, 0x48
out dx, al ;3d5 -?
dec dx
mov al, 0x31
out dx, al ;CR31 Memory Configuration Register
;0 Enable Base Address Offset (CPUA BASE). Enables bank operation if set, ;disables if clear.
;4-5 Bit 16-17 of the Display Start Address. For the 801/5,928 see index 51h,
;for the 864/964 see index 69h.
 
inc dx
in al, dx
dec dx
mov ah, al
mov al, 0x31
out dx, ax
mov al, ah
or al, 9
inc dx
out dx, al
dec dx
mov al, 0x35
out dx, al ;CR35 CRT Register Lock
inc dx
in al, dx
dec dx
and al, 0xF0
mov ch, cl
and ch, 0x0F
or ch, al
mov al, 0x35
out dx, al
inc dx
mov al, ch
out dx, ax
dec dx
mov al, 0x51 ;Extended System Control 2 Register
out dx, al
inc dx
in al, dx
dec dx
and al, 0xF3
shr cl, 2
and cl, 0x0C
or cl, al
mov al, 0x51
out dx, al
inc dx
mov al, cl
out dx, al
dec dx
mov al, 0x38
out dx, al
inc dx
xor al, al
out dx, al
dec dx
pop cx
pop dx
pop ax
.retsb:
popfd
ret
end if
 
;Set bank function for Intel 810/815 chipsets
; *****Modified by Protopopius, Russia.*****
; ********* http://menuetos.hut.ru **************
; ************************************************
 
if INTEL_VIDEO
 
set_bank:
pushfd
cli
 
cmp al, [BANK_RW]
je .retsb
 
mov [BANK_RW], al
push ax
push dx
mov dx, 3CEh
mov ah, al ; Save value for later use
mov al, 10h ; Index GR10 (Address Mapping)
out dx, al ; Select GR10
inc dl
mov al, 3 ; Set bits 0 and 1 (Enable linear page mapping)
out dx, al ; Write value
dec dl
mov al, 11h ; Index GR11 (Page Selector)
out dx, al ; Select GR11
inc dl
mov al, ah ; Write address
out dx, al ; Write the value
pop dx
pop ax
.retsb:
popfd
ret
end if
 
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!}
 
if (TRIDENT or S3_VIDEO or INTEL_VIDEO)
else
set_bank:
pushfd
cli
 
cmp al, [BANK_RW]
je .retsb
 
mov [BANK_RW], al
push ax
push dx
mov ah, al
mov dx, 0x03D4
mov al, 0x39
out dx, al
inc dl
mov al, 0xA5
out dx, al
dec dl
mov al, 6Ah
out dx, al
inc dl
mov al, ah
out dx, al
dec dl
mov al, 0x39
out dx, al
inc dl
mov al, 0x5A
out dx, al
dec dl
pop dx
pop ax
 
.retsb:
popfd
ret
end if
 
vesa12_drawbackground:
 
call [_display.disable_mouse]
 
push eax
push ebx
push ecx
push edx
 
xor edx, edx
mov eax, dword[BgrDataWidth]
mov ebx, dword[BgrDataHeight]
mul ebx
mov ebx, 3
mul ebx
mov [imax], eax
mov eax, [draw_data+32+RECT.left]
mov ebx, [draw_data+32+RECT.top]
xor edi, edi;no force
 
v12dp3:
 
push eax
push ebx
 
cmp [BgrDrawMode], dword 1 ; tiled background
jne no_vesa12_tiled_bgr
 
push edx
 
xor edx, edx
div dword [BgrDataWidth]
 
push edx
mov eax, ebx
xor edx, edx
div dword [BgrDataHeight]
mov ebx, edx
pop eax
 
pop edx
 
no_vesa12_tiled_bgr:
 
cmp [BgrDrawMode], dword 2 ; stretched background
jne no_vesa12_stretched_bgr
 
push edx
 
mul dword [BgrDataWidth]
mov ecx, [Screen_Max_X]
inc ecx
div ecx
 
push eax
mov eax, ebx
mul dword [BgrDataHeight]
mov ecx, [Screen_Max_Y]
inc ecx
div ecx
mov ebx, eax
pop eax
 
pop edx
 
no_vesa12_stretched_bgr:
 
 
mov esi, ebx
imul esi, dword [BgrDataWidth]
add esi, eax
lea esi, [esi*3]
add esi, [img_background];IMG_BACKGROUND
pop ebx
pop eax
 
v12di4:
 
mov cl, [esi+2]
shl ecx, 16
mov cx, [esi]
pusha
mov esi, eax
mov edi, ebx
mov eax, [Screen_Max_X]
add eax, 1
mul ebx
add eax, [_WinMapAddress]
cmp [eax+esi], byte 1
jnz v12nbgp
mov eax, [BytesPerScanLine]
mov ebx, edi
mul ebx
add eax, esi
lea eax, [VGABasePtr+eax+esi*2]
cmp [ScreenBPP], byte 24
jz v12bgl3
add eax, esi
 
v12bgl3:
 
push ebx
push eax
 
sub eax, VGABasePtr
 
shr eax, 16
call set_bank
pop eax
and eax, 65535
add eax, VGABasePtr
pop ebx
 
mov [eax], cx
add eax, 2
shr ecx, 16
mov [eax], cl
sti
 
v12nbgp:
 
popa
add esi, 3
inc eax
cmp eax, [draw_data+32+RECT.right]
jg v12nodp31
jmp v12dp3
 
v12nodp31:
 
mov eax, [draw_data+32+RECT.left]
inc ebx
cmp ebx, [draw_data+32+RECT.bottom]
jg v12dp4
jmp v12dp3
 
v12dp4:
 
pop edx
pop ecx
pop ebx
pop eax
ret
 
 
vesa12_drawbar:
 
call [_display.disable_mouse]
 
;; mov [novesachecksum],dword 0
sub edx, ebx
sub ecx, eax
push esi
push edi
push eax
push ebx
push ecx
push edx
mov ecx, [TASK_BASE]
add eax, [ecx-twdw+WDATA.box.left]
add ebx, [ecx-twdw+WDATA.box.top]
push eax
mov eax, ebx ; y
mov ebx, [BytesPerScanLine]
mul ebx
pop ecx
add eax, ecx ; x
add eax, ecx
add eax, ecx
cmp [ScreenBPP], byte 24; 24 or 32 bpp ? - x start
jz dbpi2412
add eax, ecx
 
dbpi2412:
 
add eax, VGABasePtr
mov edi, eax
 
; x size
 
mov eax, [esp+4]; [esp+6]
mov ecx, eax
add ecx, eax
add ecx, eax
cmp [ScreenBPP], byte 24; 24 or 32 bpp ? - x size
jz dbpi24312
add ecx, eax
 
dbpi24312:
 
mov ebx, [esp+0]
 
; check limits ?
 
push eax
push ecx
mov eax, [TASK_BASE]
mov ecx, [eax+draw_data-CURRENT_TASK+RECT.left]
cmp ecx, 0
jnz dbcblimitlset12
mov ecx, [eax+draw_data-CURRENT_TASK+RECT.top]
cmp ecx, 0
jnz dbcblimitlset12
mov ecx, [eax+draw_data-CURRENT_TASK+RECT.right]
cmp ecx, [Screen_Max_X]
jnz dbcblimitlset12
mov ecx, [eax+draw_data-CURRENT_TASK+RECT.bottom]
cmp ecx, [Screen_Max_Y]
jnz dbcblimitlset12
pop ecx
pop eax
push dword 0
jmp dbcblimitlno12
 
dbcblimitlset12:
 
pop ecx
pop eax
push dword 1
 
dbcblimitlno12:
 
cmp [ScreenBPP], byte 24; 24 or 32 bpp ?
jz dbpi24bit12
jmp dbpi32bit12
 
 
; DRAWBAR 24 BBP
 
 
dbpi24bit12:
 
push eax
push ebx
push edx
mov eax, ecx
mov ebx, 3
div ebx
mov ecx, eax
pop edx
pop ebx
pop eax
cld
 
dbnewpi12:
 
push ebx
push edi
push ecx
 
xor edx, edx
mov eax, edi
sub eax, VGABasePtr
mov ebx, 3
div ebx
add eax, [_WinMapAddress]
mov ebx, [CURRENT_TASK]
cld
 
dbnp2412:
 
mov dl, [eax]
push eax
push ecx
cmp dl, bl
jnz dbimp24no12
cmp [esp+5*4], dword 0
jz dbimp24yes12
; call dbcplimit
; jnz dbimp24no12
 
dbimp24yes12:
 
push edi
mov eax, edi
sub eax, VGABasePtr
shr eax, 16
call set_bank
and edi, 0xffff
add edi, VGABasePtr
mov eax, [esp+8+3*4+16+4+4]
stosw
shr eax, 16
stosb
sti
pop edi
add edi, 3
pop ecx
pop eax
inc eax
loop dbnp2412
jmp dbnp24d12
 
dbimp24no12:
 
pop ecx
pop eax
cld
add edi, 3
inc eax
loop dbnp2412
 
dbnp24d12:
 
mov eax, [esp+3*4+16+4]
test eax, 0x80000000
jz nodbgl2412
cmp al, 0
jz nodbgl2412
dec eax
mov [esp+3*4+16+4], eax
 
nodbgl2412:
 
pop ecx
pop edi
pop ebx
add edi, [BytesPerScanLine]
dec ebx
jz dbnonewpi12
jmp dbnewpi12
 
dbnonewpi12:
 
add esp, 7*4
 
ret
 
 
; DRAWBAR 32 BBP
 
 
dbpi32bit12:
 
cld
shr ecx, 2
 
dbnewpi3212:
 
push ebx
push edi
push ecx
 
mov eax, edi
sub eax, VGABasePtr
shr eax, 2
add eax, [_WinMapAddress]
mov ebx, [CURRENT_TASK]
cld
 
dbnp3212:
 
mov dl, [eax]
push eax
push ecx
cmp dl, bl
jnz dbimp32no12
cmp [esp+5*4], dword 0
jz dbimp32yes12
; call dbcplimit
; jnz dbimp32no12
 
dbimp32yes12:
 
push edi
mov eax, edi
sub eax, VGABasePtr
shr eax, 16
call set_bank
and edi, 0xffff
add edi, VGABasePtr
mov eax, [esp+8+3*4+16+4+4]
stosw
shr eax, 16
stosb
sti
pop edi
add edi, 4
inc ebp
pop ecx
pop eax
inc eax
loop dbnp3212
jmp dbnp32d12
 
dbimp32no12:
 
pop ecx
pop eax
inc eax
add edi, 4
inc ebp
loop dbnp3212
 
dbnp32d12:
 
mov eax, [esp+12+16+4]
test eax, 0x80000000
jz nodbgl3212
cmp al, 0
jz nodbgl3212
dec eax
mov [esp+12+16+4], eax
 
nodbgl3212:
 
pop ecx
pop edi
pop ebx
add edi, [BytesPerScanLine]
dec ebx
jz nodbnewpi3212
jmp dbnewpi3212
 
nodbnewpi3212:
 
add esp, 7*4
ret
 
 
Vesa12_putpixel24:
 
mov edi, eax; x
mov eax, ebx; y
lea edi, [edi+edi*2]
mov ebx, [BytesPerScanLine]
mul ebx
add edi, eax
mov eax, edi
shr eax, 16
call set_bank
and edi, 65535
add edi, VGABasePtr
mov eax, [esp+28]
stosw
shr eax, 16
mov [edi], al
sti
ret
 
 
 
Vesa12_putpixel32:
 
mov edi, eax; x
mov eax, ebx; y
shl edi, 2
mov ebx, [BytesPerScanLine]
mul ebx
add edi, eax
mov eax, edi
shr eax, 16
call set_bank
and edi, 65535
add edi, VGABasePtr
mov ecx, [esp+28]
mov [edi], ecx
sti
ret
 
 
Vesa12_getpixel24:
 
mov edi, eax; x
mov eax, ebx; y
lea edi, [edi+edi*2]
mov ebx, [BytesPerScanLine]
mul ebx
add edi, eax
mov eax, edi
shr eax, 16
call set_bank
and edi, 65535
add edi, VGABasePtr
mov ecx, [edi]
and ecx, 255*256*256+255*256+255
sti
ret
 
 
Vesa12_getpixel32:
 
mov edi, eax; x
mov eax, ebx; y
shl edi, 2
mov ebx, [BytesPerScanLine]
xor edx, edx
mul ebx
add edi, eax
mov eax, edi
shr eax, 16
call set_bank
and edi, 65535
add edi, VGABasePtr
mov ecx, [edi]
and ecx, 255*256*256+255*256+255
sti
 
ret
 
 
 
vesa12_putimage:
; ebx = pointer to image
; ecx = size [x|y]
; edx = coordinates [x|y]
; ebp = pointer to 'get' function
; esi = pointer to 'init' function
; edi = parameter for 'get' function
 
; mov ebx,image
; mov ecx,320*65536+240
; mov edx,20*65536+20
 
call [_display.disable_mouse]
 
mov [novesachecksum], dword 0
push esi
push edi
push eax
push ebx
push ecx
push edx
movzx eax, word [esp+2]
movzx ebx, word [esp+0]
mov ecx, [TASK_BASE]
add eax, [ecx-twdw+WDATA.box.left]
add ebx, [ecx-twdw+WDATA.box.top]
push eax
mov eax, ebx ; y
mul dword [BytesPerScanLine]
pop ecx
add eax, ecx ; x
add eax, ecx
add eax, ecx
cmp [ScreenBPP], byte 24; 24 or 32 bpp ? - x start
jz pi2412
add eax, ecx
 
pi2412:
 
add eax, VGABasePtr
mov edi, eax
 
; x size
 
movzx ecx, word [esp+6]
 
mov esi, [esp+8]
movzx ebx, word [esp+4]
 
; check limits while draw ?
 
push ecx
mov eax, [TASK_BASE]
cmp dword [eax+draw_data-CURRENT_TASK+RECT.left], 0
jnz dbcblimitlset212
cmp dword [eax+draw_data-CURRENT_TASK+RECT.top], 0
jnz dbcblimitlset212
mov ecx, [eax+draw_data-CURRENT_TASK+RECT.right]
cmp ecx, [Screen_Max_X]
jnz dbcblimitlset212
mov ecx, [eax+draw_data-CURRENT_TASK+RECT.bottom]
cmp ecx, [Screen_Max_Y]
jnz dbcblimitlset212
pop ecx
push 0
jmp dbcblimitlno212
 
dbcblimitlset212:
 
pop ecx
push 1
 
dbcblimitlno212:
 
cmp [ScreenBPP], byte 24; 24 or 32 bpp ?
jnz pi32bit12
 
pi24bit12:
 
newpi12:
 
push edi
push ecx
push ebx
 
mov edx, edi
sub edx, VGABasePtr
mov ebx, 3
div ebx
add edx, [_WinMapAddress]
mov ebx, [CURRENT_TASK]
mov bh, [esp+4*3]
 
np2412:
 
cmp bl, [edx]
jnz imp24no12
; mov eax,[esi]
push dword [esp+4*3+20]
call ebp
; cmp bh,0
; jz imp24yes12
; call dbcplimit
; jnz imp24no12
 
imp24yes12:
 
push edi
push eax
mov eax, edi
sub eax, VGABasePtr
shr eax, 16
call set_bank
pop eax
and edi, 0xffff
add edi, VGABasePtr
mov [edi], ax
shr eax, 16
mov [edi+2], al
pop edi
 
imp24no12:
 
inc edx
; add esi,3
add edi, 3
dec ecx
jnz np2412
 
np24d12:
 
pop ebx
pop ecx
pop edi
 
add edi, [BytesPerScanLine]
add esi, [esp+32]
cmp ebp, putimage_get1bpp
jz .correct
cmp ebp, putimage_get2bpp
jz .correct
cmp ebp, putimage_get4bpp
jnz @f
.correct:
mov eax, [esp+20]
mov byte[eax], 80h
@@:
dec ebx
jnz newpi12
 
nonewpi12:
 
pop eax edx ecx ebx eax edi esi
xor eax, eax
ret
 
 
pi32bit12:
 
newpi3212:
 
push edi
push ecx
push ebx
 
mov edx, edi
sub edx, VGABasePtr
shr edx, 2
add edx, [_WinMapAddress]
mov ebx, [CURRENT_TASK]
mov bh, [esp+4*3]
 
np3212:
 
cmp bl, [edx]
jnz imp32no12
; mov eax,[esi]
push dword [esp+4*3+20]
call ebp
; cmp bh,0
; jz imp32yes12
; call dbcplimit
; jnz imp32no12
 
imp32yes12:
 
push edi
push eax
mov eax, edi
sub eax, VGABasePtr
shr eax, 16
call set_bank
pop eax
and edi, 0xffff
mov [edi+VGABasePtr], eax
pop edi
 
imp32no12:
 
inc edx
; add esi,3
add edi, 4
dec ecx
jnz np3212
 
np32d12:
 
pop ebx
pop ecx
pop edi
 
add edi, [BytesPerScanLine]
cmp ebp, putimage_get1bpp
jz .correct
cmp ebp, putimage_get2bpp
jz .correct
cmp ebp, putimage_get4bpp
jnz @f
.correct:
mov eax, [esp+20]
mov byte[eax], 80h
@@:
dec ebx
jnz newpi3212
 
nonewpi3212:
 
pop eax edx ecx ebx eax edi esi
xor eax, eax
ret
 
 
vesa12_read_screen_pixel:
 
and eax, 0x3FFFFF
cmp [ScreenBPP], byte 24; 24 or 32 bpp ?
jz v12rsp24
mov edi, eax
shl edi, 2
mov eax, edi
shr eax, 16
call set_bank
and edi, 65535
add edi, VGABasePtr
mov eax, [edi]
and eax, 0x00ffffff
ret
v12rsp24:
 
imul eax, 3
mov edi, eax
shr eax, 16
call set_bank
and edi, 65535
add edi, VGABasePtr
mov eax, [edi]
and eax, 0x00ffffff
ret
 
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video/arrow.cur
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video/arrow_clock.cur
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/video
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/bootloader/uefi4kos/kolibri.ini
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
 
/kernel/branches/kolibrios-pe-clevermouse/bootloader/uefi4kos/uefi64kos.asm
0,0 → 1,1249
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 pe64 efi
entry main
 
section '.text' code executable readable
 
include '../../struct.inc'
include '../../macros.inc'
include '../../const.inc'
 
purge DQ
include 'uefi64.inc'
 
MEMORY_MAP_SIZE = 0x10000
GOP_BUFFER_SIZE = 0x100
LIP_BUFFER_SIZE = 0x100
FILE_BUFFER_SIZE = 0x1000
 
KERNEL_TRAMPOLINE = 0x8f80 ; just before BOOT_LO
KERNEL_BASE = 0x10000
RAMDISK_BASE = 0x100000
MAX_FILE_SIZE = 0x10000000
 
CODE_32_SELECTOR = 8
DATA_32_SELECTOR = 16
CODE_64_SELECTOR = 24
 
; 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
 
load_file:
virtual at rsp+8
.root dq ?
.name dq ?
.buffer dq ?
.size dq ?
.fatal dq ?
end virtual
eficall [.root], EFI_FILE_PROTOCOL.Open, [.root], file_handle, \
[.name], EFI_FILE_MODE_READ, 0
test eax, eax
jz @f
xor eax, eax
cmp [.fatal], 1
jnz .done
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error_open_file
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
[.name]
jmp $
@@:
 
lea rax, [.size]
eficall [file_handle], EFI_FILE_PROTOCOL.Read, [file_handle], rax, \
[.buffer]
eficall [file_handle], EFI_FILE_PROTOCOL.Close, [file_handle]
mov rax, [.size]
.done:
push rax
call clearbuf
mov rdi, msg
call num2dec
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_file_size
pop rbx
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
pop rbx
pop rax
ret 8*5
 
skip_whitespace:
.next_char:
cmp byte[rsi], 0
jz .done
cmp byte[rsi], 0x20 ; ' '
jz .whitespace
cmp byte[rsi], 9 ; '\t'
jz .whitespace
jmp .done
.whitespace:
inc rsi
jmp .next_char
.done:
ret
 
skip_until_newline:
.next_char:
cmp byte[rsi], 0
jz .done
cmp byte[rsi], 0xd ; '\r'
jz .done
cmp byte[rsi], 0xa ; '\n'
jz .done
inc rsi
jmp .next_char
.done:
ret
 
skip_newline:
.next_char:
cmp byte[rsi], 0xd ; '\r'
jz .newline
cmp byte[rsi], 0xa ; '\n'
jz .newline
jmp .done
.newline:
inc rsi
jmp .next_char
.done:
ret
 
skip_line:
call skip_until_newline
call skip_newline
ret
 
dec2bin:
mov edx, 0
.next_char:
movzx eax, byte[rsi]
test eax, eax
jz .done
sub eax, '0'
jb .done
cmp eax, 9
ja .done
inc rsi
imul edx, 10
add edx, eax
jmp .next_char
.done:
mov eax, edx
ret
 
parse_option:
mov rbx, config_options-3*8
.try_next_option:
add rbx, 3*8
mov rdi, rsi
mov rdx, [rbx] ; option name
test rdx, rdx
jz .done
.next_char:
cmp byte[rdx], 0
jnz @f
cmp byte[rdi], '='
jz .opt_name_ok
@@:
cmp byte[rdi], 0
jz .done
movzx eax, byte[rdi]
cmp [rdx], al
jnz .try_next_option
inc rdi
inc rdx
jmp .next_char
.opt_name_ok:
inc rdi
mov rsi, rdi
call qword[rbx+8]
.done:
ret
 
parse_line:
.next_line:
cmp byte[rsi], 0
jz .done
cmp byte[rsi], 0xd ; '\r'
jz .skip
cmp byte[rsi], 0xa ; '\n'
jz .skip
cmp byte[rsi], '#'
jz .skip
call parse_option
call skip_line
jmp .next_line
.skip:
call skip_line
jmp .next_line
.done:
ret
 
cfg_opt_func_resolution:
call dec2bin
xor edx, edx
mov [rdx+BOOT_LO.x_res], ax
cmp byte[rsi], 'x'
jz @f
cmp byte[rsi], '*'
jz @f
jmp .done
@@:
inc rsi
call dec2bin
xor edx, edx
mov [rdx+BOOT_LO.y_res], ax
mov [cfg_opt_used_resolution], 1
.done:
ret
 
cfg_opt_func_acpi:
call dec2bin
mov [cfg_opt_used_acpi], 1
mov [cfg_opt_value_acpi], al
ret
 
cfg_opt_func_debug_print:
call dec2bin
mov [cfg_opt_used_debug_print], 1
mov [cfg_opt_value_debug_print], al
ret
 
cfg_opt_func_launcher_start:
call dec2bin
mov [cfg_opt_used_launcher_start], 1
mov [cfg_opt_value_launcher_start], al
ret
 
cfg_opt_func_mtrr:
call dec2bin
mov [cfg_opt_used_mtrr], 1
mov [cfg_opt_value_mtrr], al
ret
 
cfg_opt_func_ask_params:
call dec2bin
mov [cfg_opt_used_ask_params], 1
mov [cfg_opt_value_ask_params], al
ret
 
cfg_opt_func_imgfrom:
call dec2bin
mov [cfg_opt_used_imgfrom], 1
mov [cfg_opt_value_imgfrom], al
ret
 
cfg_opt_func_syspath:
mov rdi, cfg_opt_value_syspath
.next_char:
movzx eax, byte[rsi]
cmp al, 0xd ; \r
jz .done
cmp al, 0xa ; \n
jz .done
inc rsi
stosb
jmp .next_char
.done:
mov byte[rdi], 0
ret
 
parse_config:
virtual at rsp+8
.buffer dq ?
end virtual
; mov rsi, [.buffer]
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_parsing_config
pop rbx
mov rsi, KERNEL_BASE
.next_line:
call parse_line
cmp byte[rsi], 0
jnz .next_line
ret 1*8
 
read_options_from_config:
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, EFI_BOOT_SERVICES.HandleProtocol, [efi_handle], lipuuid, \
lip_interface
test eax, eax
jz @f
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error_efi_lip_handle
pop rbx
jmp $
@@:
mov rax, [lip_interface]
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, EFI_BOOT_SERVICES.HandleProtocol, \
[rax+EFI_LOADED_IMAGE_PROTOCOL.DeviceHandle], sfspguid, \
sfsp_interface
test eax, eax
jz @f
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error_lip_dev_sfsp
pop rbx
jmp $
@@:
eficall [sfsp_interface], EFI_SIMPLE_FILE_SYSTEM_PROTOCOL.OpenVolume, \
[sfsp_interface], esp_root
test eax, eax
jz @f
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error_sfsp_openvolume
pop rbx
jmp $
@@:
push 0 ; not fatal, i.e. it's ok to not find this file
push FILE_BUFFER_SIZE
push KERNEL_BASE
; push file_name
mov rax, file_name
push rax
push [esp_root]
call load_file
 
test eax, eax
jz @f
push KERNEL_BASE
call parse_config
@@:
 
.error:
ret
 
print_vmode:
push rax rbx rcx rdx rsi rdi
mov rbx, rcx
call clearbuf
mov eax, [rbx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.HorizontalResolution]
mov rdi, msg
call num2dec
mov eax, [rbx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.VerticalResolution]
mov rdi, msg+8*2
call num2dec
 
mov eax, [rbx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelFormat]
mov rdi, msg+16*2
call num2dec
 
mov eax, [rbx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelsPerScanLine]
mov rdi, msg+24*2
call num2dec
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
pop rdi rsi rdx rcx rbx rax
ret
 
find_vmode_index_by_resolution:
mov [cfg_opt_used_resolution], 1
mov [cfg_opt_value_vmode], 0
.next_mode:
movzx eax, [cfg_opt_value_vmode]
eficall [gop_interface], EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode, \
[gop_interface], rax, gop_info_size, gop_info
cmp rax, EFI_SUCCESS
jnz .error
mov rcx, [gop_info]
call print_vmode
; PixelBlueGreenRedReserved8BitPerColor
cmp [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelFormat], 1
jnz .skip_mode
xor edx, edx
mov eax, [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.HorizontalResolution]
cmp ax, [rdx+BOOT_LO.x_res]
jnz .skip_mode
mov eax, [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.VerticalResolution]
cmp ax, [rdx+BOOT_LO.y_res]
jnz .skip_mode
jmp .done
.skip_mode:
inc [cfg_opt_value_vmode]
movzx eax, [cfg_opt_value_vmode]
mov rcx, [gop_interface]
mov rdx, [rcx+EFI_GRAPHICS_OUTPUT_PROTOCOL.Mode]
cmp eax, [rdx+EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.MaxMode]
jnz .next_mode
mov [cfg_opt_used_resolution], 0
mov [cfg_opt_value_ask_params], 1
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error_no_such_vmode
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error
jmp $
.error:
.done:
ret
 
ask_for_params:
ret
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, EFI_BOOT_SERVICES.HandleProtocol, [rax], gopuuid, \
msg_ask_for_params
jmp $
 
xor ebx, ebx
.next_mode:
call clearbuf
mov eax, ebx
lea rdi, [msg]
call num2dec
 
push rbx
eficall [gop_interface], EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode, \
[gop_interface], rbx, gop_info_size, gop_info
cmp rax, EFI_SUCCESS
jnz .error
mov rcx, [gop_info]
; PixelBlueGreenRedReserved8BitPerColor
cmp [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelFormat], 1
jnz .skip
mov eax, [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.HorizontalResolution]
lea rdi, [msg+4*2]
call num2dec
mov eax, [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.VerticalResolution]
lea rdi, [msg+9*2]
call num2dec
; mov eax, [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelsPerScanLine]
; lea rdi, [msg+14*2]
; call num2dec
.skip:
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
cmp rax, EFI_SUCCESS
jnz .error
 
pop rbx
inc rbx
mov rcx, [gop_interface]
mov rdx, [rcx+EFI_GRAPHICS_OUTPUT_PROTOCOL.Mode]
cmp ebx, [rdx+EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.MaxMode]
jnz .next_mode
 
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConIn]
eficall rbx, SIMPLE_INPUT_INTERFACE.Reset, rbx, 1
cmp rax, EFI_SUCCESS
jnz .error
xor ecx, ecx
@@:
push rcx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConIn]
eficall rbx, SIMPLE_INPUT_INTERFACE.ReadKeyStroke, rbx, msg
pop rcx
mov rdx, EFI_DEVICE_ERROR
cmp rax, rdx
jz .error
mov rdx, EFI_NOT_READY
cmp rax, rdx
jz @b
; cmp rax, EFI_SUCCESS
movzx eax, word[msg+2]
;jmp .key_done
cmp al, 0x0D
jz .key_done
imul ecx, 10
sub eax, '0'
add ecx, eax
jmp @b
.key_done:
mov [cfg_opt_value_vmode], cl
.error:
.done:
ret
 
main:
mov [efi_handle], rcx
mov [efi_table], rdx
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset, rbx, 1
test eax, eax
jz @f
jmp $ ; what can I do here?
@@:
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_u4k_loaded
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_read_options
call read_options_from_config
 
; read kernel file
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_load_kernel
push 1 ; fatal
push MAX_FILE_SIZE
push KERNEL_BASE
; push kernel_name
mov rax, kernel_name
push rax
push [esp_root]
call load_file
 
; read ramdisk image
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_load_ramdisk
push 1 ; fatal
push MAX_FILE_SIZE
push RAMDISK_BASE
; push ramdisk_name
mov rax, ramdisk_name
push rax
push [esp_root]
call load_file
 
; alloc buffer for devices.dat
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_alloc_devicesdat
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, EFI_BOOT_SERVICES.AllocatePages, \
EFI_ALLOCATE_MAX_ADDRESS, EFI_RESERVED_MEMORY_TYPE, 1, \
devicesdat_data
cmp eax, EFI_SUCCESS
jnz .error
 
; read devices.dat
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_load_devicesdat
 
push 0 ; not fatal
push [devicesdat_size]
push [devicesdat_data]
; push devicesdat_name
mov rax, devicesdat_name
push rax
push [esp_root]
call load_file
mov [devicesdat_size], rax
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_locate_gop_handlers
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, EFI_BOOT_SERVICES.LocateHandle, \
EFI_LOCATE_SEARCH_TYPE.ByProtocol, gopuuid, 0, \
gop_buffer_size, gop_buffer
mov [status], rax
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_gop_buffer_size
call clearbuf
mov rax, [gop_buffer_size]
mov rdi, msg
call num2hex
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
 
mov rax, [status]
test eax, eax
jz @f
call clearbuf
mov rdi, msg
call num2hex
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
jmp $
@@:
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_look_for_gop_handler
 
mov rbx, gop_buffer
.next_gop_handle:
mov rax, rbx
mov rcx, gop_buffer
sub rax, rcx
cmp rax, [gop_buffer_size]
jb @f
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error_out_of_handlers
pop rbx
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg_error
pop rbx
jmp $
@@:
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_query_handler
pop rbx
 
mov rax, rbx
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, EFI_BOOT_SERVICES.HandleProtocol, [rax], gopuuid, \
gop_interface
pop rbx
;mov rax, 0x8000_0000_0000_0003
test eax, eax
jz @f
call clearbuf
mov rdi, msg
call num2hex
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
pop rbx
 
add rbx, 8
jmp .next_gop_handle
@@:
 
call find_rsdp
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_acpi_tables_done
 
cmp [cfg_opt_used_resolution], 0
jz .not_used_resolution
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_opt_resolution
call clearbuf
xor edx, edx
movzx eax, [rdx+BOOT_LO.x_res]
mov rdi, msg
call num2dec
xor edx, edx
movzx eax, [rdx+BOOT_LO.y_res]
mov rdi, msg+8*2
call num2dec
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, 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 [rdx+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]
eficall [gop_interface], EFI_GRAPHICS_OUTPUT_PROTOCOL.SetMode, \
[gop_interface], rcx
test eax, eax
jz @f
call clearbuf
mov rdi, msg
call num2hex
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error
jmp $
@@:
 
mov rcx, [gop_interface]
mov rdx, [rcx+EFI_GRAPHICS_OUTPUT_PROTOCOL.Mode]
mov rdi, [rdx+EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.FrameBufferBase]
mov [fb_base], rdi
 
mov ebx, [rdx+EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE.Mode]
eficall [gop_interface], EFI_GRAPHICS_OUTPUT_PROTOCOL.QueryMode, \
[gop_interface], rbx, gop_info_size, gop_info
test eax, eax
jz @f
jmp .error
@@:
mov rcx, [gop_info]
mov eax, [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.HorizontalResolution]
xor rdx, rdx
mov [rdx+BOOT_LO.x_res], ax
mov eax, [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.VerticalResolution]
mov [rdx+BOOT_LO.y_res], ax
mov eax, [rcx+EFI_GRAPHICS_OUTPUT_MODE_INFORMATION.PixelsPerScanLine]
shl eax, 2
mov [rdx+BOOT_LO.pitch], ax
 
mov byte[rdx+BOOT_LO.pci_data+0], 1 ; PCI access mechanism
mov byte[rdx+BOOT_LO.pci_data+1], 8 ; last bus, don't know how to count them
mov byte[rdx+BOOT_LO.pci_data+2], 0x10 ; PCI version
mov byte[rdx+BOOT_LO.pci_data+3], 0x02
mov dword[rdx+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 rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, 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 rdi, [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 [rdx+BOOT_LO.devicesdat_size], eax
mov eax, dword[devicesdat_data]
mov [rdx+BOOT_LO.devicesdat_data], eax
 
mov rsi, cfg_opt_value_syspath
mov rdi, BOOT_LO.syspath
mov ecx, 0x17
rep movsb
 
; kernel trampoline
mov rsi, kernel_trampoline
mov rdi, KERNEL_TRAMPOLINE
mov ecx, kernel_trampoline.size
rep movsb
 
mov rax, GDTR
lgdt [cs:rax]
 
mov ax, DATA_32_SELECTOR
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
 
push CODE_32_SELECTOR
mov rax, KERNEL_TRAMPOLINE
push rax
retf
 
.error:
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error
jmp $
 
 
halt_on_error:
test eax, eax
jz @f
call clearbuf
mov rdi, msg
call num2hex
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_error
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
jmp $
@@:
ret
 
find_rsdp:
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_look_for_rsdp
pop rbx
 
mov rbx, [efi_table]
mov rdi, [rbx+EFI_SYSTEM_TABLE.ConfigurationTable]
mov rcx, [rbx+EFI_SYSTEM_TABLE.NumberOfTableEntries]
mov rax, 0x11d3e4f18868e871
mov rdx, 0x81883cc7800022bc
.next_table:
dec ecx
js .all_tables_done
cmp [rdi+0], rax
jnz .not_acpi20
cmp [rdi+8], rdx
jnz .not_acpi20
mov rax, [rdi+16]
mov rdx, BOOT_LO.acpi_rsdp
mov [rdx], eax
jmp .all_tables_done
.not_acpi20:
add rdi, 24
jmp .next_table
.all_tables_done:
ret
 
calc_memmap:
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, EFI_BOOT_SERVICES.AllocatePages, EFI_ALLOCATE_ANY_PAGES, \
EFI_RESERVED_MEMORY_TYPE, MEMORY_MAP_SIZE/0x1000, memory_map
call halt_on_error
 
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.BootServices]
eficall rbx, EFI_BOOT_SERVICES.GetMemoryMap, memory_map_size, \
[memory_map], memory_map_key, descriptor_size, descriptor_ver
call halt_on_error
 
mov rdi, BOOT_LO.memmap_blocks
mov dword[rdi-4], 0 ; memmap_block_cnt
mov rsi, [memory_map]
mov rbx, rsi
add rbx, [memory_map_size]
.next_descr:
call add_uefi_memmap
add rsi, [descriptor_size]
cmp rsi, rbx
jb .next_descr
ret
 
dump_memmap:
xor eax, eax
mov rsi, BOOT_LO.memmap_blocks
mov ebx, [rax+BOOT_LO.memmap_block_cnt]
 
call clearbuf
mov eax, ebx
mov rdi, msg
call num2dec
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, \
msg_memmap
pop rbx
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
pop rbx
call clearbuf
.next_mapping:
dec ebx
js .done
mov rax, rsi
mov rcx, BOOT_LO.memmap_blocks
sub rax, rcx
mov ecx, sizeof.e820entry
xor edx, edx
div ecx
mov rdi, msg
call num2dec
mov rax, [rsi+e820entry.addr]
mov rdi, msg+4*2
call num2hex
mov rax, [rsi+e820entry.size]
mov rdi, msg+24*2
call num2hex
push rbx
mov rbx, [efi_table]
mov rbx, [rbx+EFI_SYSTEM_TABLE.ConOut]
eficall rbx, EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString, rbx, msg
pop rbx
add rsi, sizeof.e820entry
jmp .next_mapping
.done:
ret
 
 
; linux/arch/x86/platform/efi/efi.c
; do_add_efi_memmap
add_uefi_memmap:
xor eax, eax
cmp [rax+BOOT_LO.memmap_block_cnt], MAX_MEMMAP_BLOCKS
jz .done
 
mov rax, [rsi+EFI_MEMORY_DESCRIPTOR.PhysicalStart]
mov [rdi+e820entry.addr], rax
 
mov rax, [rsi+EFI_MEMORY_DESCRIPTOR.NumberOfPages]
shl rax, 12
mov [rdi+e820entry.size], rax
 
mov ecx, [rsi+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 [rsi+EFI_MEMORY_DESCRIPTOR.Attribute], dword EFI_MEMORY_WB
mov eax, E820_RAM
jnz .type_done
.reserved:
mov eax, E820_RESERVED
.type_done:
mov [rdi+e820entry.type], eax
cmp eax, E820_RAM
jnz @f
xor eax, eax
inc [rax+BOOT_LO.memmap_block_cnt]
add rdi, sizeof.e820entry
@@:
.done:
ret
 
 
num2dec:
push rax rbx rcx rdx rsi rdi
 
xor ecx, ecx
mov ebx, 10
.next_digit:
xor edx, edx
div ebx
push rdx
inc ecx
test eax, eax
jnz .next_digit
 
.next_char:
pop rax
add eax, '0'
stosw
loop .next_char
 
pop rdi rsi rdx rcx rbx rax
ret
 
 
num2hex:
push rax rbx rcx rdx rsi rdi
 
xchg rdx, rax
mov ecx, 16
.next_tetra:
rol rdx, 4
movzx eax, dl
and eax, 0x0f
movzx eax, byte[hex+eax]
stosw
loop .next_tetra
 
pop rdi rsi rdx rcx rbx rax
ret
 
hex db '0123456789ABCDEF'
 
clearbuf:
push rax rbx rcx rdx rsi rdi
mov eax, 0x0020
mov ecx, 79
mov rdi, msg
rep stosw
pop rdi rsi rdx rcx rbx rax
ret
 
use32
kernel_trampoline:
org KERNEL_TRAMPOLINE
mov eax, cr0
and eax, not CR0_PG
mov cr0, eax
 
mov ecx, MSR_AMD_EFER
rdmsr
btr eax, 8 ; LME
wrmsr
 
mov eax, cr4
and eax, not CR4_PAE
mov cr4, eax
 
push KERNEL_BASE
retn
 
align 16
GDTR:
dw 4*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
dw 0FFFFh,0,9A00h,0AFh ; 64-bit code
assert $ < BOOT_LO
kernel_trampoline.size = $ - KERNEL_TRAMPOLINE
 
section '.rodata' data readable
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 dq 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 "uefi64kos loaded",13,10,0
msg_read_options du "Read options from config file",13,10,0
msg_file_size du "File size:",13,10,0
msg_parsing_config du "Parsing 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_memmap du "Memmap",13,10,0
msg_error du "Error!",13,10,0
msg_error_efi_lip_handle du "efi_handle can't handle LIP",13,10,0
msg_error_lip_dev_sfsp du "LIP device handle can't handle SFSP",13,10,0
msg_error_sfsp_openvolume du "SFSP OpenVolume failed",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_error_exit_boot_services du "Error: Exit boot services",13,10,0
msg du 79 dup " ",13,10,0
 
 
section '.data' data readable writeable
efi_handle dq 0
efi_table dq 0
uefi_rsptmp dq 0
 
fb_base dq 0
 
gop_buffer_size dq GOP_BUFFER_SIZE
gop_handle dq 0
gop_interface dq 0
gop_info_size dq 0
gop_info dq 0
 
lip_buffer_size dq LIP_BUFFER_SIZE
lip_handle dq 0
lip_interface dq 0
 
sfsp_interface dq 0
 
esp_root dq ?
file_handle dq ?
file_buffer_size dq 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 dq 0
descriptor_size dq 0
descriptor_ver dq 0
memory_map_size dq 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 dq ?
gop_buffer rq GOP_BUFFER_SIZE/8
devicesdat_data dq 0xffffffff
devicesdat_size dq 0x1000
status dq ?
 
section '.reloc' fixups data discardable
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/uefi4kos/uefi32kos.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/uefi4kos/Tupfile.lua
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")
/kernel/branches/kolibrios-pe-clevermouse/bootloader/uefi4kos/uefi.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/uefi4kos/uefi32.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/uefi4kos/uefi64.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/config.ini
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
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat32/Tupfile.lua
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")
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat32/bootsect.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat32/bootsect.txt
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.
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat32/kordldr.f32.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat32/build.bat
0,0 → 1,3
@fasm -m 65535 bootsect.asm bootsect.bin
@fasm -m 65535 kordldr.f32.asm kordldr.f32
@pause
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat32
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/after_win/Tupfile.lua
0,0 → 1,2
if tup.getconfig("NO_FASM") ~= "" then return end
tup.rule("kordldr.win.asm", "fasm %f %o", "kordldr.win.bin")
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/after_win/kordldr.win.txt
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. Добавляет сектор в конец списка (самый новый вход).
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/after_win/fat.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/after_win/kordldr.win.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/after_win/ntfs.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/after_win/build.bat
0,0 → 1,2
@fasm -m 65535 kordldr.win.asm kordldr.win
@pause
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/after_win
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/cdfs/Tupfile.lua
0,0 → 1,2
if tup.getconfig("NO_FASM") ~= "" then return end
tup.rule("bootsect.asm", "fasm %f %o ", "bootsect.bin")
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/cdfs/bootsect.asm
0,0 → 1,1024
; 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.
;*****************************************************************************
 
jmp far 0:real_start
; special text
org $+0x7C00
real_start:
; initialize
xor ax, ax
mov ss, ax
mov sp, 0x7C00
mov ds, ax
mov es, ax
cld
sti
mov [bootdrive], dl
; check LBA support
mov ah, 41h
mov bx, 55AAh
int 13h
mov si, aNoLBA
jc err_
cmp bx, 0AA55h
jnz err_
test cl, 1
jz err_
; get file system information
; scan for Primary Volume Descriptor
db 66h
push 10h-1
pop eax
pvd_scan_loop:
mov cx, 1
inc eax
mov bx, 0x1000
call read_sectors
jnc @f
fatal_read_err:
mov si, aReadError
err_:
call out_string
mov si, aPressAnyKey
call out_string
xor ax, ax
int 16h
int 18h
jmp $
@@:
push ds
pop es
cmp word [bx+1], 'CD'
jnz pvd_scan_loop
cmp word [bx+3], '00'
jnz pvd_scan_loop
cmp byte [bx+5], '1'
jnz pvd_scan_loop
; we have found ISO9660 descriptor, look for type
cmp byte [bx], 1 ; Primary Volume Descriptor?
jz pvd_found
cmp byte [bx], 0xFF ; Volume Descriptor Set Terminator?
jnz pvd_scan_loop
; Volume Descriptor Set Terminator reached, no PVD found - fatal error
mov si, no_pvd
jmp err_
pvd_found:
add bx, 80h
mov ax, [bx]
mov [lb_size], ax
; calculate number of logical blocks in one sector
mov ax, 800h
cwd
div word [bx]
mov [lb_per_sec], ax
; get location of root directory
mov di, root_location
movzx eax, byte [bx+1Dh]
add eax, [bx+1Eh]
stosd
; get memory size
int 12h
mov si, nomem_str
cmp ax, 71000h / 400h
jb err_
shr ax, 1
sub ax, 60000h / 800h
mov [size_rest], ax
mov [free_ptr], 60000h / 800h
; load path table
; if size > 62K => it's very strange, avoid using it
; if size > (size of cache)/2 => avoid using it too
mov ecx, [bx+4]
cmp ecx, 0x10000 - 0x800
ja nopathtable
shr ax, 1
cmp ax, 0x20
jae @f
shl ax, 11
cmp cx, ax
ja nopathtable
@@:
; size is ok, try to load it
mov [pathtable_size], cx
mov eax, [bx+12]
xor edx, edx
div dword [lb_per_sec]
imul dx, [bx]
mov [pathtable_start], dx
add cx, dx
call cx_to_sectors
xor bx, bx
push 6000h
pop es
call read_sectors
jc nopathtable
; path table has been loaded
inc [use_path_table]
sub [size_rest], cx
add [free_ptr], cx
nopathtable:
; init cache
mov ax, [size_rest]
mov [cache_size], ax
mov ax, [free_ptr]
mov [cache_start], ax
; load secondary loader
mov di, secondary_loader_info
call load_file
test bx, bx
jnz noloader
; set registers for secondary loader
mov ah, [bootdrive]
mov al, 'c'
mov bx, 'is'
mov si, callback
jmp far [si-callback+secondary_loader_info] ; jump to 1000:0000
 
noloader:
mov si, aKernelNotFound
jmp err_
 
read_sectors:
; es:bx = pointer to data
; eax = first sector
; cx = number of sectors
pushad
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
db 66h
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, [cs:bootdrive]
mov ah, 42h
int 13h
jc diskreaderr
; restore stack
add sp, 10h
; increase current sector & buffer; decrease number of sectors
movzx esi, cx
mov ax, es
shl cx, 7
add ax, cx
mov es, ax
pop cx
pop ax
add eax, esi
sub cx, si
jnz do_read_sectors
pop ds
popad
ret
diskreaderr:
add sp, 10h + 2*2
pop ds
popad
stc
out_string.ret:
ret
 
out_string:
; in: ds:si -> ASCIIZ string
lodsb
test al, al
jz .ret
mov ah, 0Eh
mov bx, 7
int 10h
jmp out_string
 
aNoLBA db 'The drive does not support LBA!',0
aReadError db 'Read error',0
no_pvd db 'Primary Volume Descriptor not found!',0
nomem_str db 'No memory',0
aPressAnyKey db 13,10,'Press any key...',13,10,0
 
load_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 = 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)
; parse path to the file
lea si, [di+6]
mov eax, [cs:root_location]
cmp [cs:use_path_table], 0
jz parse_dir
; scan for path in path table
push di
push 6000h
pop es
mov di, [cs:pathtable_start] ; es:di = pointer to current entry in path table
mov dx, 1 ; dx = number of current entry in path table, start from 1
mov cx, [cs:pathtable_size]
pathtable_newparent:
mov bx, dx ; bx = number of current parent in path table: root = 1
scan_path_table_e:
call is_last_component
jnc path_table_scanned
scan_path_table_i:
cmp word [es:di+6], bx
jb .next
ja path_table_notfound
call test_filename1
jc .next
@@:
lodsb
cmp al, '/'
jnz @b
jmp pathtable_newparent
.next:
; go to next entry
inc dx
movzx ax, byte [es:di]
add ax, 8+1
and al, not 1
add di, ax
sub cx, ax
ja scan_path_table_i
path_table_notfound:
pop di
mov ax, -1
mov dx, ax
mov bx, 2 ; file not found
ret
path_table_scanned:
movzx eax, byte [es:di+1]
add eax, [es:di+2]
pop di
parse_dir:
; eax = logical block, ds:di -> information structure, ds:si -> file name
; was the folder already read?
push di ds
push cs
pop ds
mov [cur_desc_end], 2000h
mov bx, cachelist
.scan1:
mov bx, [bx+2]
cmp bx, cachelist
jz .notfound
cmp [bx+4], eax
jnz .scan1
.found:
; yes; delete this item from the list (the following code will append this item to the tail)
mov di, [bx]
push word [bx+2]
pop word [di+2]
mov di, [bx+2]
push word [bx]
pop word [di]
mov di, bx
jmp .scan
.notfound:
; no; load first sector of the folder to get its size
push eax
push si
mov si, 1
call load_phys_sector_for_lb_force
mov bx, si
pop si
pop eax
jnc @f
; read error - return
.readerr:
pop ds
.readerr2:
pop di
mov ax, -1
mov dx, ax
mov bx, 3
ret
@@:
; first item of the folder describes the folder itself
; do not cache too big folders: size < 64K and size <= (total cache size)/2
cmp word [bx+12], 0
jnz .nocache
mov cx, [cache_size] ; cx = cache size in sectors
shr cx, 1 ; cx = (cache size)/2
cmp cx, 0x20
jae @f
shl cx, 11
cmp [bx+10], cx
ja .nocache
@@:
; we want to cache this folder; get space for it
mov cx, [bx+10]
call cx_to_sectors
jnz .yescache
.nocache:
push dword [bx+10]
pop dword [cur_nocache_len]
call lb_to_sector
push ds
pop es
pop ds
.nocache_loop:
push eax
mov dx, 1800h
call scan_for_filename_in_sector
mov cx, dx
pop eax
jnc .j_scandone
sub cx, bx
sub word [es:cur_nocache_len], cx
sbb word [es:cur_nocache_len+2], 0
jb .j_scandone
ja @f
cmp word [es:cur_nocache_len], 0
jz .j_scandone
@@:
mov cx, 1
inc eax
push es
mov bx, 1000h
call read_sectors
pop es
jc .readerr2
jmp .nocache_loop
.j_scandone:
jmp .scandone
.yescache:
push bx
mov bx, [cachelist.head]
.freeloop:
cmp cx, [size_rest]
jbe .sizeok
@@:
; if we are here: there is not enough free space, so we must delete old folders' data
; N.B. We know that after deleting some folders the space will be available (size <= (total cache size)/2).
; one loop iteration: delete data of one folder
pusha
mov dx, [bx+10]
mov es, dx ; es = segment of folder data to be deleted
xor di, di
mov ax, [bx+8]
add ax, 0x7FF
rcr ax, 1
shr ax, 10
push ax
shl ax, 11-4 ; get number of paragraphs in folder data to be deleted
mov cx, [cache_size]
add cx, [cache_start]
push ds
push ax
add ax, dx
mov ds, ax
pop ax
shl cx, 11-4
sub cx, dx ; cx = number of paragraphs to be moved
push si
xor si, si
; move cx paragraphs from ds:si to es:di to get free space in the end of cache
@@:
sub cx, 1000h
jbe @f
push cx
mov cx, 8000h
rep movsw
mov cx, ds
add cx, 1000h
mov ds, cx
mov cx, es
add cx, 1000h
mov es, cx
pop cx
jmp @b
@@:
add cx, 1000h
shl cx, 3
rep movsw
pop si
pop ds
; correct positions in cache for existing items
mov cx, 80h
mov di, 8400h
.correct:
cmp [di+10], dx
jbe @f
sub [di+10], ax
@@:
add di, 12
loop .correct
; some additional space is free now
pop ax
add [size_rest], ax
sub [free_ptr], ax
; add cache item to the list of free items
mov dx, [bx]
mov ax, [free_cache_item]
mov [bx], ax
mov [free_cache_item], bx
mov bx, dx
; current iteration done
popa
jmp .freeloop
.sizeok:
mov [cachelist.head], bx
mov word [bx+2], cachelist
; allocate new item in cache
mov di, [free_cache_item]
test di, di
jz .nofree
push word [di]
pop [free_cache_item]
jmp @f
.nofree:
mov di, [last_cache_item]
add [last_cache_item], 12
@@:
pop bx
push si di
; mov [di+4], eax ; start of folder
scasd
stosd
push ax
mov ax, [free_ptr]
shl ax, 11-4
mov [di+10-8], ax
mov es, ax
pop ax
add [free_ptr], cx
sub [size_rest], cx
; read folder data
; first sector is already in memory, 0000:bx
pusha
mov cx, [bx+10]
mov [di+8-8], cx ; folder size in bytes
mov si, bx
xor di, di
mov cx, 0x1800
sub cx, si
rep movsb
pop ax
push di
popa
; read rest of folder
mov esi, dword [lb_per_sec]
add eax, esi
dec si
not si
and ax, si
mov si, word [bx+10]
mov bx, di
pop di
sub si, bx
jbe @f
mov [cur_limit], esi
call read_many_bytes
pop si
jnc .scan
jmp .readerr
@@:
pop si
.scan:
; now we have required cache item; append it to the end of list
mov bx, [cachelist.tail]
mov [cachelist.tail], di
mov [di+2], bx
mov word [di], cachelist
mov [bx], di
; scan for given filename
mov es, [di+10]
mov dx, [di+8]
pop ds
xor bx, bx
call scan_for_filename_in_sector
.scandone:
push cs
pop es
mov bx, 2000h
cmp bx, [es:cur_desc_end]
jnz filefound
j_notfound:
jmp path_table_notfound
filefound:
@@:
lodsb
test al, al
jz @f
cmp al, '/'
jnz @b
@@:
mov cl, [es:bx+8]
test al, al
jz @f
; parse next component of file name
test cl, 2 ; directory?
jz j_notfound
mov eax, [es:bx]
pop di
jmp parse_dir
@@:
test cl, 2 ; directory?
jnz j_notfound ; do not allow read directories as regular files
; ok, now load the file
pop di
les bx, [di]
call normalize
movzx esi, word [di+4] ; esi = limit in 4K blocks
shl esi, 12 ; esi = limit in bytes
push cs
pop ds
mov [cur_limit], esi
mov di, 2000h
loadloop:
and [cur_start], 0
.loadnew:
mov esi, [cur_limit]
mov eax, [cur_start]
add esi, eax
mov [overflow], 1
sub esi, [di+4]
jb @f
xor esi, esi
dec [overflow]
@@:
add esi, [di+4] ; esi = number of bytes to read
mov [cur_start], esi
sub esi, eax
jz .loadcontinue
xor edx, edx
div dword [lb_size] ; eax = number of logical blocks to skip,
mov [first_byte], dx; [first_byte] = number of bytes to skip in 1st block
cmp byte [di+10], 0
jnz .interleaved
add eax, [di]
; read esi bytes from logical block eax to buffer es:bx
call read_many_bytes.with_first
jc .readerr3
.loadcontinue:
mov [cur_chunk], di
add di, 11
cmp di, [cur_desc_end]
jae @f
cmp [cur_limit], 0
jnz loadloop
@@:
mov bx, [overflow]
.calclen:
; calculate length of file
xor ax, ax
xor dx, dx
mov di, 2000h
@@:
add ax, [di+4]
adc dx, [di+6]
add di, 11
cmp di, [cur_desc_end]
jb @b
ret
.interleaved:
mov [cur_unit_limit], esi
push esi
; skip first blocks
movzx ecx, byte [di+9] ; Unit Size
movzx esi, byte [di+10] ; Interleave Gap
add si, cx
mov edx, [di]
@@:
sub eax, ecx
jb @f
add edx, esi
jmp @b
@@:
add ecx, eax ; ecx = number of logical blocks to skip
lea eax, [ecx+edx] ; eax = first logical block
pop esi
.interleaved_loop:
; get number of bytes in current file unit
push eax
movzx eax, byte [di+9]
sub ax, cx
imul eax, dword [lb_size]
cmp eax, esi
ja .i2
.i1:
xchg esi, eax
.i2:
pop eax
sub [cur_unit_limit], esi
push eax
; read esi bytes from logical block eax to buffer es:bx
call read_many_bytes.with_first
pop eax
jnc @f
.readerr3:
mov bx, 3
jmp .calclen
@@:
mov esi, [cur_unit_limit]
test esi, esi
jz .loadcontinue
movzx ecx, byte [di+9] ; add Unit Size
add cl, byte [di+10] ; add Interleave Gap
adc ch, 0
add eax, ecx
xor cx, cx
mov [first_byte], cx
jmp .interleaved_loop
 
cx_to_sectors:
add cx, 7FFh
rcr cx, 1
shr cx, 10
ret
 
is_last_component:
; in: ds:si -> name
; out: CF set <=> current component is not last (=> folder)
push si
@@:
lodsb
test al, al
jz @f
cmp al, '/'
jnz @b
stc
@@:
pop si
ret
 
test_filename1:
; in: ds:si -> filename, es:di -> path table item
; out: CF set <=> no match
pusha
mov cl, [es:di]
add di, 8
jmp test_filename2.start
test_filename2:
; in: ds:si -> filename, es:bx -> directory item
; out: CF set <=> no match
pusha
mov cl, [es:bx+32]
lea di, [bx+33]
.start:
mov ch, 0
@@:
lodsb
test al, al
jz .test1
cmp al, '/'
jz .test1
call toupper
mov ah, al
mov al, [es:di]
call toupper
inc di
cmp al, ah
loopz @b
jnz .next1
; if we have reached this point: current name is done
lodsb
test al, al
jz .ret
cmp al, '/'
jz .ret
; if we have reached this point: current name is done, but input name continues
; so they do not match
jmp .next1
.test1:
; if we have reached this point: input name is done, but current name continues
; "filename.ext;version" in ISO-9660 represents file "filename.ext"
; "filename." and "filename.;version" are also possible for "filename"
cmp byte [es:di], '.'
jnz @f
inc di
dec cx
jz .ret
@@:
cmp byte [es:di], ';'
jnz .next1
jmp .ret
.next1:
stc
.ret:
popa
ret
 
toupper:
; in: al=symbol
; out: al=symbol in uppercase
cmp al, 'a'
jb .ret
cmp al, 'z'
ja .ret
sub al, 'a'-'A'
.ret:
ret
 
scan_for_filename_in_sector:
; in: ds:si->filename, es:bx->folder data, dx=limit
; out: CF=0 if found
push bx
.loope:
push bx
.loop:
cmp bx, dx
jae .notfound
cmp byte [es:bx], 0
jz .loopd
test byte [es:bx+25], 4 ; ignore files with Associated bit
jnz .next
call test_filename2
jc .next
push ds es di
push es
pop ds
push cs
pop es
mov di, [es:cur_desc_end]
movzx eax, byte [bx+1]
add eax, [bx+2]
stosd ; first logical block
mov eax, [bx+10]
stosd ; length
mov al, [bx+25]
stosb ; flags
mov ax, [bx+26]
stosw ; File Unit size, Interleave Gap size
mov [es:cur_desc_end], di
cmp di, 3000h
pop di es ds
jae .done
test byte [es:bx+25], 80h
jz .done
.next:
add bl, [es:bx]
adc bh, 0
jmp .loop
.loopd:
mov ax, bx
pop bx
@@:
add bx, [cs:lb_size]
jz .done2
cmp bx, ax
jb @b
jmp .loope
.notfound:
stc
.done:
pop bx
.done2:
pop bx
ret
 
lb_to_sector:
xor edx, edx
div dword [lb_per_sec]
ret
 
load_phys_sector_for_lb_force:
; in: eax = logical block, ds=0
; in: si=0 - accept 0 logical blocks, otherwise force read at least 1
; out: 0000:1000 = physical sector data; si -> logical block
; out: eax = next physical sector
; out: CF=1 if read error
; destroys cx
; this procedure reads 0-3 or 1-4 logical blocks, up to the end of physical sector
call lb_to_sector
or si, dx
jnz @f
mov si, 1800h
jmp .done
@@:
mov si, 1000h
imul dx, [lb_size]
add si, dx
mov cx, 1
push es bx
push ds
pop es
mov bx, 1000h
call read_sectors
pop bx es
inc eax
.done:
ret
 
normalize:
; in: es:bx = far pointer
; out: es:bx = normalized pointer (i.e. 0 <= bx < 0x10)
push ax bx
mov ax, es
shr bx, 4
add ax, bx
mov es, ax
pop bx ax
and bx, 0x0F
ret
 
read_many_bytes:
and [first_byte], 0
read_many_bytes.with_first:
; read esi bytes from logical block dx:ax to buffer es:bx
; out: CF=1 <=> disk error
push di
; load first physical sector
push bx si
mov si, [first_byte]
call load_phys_sector_for_lb_force
jnc @f
pop si bx
.ret:
pop di
ret
@@:
add si, [first_byte]
mov ecx, 1800h
sub cx, si
mov ebx, esi
pop bx
sub ebx, ecx
jnc @f
add cx, bx
xor ebx, ebx
@@:
pop di
sub [cur_limit], ecx
rep movsb
mov esi, ebx
mov bx, di
call normalize
; load other physical sectors
; read esi bytes from physical sector eax to buffer es:bx
test esi, esi
jz .ret
push esi
add esi, 0x7FF
and si, not 0x7FF
cmp esi, [cur_limit]
jbe .okplace
.noplace:
sub esi, 800h
.okplace:
shr esi, 11 ; si = number of sectors
mov cx, si
jz @f
call read_sectors
@@:
pop esi
jc .ret
movzx ecx, cx
add eax, ecx
shl ecx, 11
sub [cur_limit], ecx
sub esi, ecx
jc .big
jz .nopost
push bx es
push ds
pop es
mov bx, 1000h
mov cx, 1
call read_sectors
pop es di
jc .ret2
mov cx, si
mov si, 1000h
sub word [cur_limit], cx
sbb word [cur_limit+2], 0
rep movsb
mov bx, di
call normalize
.nopost:
clc
.ret2:
pop di
ret
.big:
mov ax, es
sub ax, 80h
mov es, ax
add bx, 800h
add bx, si
call normalize
sub [cur_limit], esi
jmp .nopost
 
; Callback function for secondary loader
callback:
; in: ax = function number; only function 1 is defined for now
dec ax
jz callback_readfile
dec ax
jz callback_continueread
stc ; unsupported function
retf
 
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
clc ; function is supported
retf
 
callback_continueread:
; function 2: continue to 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)
; out: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=3 - read error
; out: dx:ax = file size
les bx, [di]
call normalize
movzx esi, word [di+4] ; si = limit in 4K blocks
shl esi, 12 ; bp:si = limit in bytes
push cs
pop ds
mov [cur_limit], esi
mov di, [cur_chunk]
call loadloop.loadnew
clc ; function is supported
retf
 
secondary_loader_info:
dw 0, 0x1000
dw 0x30000 / 0x1000
db 'kernel.mnt',0
aKernelNotFound db 'Fatal error: cannot load the kernel',0
 
align 2
cachelist:
.head dw cachelist
.tail dw cachelist
free_cache_item dw 0
last_cache_item dw 0x8400
 
use_path_table db 0
bootdrive db ?
align 2
lb_size dw ? ; Logical Block size in bytes
dw 0 ; to allow access dword [lb_size]
lb_per_sec dw ? ; Logical Blocks per physical sector
dw 0 ; to allow access dword [lb_per_sec]
free_ptr dw ? ; first free block in cache (cache block = sector = 0x800 bytes)
size_rest dw ? ; free space in cache (in blocks)
cache_size dw ?
cache_start dw ?
pathtable_size dw ?
pathtable_start dw ?
root_location dd ?
cur_desc_end dw ?
cur_nocache_len dd ?
cur_limit dd ?
cur_unit_limit dd ?
overflow dw ?
cur_chunk dw ?
first_byte dw ?
cur_start dd ?
 
times 83FCh-$ db 0
db 43h
; just to make file 2048 bytes long :)
db 'd' xor 'i' xor 'a' xor 'm' xor 'o' xor 'n' xor 'd'
 
dw 0xAA55 ; this is not required for CD, but to be consistent...
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/cdfs/bootsect.txt
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. Если же нет, то считываются все сектора, кроме последнего, после чего
последний сектор считывается отдельно во временную область, и уже
оттуда нужная часть данных копируется в буфер.
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/cdfs/build.bat
0,0 → 1,2
@fasm -m 65535 bootsect.asm bootsect.bin
@pause
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/cdfs
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat1x/Tupfile.lua
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")
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat1x/bootsect.txt
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.
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat1x/bootsect.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat1x/kordldr.f1x.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat1x/build.bat
0,0 → 1,3
@fasm -m 65535 bootsect.asm bootsect.bin
@fasm -m 65535 kordldr.f1x.asm kordldr.f1x
@pause
/kernel/branches/kolibrios-pe-clevermouse/bootloader/extended_primary_loader/fat1x
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/boot_fat12.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/grub4kos.asm
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:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/floppy1440.inc
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)
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/floppy1680.inc
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)
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/floppy1743.inc
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)
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/floppy2880.inc
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)
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootloader/Tupfile.lua
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")
/kernel/branches/kolibrios-pe-clevermouse/bootloader/readme
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
/kernel/branches/kolibrios-pe-clevermouse/init.inc
0,0 → 1,531
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
align 4
proc mem_test
; if we have BIOS with fn E820, skip the test
cmp [BOOT_LO.memmap_block_cnt], 0
jnz .ret
 
mov eax, cr0
and eax, not (CR0_CD+CR0_NW)
or eax, CR0_CD ;disable caching
mov cr0, eax
wbinvd ;invalidate cache
 
xor edi, edi
mov ebx, 'TEST'
@@:
add edi, 0x100000
xchg ebx, dword [edi]
cmp dword [edi], 'TEST'
xchg ebx, dword [edi]
je @b
 
and eax, not (CR0_CD+CR0_NW) ;enable caching
mov cr0, eax
inc dword [BOOT_LO.memmap_block_cnt]
xor eax, eax
mov [BOOT_LO.memmap_blocks+e820entry.addr.lo], eax
mov [BOOT_LO.memmap_blocks+e820entry.addr.hi], eax
mov [BOOT_LO.memmap_blocks+e820entry.size.lo], edi
mov [BOOT_LO.memmap_blocks+e820entry.size.hi], eax
inc eax
mov [BOOT_LO.memmap_blocks+e820entry.type], eax
.ret:
ret
endp
 
align 4
proc init_mem
; calculate maximum allocatable address and number of allocatable pages
mov edi, BOOT_LO.memmap_blocks
mov ecx, [edi-4] ; memmap_block_cnt
xor esi, esi; esi will hold total amount of memory
xor edx, edx; edx will hold maximum allocatable address
.calcmax:
; round all to pages
mov eax, [edi+e820entry.addr.lo]
cmp byte [edi+e820entry.type], 1
jne .unusable
 
test eax, 0xFFF
jz @f
neg eax
and eax, 0xFFF
add [edi+e820entry.addr.lo], eax
adc [edi+e820entry.addr.hi], 0
sub [edi+e820entry.size.lo], eax
sbb [edi+e820entry.size.hi], 0
jc .unusable
@@:
and [edi+e820entry.size.lo], not 0xFFF
jz .unusable
; ignore memory after 4 GiB
cmp [edi+e820entry.addr.hi], 0
jnz .unusable
mov eax, [edi+e820entry.addr.lo]
cmp [edi+e820entry.size.hi], 0
jnz .overflow
add eax, [edi+e820entry.size.lo]
jnc @f
.overflow:
mov eax, 0xFFFFF000
@@:
cmp edx, eax
jae @f
mov edx, eax
@@:
sub eax, [edi+e820entry.addr.lo]
mov [edi+e820entry.size.lo], eax
add esi, eax
jmp .usable
.unusable:
; and dword [edi+e820entry.size.lo], 0
.usable:
add edi, sizeof.e820entry
loop .calcmax
.calculated:
mov [MEM_AMOUNT-OS_BASE], esi
mov [pg_data.mem_amount-OS_BASE], esi
shr esi, 12
mov [pg_data.pages_count-OS_BASE], esi
 
shr edx, 12
add edx, 31
and edx, not 31
shr edx, 3
mov [pg_data.pagemap_size-OS_BASE], edx
 
add edx, (sys_pgmap-OS_BASE)+4095
and edx, not 4095
mov [tmp_page_tabs], edx
 
mov edx, esi
and edx, -1024
cmp edx, (OS_BASE/4096)
jbe @F
mov edx, (OS_BASE/4096)
jmp .set
@@:
cmp edx, (HEAP_BASE-OS_BASE+HEAP_MIN_SIZE)/4096
jae .set
mov edx, (HEAP_BASE-OS_BASE+HEAP_MIN_SIZE)/4096
.set:
mov [pg_data.kernel_pages-OS_BASE], edx
shr edx, 10
mov [pg_data.kernel_tables-OS_BASE], edx
 
xor eax, eax
mov edi, sys_proc-OS_BASE
mov ecx, 8192/4
cld
rep stosd
 
mov edx, (sys_proc-OS_BASE+PROC.pdt_0)+ 0x800; (OS_BASE shr 20)
bt [cpu_caps-OS_BASE], CAPS_PSE
jnc .no_PSE
 
mov ebx, cr4
or ebx, CR4_PSE
mov eax, PDE_LARGE+PG_SWR
mov cr4, ebx
dec [pg_data.kernel_tables-OS_BASE]
 
mov [edx], eax
add edx, 4
 
mov edi, [tmp_page_tabs]
jmp .map_kernel_heap ; new kernel fits to the first 4Mb - nothing to do with ".map_low"
.no_PSE:
mov eax, PG_SWR
mov ecx, [tmp_page_tabs]
shr ecx, 12
.map_low:
mov edi, [tmp_page_tabs]
@@: ;
stosd
add eax, 0x1000
dec ecx
jnz @B
 
.map_kernel_heap:
mov ecx, [pg_data.kernel_tables-OS_BASE]
shl ecx, 10
xor eax, eax
rep stosd
 
mov ecx, [pg_data.kernel_tables-OS_BASE]
mov eax, [tmp_page_tabs]
or eax, PG_SWR
mov edi, edx
 
.map_kernel_tabs:
stosd
add eax, 0x1000
dec ecx
jnz .map_kernel_tabs
 
mov dword [sys_proc-OS_BASE+PROC.pdt_0+(page_tabs shr 20)], sys_proc+PROC.pdt_0+PG_SWR-OS_BASE
 
mov edi, (sys_proc+PROC.pdt_0-OS_BASE)
lea esi, [edi+(OS_BASE shr 20)]
movsd
movsd
ret
endp
 
align 4
proc init_page_map
; mark all memory as unavailable
mov edi, sys_pgmap-OS_BASE
mov ecx, [pg_data.pagemap_size-OS_BASE]
shr ecx, 2
xor eax, eax
cld
rep stosd
 
; scan through memory map and mark free areas as available
mov ebx, BOOT_LO.memmap_blocks
mov edx, [ebx-4]
.scanmap:
cmp byte [ebx+e820entry.type], 1
jne .next
 
mov ecx, [ebx+e820entry.size.lo]
shr ecx, 12; ecx = number of pages
jz .next
mov edi, [ebx+e820entry.addr.lo]
shr edi, 12; edi = first page
mov eax, edi
shr edi, 5
shl edi, 2
add edi, sys_pgmap-OS_BASE
and eax, 31
jz .startok
add ecx, eax
sub ecx, 32
jbe .onedword
push ecx
mov ecx, eax
or eax, -1
shl eax, cl
or [edi], eax
add edi, 4
pop ecx
.startok:
push ecx
shr ecx, 5
or eax, -1
rep stosd
pop ecx
and ecx, 31
neg eax
shl eax, cl
dec eax
or [edi], eax
jmp .next
.onedword:
add ecx, 32
sub ecx, eax
@@:
bts [edi], eax
inc eax
loop @b
.next:
add ebx, sizeof.e820entry
dec edx
jnz .scanmap
 
; mark kernel memory as allocated (unavailable)
mov ecx, [tmp_page_tabs]
mov edx, [pg_data.pages_count-OS_BASE]
shr ecx, 12
add ecx, [pg_data.kernel_tables-OS_BASE]
sub edx, ecx
mov [pg_data.pages_free-OS_BASE], edx
 
mov edi, sys_pgmap-OS_BASE
mov ebx, ecx
shr ecx, 5
xor eax, eax
rep stosd
 
not eax
mov ecx, ebx
and ecx, 31
shl eax, cl
and [edi], eax
add edi, OS_BASE
mov [page_start-OS_BASE], edi;
 
mov ebx, sys_pgmap
add ebx, [pg_data.pagemap_size-OS_BASE]
mov [page_end-OS_BASE], ebx
 
ret
endp
 
align 4
 
init_BIOS32:
mov edi, 0xE0000
.pcibios_nxt:
cmp dword[edi], '_32_'; "magic" word
je .BIOS32_found
.pcibios_nxt2:
add edi, 0x10
cmp edi, 0xFFFF0
je .BIOS32_not_found
jmp .pcibios_nxt
.BIOS32_found: ; magic word found, check control summ
 
movzx ecx, byte[edi + 9]
shl ecx, 4
mov esi, edi
xor eax, eax
cld ; paranoia
@@:
lodsb
add ah, al
loop @b
jnz .pcibios_nxt2; control summ must be zero
; BIOS32 service found !
mov ebp, [edi + 4]
mov [bios32_entry], ebp
; check PCI BIOS present
mov eax, '$PCI'
xor ebx, ebx
push cs ; special for 'ret far' from BIOS
call ebp
test al, al
jnz .PCI_BIOS32_not_found
 
; descriptors for PCI BIOS are created here
 
add ebx, OS_BASE
dec ecx
mov [(pci_code_32-OS_BASE)], cx ;limit 0-15
mov [(pci_data_32-OS_BASE)], cx ;limit 0-15
 
mov [(pci_code_32-OS_BASE)+2], bx ;base 0-15
mov [(pci_data_32-OS_BASE)+2], bx ;base 0-15
 
shr ebx, 16
mov [(pci_code_32-OS_BASE)+4], bl ;base 16-23
mov [(pci_data_32-OS_BASE)+4], bl ;base 16-23
 
shr ecx, 16
and cl, 0x0F
mov ch, bh
add cx, D32
mov [(pci_code_32-OS_BASE)+6], cx ;lim 16-19 &
mov [(pci_data_32-OS_BASE)+6], cx ;base 24-31
 
mov [(pci_bios_entry-OS_BASE)], edx
; jmp .end
.PCI_BIOS32_not_found:
; pci_emu_dat structure should be filled here
.BIOS32_not_found:
.end:
ret
 
align 4
proc test_cpu
locals
cpu_type dd ?
endl
 
xor eax, eax
mov [cpu_type], eax
mov [cpu_caps-OS_BASE], eax
mov [cpu_caps+4-OS_BASE], eax
mov [cpu_phys_addr_width-OS_BASE], 32
 
pushfd
pop eax
mov ecx, eax
xor eax, EFLAGS_AC
push eax
popfd
pushfd
pop eax
xor eax, ecx
mov [cpu_type], CPU_386
jz .end_cpuid
push ecx
popfd
 
mov [cpu_type], CPU_486
mov eax, ecx
xor eax, EFLAGS_ID
push eax
popfd
pushfd
pop eax
xor eax, ecx
je .end_cpuid
 
xor eax, eax
cpuid
 
mov [cpu_vendor-OS_BASE], ebx
mov [cpu_vendor+4-OS_BASE], edx
mov [cpu_vendor+8-OS_BASE], ecx
 
cmp eax, 1
jl .end_cpuid
mov eax, 1
cpuid
mov [cpu_sign-OS_BASE], eax
mov [cpu_info-OS_BASE], ebx
mov [cpu_caps-OS_BASE], edx
mov [cpu_caps+4-OS_BASE], ecx
 
bt edx, CAPS_PAE
jnc @f
mov [cpu_phys_addr_width-OS_BASE], 36
@@:
mov eax, 0x80000000
cpuid
cmp eax, 0x80000008
jb @f
mov eax, 0x80000008
cpuid
mov [cpu_phys_addr_width-OS_BASE], al
@@:
 
mov eax, [cpu_sign-OS_BASE]
shr eax, 8
and eax, 0x0f
ret
.end_cpuid:
mov eax, [cpu_type]
ret
endp
 
ACPI_HI_RSDP_WINDOW_START = 0x000E0000
ACPI_HI_RSDP_WINDOW_END = 0x00100000
ACPI_RSDP_CHECKSUM_LENGTH = 20
 
proc acpi_locate_tables uses ebx esi edi
mov ebx, [ebx+ACPI_RSDP.RsdtAddress]
mov [acpi_rsdt_base-OS_BASE], ebx
mov eax, [ebx+ACPI_RSDT.Length]
mov [acpi_rsdt_size-OS_BASE], eax
 
mov esi, [acpi_rsdt_base-OS_BASE]
mov ecx, [esi+ACPI_RSDT.Length]
lea edi, [esi+ecx]
add esi, sizeof.ACPI_TABLE
movi ecx, 1
.next_table:
cmp esi, edi
jae .done
lodsd
cmp [eax+ACPI_TABLE.Signature], 'SSDT' ; skip DSDT if present
jz .ssdt ; read it from FADT
cmp [eax+ACPI_TABLE.Signature], 'FACP' ; this is FADT
jz .fadt
cmp [eax+ACPI_TABLE.Signature], 'APIC' ; this is MADT
jz .madt
cmp [eax+ACPI_TABLE.Signature], 'HPET'
jz .hpet
jmp .next_table
.ssdt:
mov [acpi_ssdt_base+ecx*4-OS_BASE], eax
mov eax, [eax+ACPI_TABLE.Length]
mov [acpi_ssdt_size+ecx*4-OS_BASE], eax
inc ecx
jmp .next_table
.fadt:
mov [acpi_fadt_base-OS_BASE], eax
cmp [eax+ACPI_FADT.DSDT], 0
jz @f
mov edx, [eax+ACPI_FADT.DSDT]
mov [acpi_ssdt_base-OS_BASE], edx
mov edx, [edx+ACPI_TABLE.Length]
mov [acpi_ssdt_size-OS_BASE], edx
@@:
mov eax, [eax+ACPI_TABLE.Length]
mov [acpi_fadt_size-OS_BASE], eax
jmp .next_table
.madt:
mov [acpi_madt_base-OS_BASE], eax
mov eax, [eax+ACPI_TABLE.Length]
mov [acpi_madt_size-OS_BASE], eax
jmp .next_table
.hpet:
mov [acpi_hpet_base-OS_BASE], eax
mov eax, [eax+ACPI_TABLE.Length]
mov [acpi_hpet_size-OS_BASE], eax
jmp .next_table
.done:
mov [acpi_ssdt_cnt-OS_BASE], ecx
ret
endp
 
acpi_locate:
push ebx
push edi
 
if defined UEFI
; UEFI loader knows where RSDP is
mov ebx, [BOOT_LO.acpi_rsdp]
test ebx, ebx
jz .done
call .check
else
movzx ebx, word [0x40E]
shl ebx, 4
lea ecx, [ebx+1024]
call .check
 
test ebx, ebx
jz @F
jmp .done
 
@@:
mov ebx, ACPI_HI_RSDP_WINDOW_START
mov edi, ACPI_HI_RSDP_WINDOW_END
call .check
end if
.done:
mov [acpi_rsdp_base-OS_BASE], ebx
test ebx, ebx
jz @f
call acpi_locate_tables
@@:
pop edi
pop ebx
ret
 
.check:
cmp [ebx], dword 'RSD '
jne .next
cmp [ebx+4], dword 'PTR '
jne .next
 
mov edx, ebx
mov ecx, ACPI_RSDP_CHECKSUM_LENGTH
xor eax, eax
.sum:
add al, [edx]
inc edx
loop .sum
 
test al, al
jnz .next
ret
.next:
add ebx, 16
cmp ebx, edi
jb .check
xor ebx, ebx
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/booten.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/bootsp.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/bootvesa.inc
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
 
;=============================================================================
;=============================================================================
;=============================================================================
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/shutdown.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/parsers.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/bootcode.inc
0,0 → 1,1400
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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 ;;
;; ;;
;; BOOTCODE.INC ;;
;; ;;
;; KolibriOS 16-bit loader, ;;
;; based on bootcode for MenuetOS ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
;==========================================================================
;
; 16 BIT FUNCTIONS
;
;==========================================================================
 
 
putchar:
; in: al=character
mov ah, 0Eh
mov bh, 0
int 10h
ret
 
print:
; in: si->string
mov al, 186
call putchar
mov al, ' '
call putchar
 
printplain:
; in: si->string
pusha
lodsb
@@:
call putchar
lodsb
test al, al
jnz @b
popa
ret
 
getkey: ; Use BIOS INT 16h to read a key from the keyboard
; get number in range [bl,bh] (bl,bh in ['0'..'9'])
; in: bx=range
; out: ax=digit (1..9, 10 for 0)
mov ah, 0 ; If 'int 16h' is called with 'ah' equal to zero, the BIOS will not return control to the caller
int 16h ; until a key is available in the system type ahead buffer. On return, 'al' contains the ASCII
cmp al, 27 ; code for the key read from the buffer and 'ah' contains the keyboard scan code. (27=>ESC)
jz @f ; If ESC is pressed, return (user doesn't want to change any value).
cmp al, bl ; Compare 'al' (ASCII code of key pressed) with 'bl' (lowest accepted char from the range).
jb getkey ; ASCII code is below lowest accepted value => continue waiting for another key.
cmp al, bh ; Compare 'al' (ASCII code of key pressed) with 'bh' (highest accepted char from the range).
ja getkey ; ASCII code is above highest accepted value => continue waiting for another key.
push ax ; If the pressed key is in the accepted range, save it on the stack and echo to screen.
call putchar
pop ax
and ax, 0Fh ; Convert ASCII code to number: '1'->1, '2'->2, etc. 0Fh=1111b.
jnz @f ; ASCII code for '0' is 48 (110000b). (110000b AND 1111b) = 0
mov al, 10 ; So if key '0' was entered, return 10 in 'ax'
@@:
ret
 
setcursor:
; in: dl=column, dh=row
mov ah, 2
mov bh, 0
int 10h
ret
 
macro _setcursor row,column
{
mov dx, row*256 + column
call setcursor
}
 
macro _ask_question question,range,variable_to_set
{
_setcursor 16,0
mov si, question ; Print the question
call print
mov bx, range ; range accepted for answer
call getkey
cmp al, 27 ; If ESC was pressed, do not change the value
jz .esc_pressed
mov [variable_to_set], al
}
 
boot_read_floppy:
push si
xor si, si
mov ah, 2 ; read
@@:
push ax
int 0x13
pop ax
jnc @f
inc si
cmp si, 10
jb @b
sayerr_badsect:
mov si, badsect
sayerr_plain:
call printplain
jmp $
@@:
pop si
ret
 
; 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]
xor dx, dx
div bx
inc dx
mov cl, dl ; cl = sector number
mov bx, word [BPB_NumHeads]
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
; needed variables
BPB_SecPerTrk dw 0 ; sectors per track
BPB_NumHeads dw 0 ; number of heads
BPB_FATSz16 dw 0 ; size of FAT
BPB_RootEntCnt dw 0 ; count of root dir. entries
BPB_BytsPerSec dw 0 ; bytes per sector
BPB_RsvdSecCnt dw 0 ; number of reserved sectors
BPB_TotSec16 dw 0 ; count of the sectors on the volume
BPB_SecPerClus db 0 ; number of sectors per cluster
BPB_NumFATs db 0 ; number of FAT tables
abs_sector_adj dw 0 ; adjustment to make abs. sector number
end_of_FAT dw 0 ; end of FAT table
FirstDataSector dw 0 ; begin of data
 
;=========================================================================
;
; 16 BIT CODE
;
;=========================================================================
 
include 'bootvesa.inc' ;Include source for boot vesa
if defined extended_primary_loader
include 'parsers.inc'
end if
 
start_of_code:
 
if defined extended_primary_loader
; save data from primary loader
mov word [cs:bootcallback], si
mov word [cs:bootcallback+2], ds
push cs
pop ds
mov [bootdevice], ax
mov [bootfs], bx
 
; set up stack
mov ax, (TMP_STACK_TOP and 0xF0000) shr 4
mov ss, ax
mov sp, TMP_STACK_TOP and 0xFFFF
 
; try to load configuration file
mov ax, 1
mov di, config_file_struct
call [bootcallback]
cld
push cs
pop es
; bx=0 - ok, bx=1 - part of file loaded, assume this is ok
cmp bx, 1
ja .config_bad
; configuration file was loaded, parse
; if length is too big, use first 0FFFFh bytes
test dx, dx
jz @f
mov ax, 0FFFFh
@@:
; ds:si will be pointer to current data, dx = limit
xchg ax, dx
push 4000h
pop ds
xor si, si
.parse_loop:
; skip spaces
cmp si, dx
jae .parse_done
lodsb
cmp al, ' '
jbe .parse_loop
dec si
; loop over all possible configuration values
mov bx, config_file_variables
.find_variant:
; get length
mov cx, [es:bx]
; zero length = end of list
jecxz .find_newline
; skip over length
inc bx
inc bx
mov di, bx
; skip over string
add bx, cx
; test whether we have at least cx symbols left
mov ax, cx
add ax, si
jc .next_variant1
cmp ax, dx
jae .next_variant1
; save current position
push si
; compare strings
repz cmpsb
jnz .next_variant2
; strings are equal; look for "=" with possible spaces before and after
@@:
cmp si, dx
jae .next_variant2
lodsb
cmp al, ' '
jbe @b
cmp al, '='
jnz .next_variant2
; ok, we found the true variant
; ignore saved position on the stack
pop ax
; call the parser
call word [es:bx]
; line parsed, find next
.find_newline:
cmp si, dx
jae .parse_done
lodsb
cmp al, 13
jz .parse_loop
cmp al, 10
jz .parse_loop
jmp .find_newline
.next_variant2:
; continue to the next variant, restoring current position
pop si
.next_variant1:
; continue to the next variant
; skip over the parser
inc bx
inc bx
jmp .find_variant
.parse_done:
.config_bad:
 
; set up segment registers
push cs
pop ds
else
cld
push 0
pop es
; \begin{diamond}[02.12.2005]
; if bootloader sets ax = 'KL', then ds:si points to loader block
cmp ax, 'KL'
jnz @f
mov word [cs:cfgmanager.loader_block], si
mov word [cs:cfgmanager.loader_block+2], ds
mov word [es:BOOT_LO.kernel_restart], kernel_restart_bootblock
@@:
; \end{diamond}[02.12.2005]
 
; if bootloader sets cx = 'HA' and dx = 'RD', then bx contains identifier of source disk
; (see comment to BOOT_LO.sys_disk and loader_doc.txt)
mov word [es:BOOT_LO.sys_disk], 'r1' ; default value: /rd/1
cmp cx, 'HA'
jnz no_hd_load
cmp dx, 'RD'
jnz no_hd_load
mov [es:BOOT_LO.sys_disk], bx
no_hd_load:
 
; set up stack
mov ax, (TMP_STACK_TOP and 0xF0000) shr 4
mov ss, ax
mov sp, TMP_STACK_TOP and 0xFFFF
; set up segment registers
push cs
pop ds
push cs
pop es
end if
 
; set videomode
mov ax, 3
int 0x10
 
if lang eq ru
; Load & set russian VGA font (RU.INC)
mov bp, RU_FNT1 ; RU_FNT1 - First part
mov bx, 1000h ; 768 bytes
mov cx, 30h ; 48 symbols
mov dx, 80h ; 128 - position of first symbol
mov ax, 1100h
int 10h
 
mov bp, RU_FNT2 ; RU_FNT2 -Second part
mov bx, 1000h ; 512 bytes
mov cx, 20h ; 32 symbols
mov dx, 0E0h ; 224 - position of first symbol
mov ax, 1100h
int 10h
; End set VGA russian font
else if lang eq et
mov bp, ET_FNT ; ET_FNT1
mov bx, 1000h ;
mov cx, 255 ; 256 symbols
xor dx, dx ; 0 - position of first symbol
mov ax, 1100h
int 10h
end if
 
; draw frames
push 0xb800
pop es
xor di, di
mov ah, 1*16+15
 
; draw top
mov si, d80x25_top
mov cx, d80x25_top_num * 80
@@:
lodsb
stosw
loop @b
; draw spaces
mov si, space_msg
mov dx, 25 - d80x25_top_num - d80x25_bottom_num
dfl1:
push si
mov cx, 80
@@:
lodsb
stosw
loop @b
pop si
dec dx
jnz dfl1
; draw bottom
mov si, d80x25_bottom
mov cx, d80x25_bottom_num * 80
@@:
lodsb
stosw
loop @b
 
mov byte [space_msg+80], 0 ; now space_msg is null terminated
 
_setcursor d80x25_top_num,0
 
 
; TEST FOR 386+
 
mov bx, 0x4000
pushf
pop ax
mov dx, ax
xor ax, bx
push ax
popf
pushf
pop ax
and ax, bx
and dx, bx
cmp ax, dx
jnz cpugood
mov si, not386
sayerr:
call print
jmp $
cpugood:
 
push 0
popf
 
; set up esp
movzx esp, sp
 
push 0
pop es
 
xor cx, cx
@@:
in al, 64h
test al, 2
loopnz @b
 
mov al, 0xf6 ; Сброс клавиатуры, разрешить сканирование
out 0x60, al
xor cx, cx
@@:
in al, 64h
test al, 1
loopz @b
in al, 0x60
 
;;;/diamond today 5.02.2008
; set keyboard typematic rate & delay
mov al, 0xf3
out 0x60, al
xor cx, cx
@@:
in al, 64h
test al, 1
loopz @b
in al, 0x60
mov al, 0
out 0x60, al
xor cx, cx
@@:
in al, 64h
test al, 1
loopz @b
in al, 0x60
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
sti
; --------------- APM ---------------------
and word [es:BOOT_LO.apm_version], 0 ; ver = 0.0 (APM not found)
mov ax, 0x5300
xor bx, bx
int 0x15
jc apm_end ; APM not found
test cx, 2
jz apm_end ; APM 32-bit protected-mode interface not supported
mov [es:BOOT_LO.apm_version], ax ; Save APM Version
mov [es:BOOT_LO.apm_flags], cx ; Save APM flags
 
; Write APM ver ----
and ax, 0xf0f
add ax, '00'
mov si, msg_apm
mov [si + 5], ah
mov [si + 7], al
_setcursor 0, 3
call printplain
; ------------------
 
mov ax, 0x5304 ; Disconnect interface
xor bx, bx
int 0x15
mov ax, 0x5303 ; Connect 32 bit mode interface
xor bx, bx
int 0x15
 
mov [es:BOOT_LO.apm_entry], ebx
mov [es:BOOT_LO.apm_code_32], ax
mov [es:BOOT_LO.apm_code_16], cx
mov [es:BOOT_LO.apm_data_16], dx
 
apm_end:
_setcursor d80x25_top_num, 0
 
if ~ defined extended_primary_loader
;CHECK current of code
cmp [cfgmanager.loader_block], -1
jz noloaderblock
les bx, [cfgmanager.loader_block]
cmp byte [es:bx], 1
mov si, loader_block_error
jnz sayerr
push 0
pop es
end if
 
noloaderblock:
; DISPLAY VESA INFORMATION
call print_vesa_info
call calc_vmodes_table
call check_first_parm ;check and enable cursor_pos
 
; \begin{diamond}[30.11.2005]
cfgmanager:
; settings:
; a) preboot_graph = graphical mode
; preboot_gprobe = probe this mode?
; b) preboot_biosdisk = use BIOS disks through V86 emulation? // (earlier was: preboot_dma = use DMA access?)
; c) preboot_debug = duplicates kernel debug output to the screen
; d) preboot_launcher = start the first app (right now it's LAUNCHER) after kernel is loaded?
; e) preboot_device = from where to boot?
 
; determine default settings
if ~ defined extended_primary_loader
mov [.bSettingsChanged], 0
end if
 
;.preboot_gr_end:
mov di, preboot_device
; if image in memory is present and [preboot_device] is uninitialized,
; set it to use this preloaded image
cmp byte [di], 0
jnz .preboot_device_inited
if defined extended_primary_loader
inc byte [di]
cmp byte [bootdevice], 'f' ; floppy?
jz .preboot_device_inited
inc byte [di]
else
cmp [.loader_block], -1
jz @f
les bx, [.loader_block]
test byte [es:bx+1], 1
jz @f
mov byte [di], 3
jmp .preboot_device_inited
@@:
; otherwise, set [preboot_device] to 1 (default value - boot from floppy)
mov byte [di], 1
end if
.preboot_device_inited:
; following 4 lines set variables to 1 if its current value is 0
cmp byte [di+preboot_dma-preboot_device], 1
adc byte [di+preboot_dma-preboot_device], 0
cmp byte [di+preboot_launcher-preboot_device], 1 ; Start LAUNCHER by default
adc byte [di+preboot_launcher-preboot_device], 0
_setcursor 5,2
 
mov si, linef
call printplain
mov si, start_msg
call print
mov si, time_msg
call print
; get start time
call .gettime
mov [.starttime], eax
mov word [.timer], .newtimer
mov word [.timer+2], cs
.printcfg:
 
_setcursor 9,0
mov si, current_cfg_msg
call print
mov si, curvideo_msg
call print
 
call draw_current_vmode
 
mov si, usebd_msg
cmp [preboot_biosdisk], 1
call .say_on_off
mov si, debug_mode_msg
cmp [preboot_debug], 1
call .say_on_off
mov si, launcher_msg
cmp [preboot_launcher], 1
call .say_on_off
mov si, preboot_device_msg
call print
mov al, [preboot_device]
if defined extended_primary_loader
and eax, 3
else
and eax, 7
end if
mov si, [preboot_device_msgs+eax*2]
call printplain
.show_remarks:
; show remarks in gray color
mov di, ((21-num_remarks)*80 + 2)*2
push 0xB800
pop es
mov cx, num_remarks
mov si, remarks
.write_remarks:
lodsw
push si
xchg ax, si
mov ah, 1*16+7 ; background: blue (1), foreground: gray (7)
push di
.write_remark:
lodsb
test al, al
jz @f
stosw
jmp .write_remark
@@:
pop di
pop si
add di, 80*2
loop .write_remarks
.wait:
_setcursor 25,0 ; out of screen
; set timer interrupt handler
cli
push 0
pop es
push dword [es:8*4]
pop dword [.oldtimer]
push dword [.timer]
pop dword [es:8*4]
; mov eax, [es:8*4]
; mov [.oldtimer], eax
; mov eax, [.timer]
; mov [es:8*4], eax
sti
; wait for keypressed
xor ax, ax
int 16h
push ax
; restore timer interrupt
; push 0
; pop es
mov eax, [.oldtimer]
mov [es:8*4], eax
mov [.timer], eax
 
_setcursor 7,0
mov si, space_msg
call printplain
; clear remarks and restore normal attributes
push es
mov di, ((21-num_remarks)*80 + 2)*2
push 0xB800
pop es
mov cx, num_remarks
mov ax, ' ' + (1*16 + 15)*100h
@@:
push cx
mov cx, 76
rep stosw
pop cx
add di, 4*2
loop @b
pop es
pop ax
; switch on key
cmp al, 13
jz .continue
or al, 20h
cmp al, 'a' ; select graphical mode
jz .change_a
cmp al, 'q' ; Trick to make 'A' key on azerty keyboard work
je .change_a
cmp al, 'b' ; use BIOS disks? // (selecting YES will make BIOS disks visible as /bd)
jz .change_b
cmp al, 'c' ; load kernel in debug mode?
jz .change_c
cmp al, 'd' ; start launcher after kernel is loaded?
jz .change_d
cmp al, 'e' ; select boot origin
jnz .show_remarks
; e) preboot_device = from where to boot?
if defined extended_primary_loader
_ask_question bdev,'13',preboot_device ; range accepted for answer: 1-3
else
_ask_question bdev,'14',preboot_device ; range accepted for answer: 1-4
end if
_setcursor 14,0
 
.d:
if ~ defined extended_primary_loader
mov [.bSettingsChanged], 1
end if
.esc_pressed:
call clear_vmodes_table ;clear vmodes_table
jmp .printcfg
 
.change_a:
call clear_vmodes_table ;clear vmodes_table
 
mov si, word [cursor_pos]
mov word [cursor_pos_old], si
.loops:
call draw_vmodes_table
_setcursor 25,0 ; out of screen
xor ax, ax
int 0x16
; call clear_table_cursor ;clear current position of cursor
 
mov si, word [cursor_pos]
 
cmp al, 27 ; If ESC was pressed, do not change the value
jnz @f ; Just exit the resolution selection box
 
mov si, word [cursor_pos_old]
mov word [cursor_pos], si
jmp .esc_pressed
@@:
cmp ah, 0x48;x,0x48E0 ; up
jne .down
cmp si, modes_table
jbe .loops
sub word [cursor_pos], size_of_step
jmp .loops
 
.down:
cmp ah, 0x50;x,0x50E0 ; down
jne .pgup
cmp word[es:si+10], -1
je .loops
add word [cursor_pos], size_of_step
jmp .loops
 
.pgup:
cmp ah, 0x49 ; page up
jne .pgdn
sub si, size_of_step*long_v_table
cmp si, modes_table
jae @f
mov si, modes_table
@@:
mov word [cursor_pos], si
mov si, word [home_cursor]
sub si, size_of_step*long_v_table
cmp si, modes_table
jae @f
mov si, modes_table
@@:
mov word [home_cursor], si
jmp .loops
 
.pgdn:
cmp ah, 0x51 ; page down
jne .enter
mov ax, [end_cursor]
add si, size_of_step*long_v_table
cmp si, ax
jb @f
mov si, ax
sub si, size_of_step
@@:
mov word [cursor_pos], si
mov si, word [home_cursor]
sub ax, size_of_step*long_v_table
add si, size_of_step*long_v_table
cmp si, ax
jb @f
mov si, ax
@@:
mov word [home_cursor], si
jmp .loops
 
.enter:
cmp al, 0x0D;x,0x1C0D ; enter
jne .loops
push word [cursor_pos]
pop bp
push word [es:bp]
pop word [x_save]
push word [es:bp+2]
pop word [y_save]
push word [es:bp+6]
pop word [number_vm]
mov word [preboot_graph], bp ;save choose
jmp .d
 
.change_b: ; b) preboot_biosdisk = use BIOS disks through V86 emulation?
; _setcursor 16,0
; mov si, ask_dma // (earlier was: preboot_dma = use DMA access?)
; call print
; mov bx, '13' ; range accepted for answer: 1-3
; call getkey
; mov [preboot_dma], al
_ask_question ask_bd,'12',preboot_biosdisk ; range accepted for answer: 1-2
_setcursor 11,0
jmp .d
.change_c: ; c) preboot_debug = duplicates kernel debug output to the screen
_ask_question ask_debug,'12',preboot_debug ; range accepted for answer: 1-2
_setcursor 12,0
jmp .d
.change_d: ; d) preboot_launcher = start the first app (right now it's LAUNCHER) after kernel is loaded?
_ask_question ask_launcher,'12',preboot_launcher ; range accepted for answer: 1-2
_setcursor 13,0
jmp .d
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
.say_on_off:
pushf
call print
mov si, on_msg
popf
jz @f
mov si, off_msg
@@:
jmp printplain
; novesa and vervesa strings are not used at the moment of executing this code
virtual at novesa
.oldtimer dd ?
.starttime dd ?
if ~ defined extended_primary_loader
.bSettingsChanged db ?
end if
.timer dd ?
end virtual
if ~ defined extended_primary_loader
.loader_block dd -1
end if
.gettime:
mov ah, 0
int 1Ah
xchg ax, cx
shl eax, 10h
xchg ax, dx
ret
.newtimer:
push ds
push cs
pop ds
pushf
call [.oldtimer]
pushad
call .gettime
sub eax, [.starttime]
if defined extended_primary_loader
sub ax, [preboot_timeout]
else
; bios 0x1A timer runs at ~18 ticks per second
sub ax, 18*PREBOOT_TIMEOUT
end if
jae .timergo
neg ax
add ax, 18-1
mov bx, 18
xor dx, dx
div bx
if lang eq ru
; подождите 5 секунд, 4/3/2 секунды, 1 секунду
cmp al, 5
mov cl, ' '
jae @f
cmp al, 1
mov cl, 0xE3 ; 'у' in cp866
jz @f
mov cl, 0xEB ; 'ы' in cp866
@@:
mov [time_str+9], cl
else if lang eq et
cmp al, 1
ja @f
mov byte [time_str+9], ' '
mov byte [time_str+10], ' '
@@:
else if lang eq sp
; esperar 5/4/3/2 segundos, 1 segundo
cmp al, 1
mov cl, 's'
ja @f
mov cl, ' '
@@:
mov [time_str+10], cl
else
; wait 5/4/3/2 seconds, 1 second
cmp al, 1
mov cl, 's'
ja @f
mov cl, ' '
@@:
mov [time_str+9], cl
end if
add al, '0'
mov [time_str+1], al
mov si, time_msg
_setcursor 7,0
call print
_setcursor 25,0
popad
pop ds
iret
.timergo:
push 0
pop es
mov eax, [.oldtimer]
mov [es:8*4], eax
mov sp, 0EC00h
.continue:
sti
_setcursor 6,0
mov si, space_msg
call printplain
call printplain
_setcursor 6,0
mov si, loading_msg
call print
_setcursor 16,0
if ~ defined extended_primary_loader
cmp [.bSettingsChanged], 0
jz .load
cmp [.loader_block], -1
jz .load
les bx, [.loader_block]
mov eax, [es:bx+3]
push ds
pop es
test eax, eax
jz .load
push eax
mov si, save_quest
call print
.waityn:
mov ah, 0
int 16h
or al, 20h
cmp al, 'n'
jz .loadc
if lang eq sp
cmp al, 's'
else
cmp al, 'y'
end if
jnz .waityn
call putchar
mov byte [space_msg+80], 186
 
pop eax
push cs
push .cont
push eax
retf ;call back
.loadc:
pop eax
.cont:
push cs
pop ds
mov si, space_msg
mov byte [si+80], 0
_setcursor 16,0
call printplain
_setcursor 16,0
.load:
end if
; \end{diamond}[02.12.2005]
 
; ASK GRAPHICS MODE
 
call set_vmode
 
; GRAPHICS ACCELERATION
; force yes
mov [es:BOOT_LO.mtrr], byte 1
 
; DMA ACCESS TO HD
 
mov al, [preboot_dma]
mov [es:BOOT_LO.dma], al
 
; Set kernel DEBUG mode - if nonzero, duplicates debug output to the screen.
mov al, [preboot_debug]
mov [es:BOOT_LO.debug_print], al ;// 0x901E
 
; Start the first app (right now it's LAUNCHER) after kernel is loaded?
mov al, [preboot_launcher]
mov [es:BOOT_LO.launcher_start], al ;// 0x901D
 
; BOOT DEVICE
 
mov al, [preboot_device]
if defined extended_primary_loader
cmp al, RD_LOAD_FROM_MEMORY
jnz @f
mov al, RD_LOAD_FROM_NONE
@@:
end if
mov [es:BOOT_LO.rd_load_from], al
 
; /sys path
mov eax, dword[preboot_syspath+0]
mov dword[es:BOOT_LO.syspath+0], eax
mov eax, dword[preboot_syspath+4]
mov dword[es:BOOT_LO.syspath+4], eax
mov eax, dword[preboot_syspath+8]
mov dword[es:BOOT_LO.syspath+8], eax
mov eax, dword[preboot_syspath+12]
mov dword[es:BOOT_LO.syspath+12], eax
 
 
; GET MEMORY MAP
include '../detect/biosmem.inc'
 
; READ DISKETTE TO MEMORY
 
cmp byte [es:BOOT_LO.rd_load_from], RD_LOAD_FROM_FLOPPY
jne no_sys_on_floppy
mov si, diskload
call print
xor ax, ax ; reset drive
xor dx, dx
int 0x13
; do we boot from CD-ROM?
mov ah, 41h
mov bx, 55AAh
xor dx, dx
int 0x13
jc .nocd
cmp bx, 0AA55h
jnz .nocd
mov ah, 48h
push ds
push es
pop ds
mov si, 0xa000
mov word [si], 30
int 0x13
pop ds
jc .nocd
push ds
lds si, [es:si+26]
test byte [ds:si+10], 40h
pop ds
jz .nocd
; yes - read all floppy by 18 sectors
 
; TODO: !!!! read only first sector and set variables !!!!!
; ...
; TODO: !!! then read flippy image track by track
mov cx, 0x0001 ; startcyl,startsector
.a1:
push cx dx
mov al, 18
mov bx, 0xa000
call boot_read_floppy
mov si, movedesc
push es
push ds
pop es
mov cx, 256*18
mov ah, 0x87
int 0x15
pop es
pop dx cx
test ah, ah
jnz sayerr_floppy
add dword [si+8*3+2], 512*18
inc dh
cmp dh, 2
jnz .a1
mov dh, 0
inc ch
cmp ch, 80
jae ok_sys_on_floppy
pusha
mov al, ch
shr ch, 2
add al, ch
aam
xchg al, ah
add ax, '00'
mov si, pros
mov [si], ax
call printplain
popa
jmp .a1
.nocd:
; no - read only used sectors from floppy
; now load floppy image to memory
; at first load boot sector and first FAT table
 
; read only first sector and fill variables
mov cx, 0x0001 ; first logical sector
xor dx, dx ; head = 0, drive = 0 (a:)
mov al, 1 ; read one sector
mov bx, 0xB000 ; es:bx -> data area
call boot_read_floppy
; fill the necessary parameters to work with a floppy
mov ax, word [es:bx+24]
mov word [BPB_SecPerTrk], ax
mov ax, word [es:bx+26]
mov word [BPB_NumHeads], ax
mov ax, word [es:bx+17]
mov word [BPB_RootEntCnt], ax
mov ax, word [es:bx+14]
mov word [BPB_RsvdSecCnt], ax
mov ax, word [es:bx+19]
mov word [BPB_TotSec16], ax
mov al, byte [es:bx+13]
mov byte [BPB_SecPerClus], al
mov al, byte [es:bx+16]
mov byte [BPB_NumFATs], al
;<Lrz> 18.11.2008
mov ax, word [es:bx+22]
mov word [BPB_FATSz16], ax
mov cx, word [es:bx+11]
mov word [BPB_BytsPerSec], cx
 
; count of clusters in FAT12 ((size_of_FAT*2)/3)
; mov ax, word [BPB_FATSz16]
; mov cx, word [BPB_BytsPerSec]
;end <Lrz> 18.11.2008
xor dx, dx
mul cx
shl ax, 1
mov cx, 3
div cx ; now ax - number of clusters in FAT12
mov word [end_of_FAT], ax
 
; load first FAT table
mov cx, 0x0002 ; startcyl,startsector ; TODO!!!!!
xor dx, dx ; starthead,drive
mov al, byte [BPB_FATSz16] ; no of sectors to read
add bx, word [BPB_BytsPerSec] ; es:bx -> data area
call boot_read_floppy
mov bx, 0xB000
 
; and copy them to extended memory
mov si, movedesc
mov [si+8*2+3], bh ; from
mov ax, word [BPB_BytsPerSec]
shr ax, 1 ; words per sector
mov cx, word [BPB_RsvdSecCnt]
add cx, word [BPB_FATSz16]
mul cx
push ax ; save to stack count of words in boot+FAT
xchg ax, cx
push es
push ds
pop es
mov ah, 0x87
int 0x15
pop es
test ah, ah
jz @f
sayerr_floppy:
mov dx, 0x3f2
mov al, 0
out dx, al
sayerr_memmove:
mov si, memmovefailed
jmp sayerr_plain
@@:
pop ax ; restore from stack count of words in boot+FAT
shl ax, 1 ; make bytes count from count of words
and eax, 0ffffh
add dword [si+8*3+2], eax
 
; copy first FAT to second copy
; TODO: BPB_NumFATs !!!!!
add bx, word [BPB_BytsPerSec] ; !!! TODO: may be need multiply by BPB_RsvdSecCnt !!!
mov byte [si+8*2+3], bh ; bx - begin of FAT
mov ax, word [BPB_BytsPerSec]
shr ax, 1 ; words per sector
mov cx, word [BPB_FATSz16]
mul cx
mov cx, ax ; cx - count of words in FAT
 
push es
push ds
pop es
mov ah, 0x87
int 0x15
pop es
test ah, ah
jnz sayerr_floppy
mov ax, cx
shl ax, 1
and eax, 0ffffh ; ax - count of bytes in FAT
add dword [si+8*3+2], eax
; reading RootDir
; TODO: BPB_NumFATs
add bx, ax
add bx, 100h
and bx, 0ff00h ; bx - place in buffer to write RootDir
push bx
 
mov bx, word [BPB_BytsPerSec]
shr bx, 5 ; divide bx by 32
mov ax, word [BPB_RootEntCnt]
xor dx, dx
div bx
push ax ; ax - count of RootDir sectors
 
mov ax, word [BPB_FATSz16]
xor cx, cx
mov cl, byte [BPB_NumFATs]
mul cx
add ax, word [BPB_RsvdSecCnt] ; ax - first sector of RootDir
 
mov word [FirstDataSector], ax
pop bx
push bx
add word [FirstDataSector], bx ; Begin of data region of floppy
; read RootDir
call conv_abs_to_THS
pop ax
pop bx ; place in buffer to write
push ax
call boot_read_floppy ; read RootDir into buffer
; copy RootDir
mov byte [si+8*2+3], bh ; from buffer
pop ax ; ax = count of RootDir sectors
mov cx, word [BPB_BytsPerSec]
mul cx
shr ax, 1
mov cx, ax ; count of words to copy
push es
push ds
pop es
mov ah, 0x87
int 0x15
pop es
 
mov ax, cx
shl ax, 1
and eax, 0ffffh ; ax - count of bytes in RootDir
add dword [si+8*3+2], eax ; add count of bytes copied
 
; Reading data clusters from floppy
mov byte [si+8*2+3], bh
push bx
 
mov di, 2 ; First data cluster
.read_loop:
mov bx, di
shr bx, 1 ; bx+di = di*1.5
jnc .even
test word [es:bx+di+0xB200], 0xFFF0 ; TODO: may not be 0xB200 !!!
jmp @f
.even:
test word [es:bx+di+0xB200], 0xFFF ; TODO: may not be 0xB200 !!!
 
@@:
jz .skip
; read cluster di
;.read:
;conv cluster di to abs. sector ax
; ax = (N-2) * BPB_SecPerClus + FirstDataSector
mov ax, di
sub ax, 2
xor bx, bx
mov bl, byte [BPB_SecPerClus]
mul bx
add ax, word [FirstDataSector]
call conv_abs_to_THS
pop bx
push bx
mov al, byte [BPB_SecPerClus] ; number of sectors in cluster
call boot_read_floppy
push es
push ds
pop es
pusha
;
mov ax, word [BPB_BytsPerSec]
xor cx, cx
mov cl, byte [BPB_SecPerClus]
mul cx
shr ax, 1 ; ax = (BPB_BytsPerSec * BPB_SecPerClus)/2
mov cx, ax ; number of words to copy (count words in cluster)
;
mov ah, 0x87
int 0x15 ; copy data
test ah, ah
popa
pop es
jnz sayerr_floppy
; skip cluster di
.skip:
mov ax, word [BPB_BytsPerSec]
xor cx, cx
mov cl, byte [BPB_SecPerClus]
mul cx
and eax, 0ffffh ; ax - count of bytes in cluster
add dword [si+8*3+2], eax
 
mov ax, word [end_of_FAT] ; max cluster number
pusha
; draw percentage
; total clusters: ax
; read clusters: di
xchg ax, di
mov cx, 100
mul cx
div di
aam
xchg al, ah
add ax, '00'
mov si, pros
cmp [si], ax
jz @f
mov [si], ax
call printplain
@@:
popa
inc di
cmp di, word [end_of_FAT] ; max number of cluster
jnz .read_loop
pop bx ; clear stack
 
ok_sys_on_floppy:
mov si, backspace2
call printplain
mov si, okt
call printplain
no_sys_on_floppy:
xor ax, ax ; reset drive
xor dx, dx
int 0x13
mov dx, 0x3f2 ; floppy motor off
mov al, 0
out dx, al
 
if defined extended_primary_loader
cmp [es:BOOT_LO.rd_load_from], RD_LOAD_FROM_HD
jne no_sys_from_primary
; load kolibri.img using callback from primary loader
and word [movedesc + 24 + 2], 0
mov byte [movedesc + 24 + 4], 10h
; read in blocks of 64K until file is fully loaded
mov ax, 1
.repeat:
mov di, image_file_struct
call [bootcallback]
push cs
pop ds
push cs
pop es
cmp bx, 1
ja sayerr_badsect
push bx
mov si, movedesc
and word [si + 16 + 2], 0
mov byte [si + 16 + 4], 4
mov ah, 87h
mov cx, 8000h
int 15h
pop bx
test ah, ah
jnz sayerr_memmove
inc byte [si + 24 + 4]
test bx, bx
jz no_sys_from_primary
mov ax, 2
jmp .repeat
no_sys_from_primary:
end if
 
; SET GRAPHICS
 
xor ax, ax
mov es, ax
 
mov ax, [es:BOOT_LO.vesa_mode] ; vga & 320x200
mov bx, ax
cmp ax, 0x13
je setgr
cmp ax, 0x12
je setgr
mov ax, 0x4f02 ; Vesa
setgr:
int 0x10
test ah, ah
mov si, fatalsel
jnz v_mode_error
; set mode 0x12 graphics registers:
cmp bx, 0x12
jne gmok2
 
mov al, 0x05
mov dx, 0x03ce
push dx
out dx, al ; select GDC mode register
mov al, 0x02
inc dx
out dx, al ; set write mode 2
 
mov al, 0x02
mov dx, 0x03c4
out dx, al ; select VGA sequencer map mask register
mov al, 0x0f
inc dx
out dx, al ; set mask for all planes 0-3
 
mov al, 0x08
pop dx
out dx, al ; select GDC bit mask register
; for writes to 0x03cf
gmok2:
push ds
pop es
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/bootru.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/preboot.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/rdload.inc
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:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/bootet.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/bootstr.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/bootge.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/et.inc
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"
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/ru.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot/ETFONT.FNT
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/boot
Property changes:
Added: svn:ignore
+booteng.inc
/kernel/branches/kolibrios-pe-clevermouse/bus/pci/PCIe.inc
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 >>>>>>>>>
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/pci/pci32.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/pci/pci16.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/pci
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/bus/usb/hccommon.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/usb/memory.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/usb/hub.inc
0,0 → 1,1285
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
; Support for USB (non-root) hubs:
; powering up/resetting/disabling ports,
; watching for adding/removing devices.
 
; =============================================================================
; ================================= Constants =================================
; =============================================================================
; Hub constants
; USB hub descriptor type
USB_HUB_DESCRIPTOR = 29h
 
; Features for CLEAR_FEATURE commands to the hub.
C_HUB_LOCAL_POWER = 0
C_HUB_OVER_CURRENT = 1
 
; Bits in result of GET_STATUS command for a port.
; Also suitable for CLEAR_FEATURE/SET_FEATURE commands, where applicable,
; except TEST/INDICATOR.
PORT_CONNECTION = 0
PORT_ENABLE = 1
PORT_SUSPEND = 2
PORT_OVER_CURRENT = 3
PORT_RESET = 4
PORT_POWER = 8
PORT_LOW_SPEED = 9
PORT_HIGH_SPEED = 10
PORT_TEST_BIT = 11
PORT_INDICATOR_BIT = 12
C_PORT_CONNECTION = 16
C_PORT_ENABLE = 17
C_PORT_SUSPEND = 18
C_PORT_OVER_CURRENT = 19
C_PORT_RESET = 20
PORT_TEST_FEATURE = 21
PORT_INDICATOR_FEATURE = 22
 
; Internal constants
; Bits in usb_hub.Actions
HUB_WAIT_POWERED = 1
; ports were powered, wait until power is stable
HUB_WAIT_CONNECT = 2
; some device was connected, wait initial debounce interval
HUB_RESET_IN_PROGRESS = 4
; reset in progress, so buffer for config requests is owned
; by reset process; this includes all stages from initial disconnect test
; to end of setting address (fail on any stage should lead to disabling port,
; which requires a config request)
HUB_RESET_WAITING = 8
; the port is ready for reset, but another device somewhere on the bus
; is resetting. Implies HUB_RESET_IN_PROGRESS
HUB_RESET_SIGNAL = 10h
; reset signalling is active for some port in the hub
; Implies HUB_RESET_IN_PROGRESS
HUB_RESET_RECOVERY = 20h
; reset recovery is active for some port in the hub
; Implies HUB_RESET_IN_PROGRESS
 
; Well, I think that those 5 flags WAIT_CONNECT and RESET_* require additional
; comments. So that is the overview of what happens with a new device assuming
; no errors.
; * device is connected;
; * hub notifies us about connect event; after some processing
; usb_hub_port_change finally processes that event, setting the flag
; HUB_WAIT_CONNECT and storing time when the device was connected;
; * 100 ms delay;
; * usb_hub_process_deferred clears HUB_WAIT_CONNECT,
; sets HUB_RESET_IN_PROGRESS, stores the port index in ConfigBuffer and asks
; the hub whether there was a disconnect event for that port during those
; 100 ms (on the hardware level notifications are obtained using polling
; with some intervals, so it is possible that the corresponding notification
; has not arrived yet);
; * usb_hub_connect_port_status checks that there was no disconnect event
; and sets HUB_RESET_WAITING flag (HUB_RESET_IN_PROGRESS is still set,
; ConfigBuffer still contains the port index);
; * usb_hub_process_deferred checks whether there is another device currently
; resetting. If so, it waits until reset is done
; (with HUB_RESET_WAITING and HUB_RESET_IN_PROGRESS bits set);
; * usb_hub_process_deferred clears HUB_RESET_WAITING, sets HUB_RESET_SIGNAL
; and initiates reset signalling on the port;
; * usb_hub_process_deferred checks the status every tick;
; when reset signalling is stopped by the hub, usb_hub_resetting_port_status
; callback clears HUB_RESET_SIGNAL and sets HUB_RESET_RECOVERY;
; * 10 ms (at least) delay;
; * usb_hub_process_deferred clears HUB_RESET_RECOVERY and notifies other code
; that the new device is ready to be configured;
; * when it is possible to reset another device, the protocol layer
; clears HUB_RESET_IN_PROGRESS bit.
 
; =============================================================================
; ================================ Structures =================================
; =============================================================================
; This structure contains all used data for one hub.
struct usb_hub
; All configured hubs are organized in the global usb_hub_list.
; Two following fields give next/prev items in that list.
; While the hub is unconfigured, they point to usb_hub itself.
Next dd ?
Prev dd ?
Controller dd ?
; Pointer to usb_controller for the bus.
;
; Handles of two pipes: configuration control pipe for zero endpoint opened by
; the common code and status interrupt pipe opened by us.
ConfigPipe dd ?
StatusPipe dd ?
NumPorts dd ?
; Number of downstream ports; from 1 to 255.
MaxPacketSize dd ?
; Maximum packet size for interrupt endpoint.
; Usually equals ceil((1+NumPorts)/8), but some hubs give additional bytes.
Actions dd ?
; Bitfield with HUB_* constants.
PoweredOnTime dd ?
; Time (in ticks) when all downstream ports were powered up.
ResetTime dd ?
; Time (in ticks) when the current port was reset;
; when a port is resetting, contains the last tick of status check;
; when reset recovery for a port is active, contains the time when
; reset was completed.
;
; There are two possible reasons for configuration requests:
; synchronous, when certain time is passed after something,
; and asynchronous, when the hub is notifying about some change and
; config request needs to be issued in order to query details.
; Use two different buffers to avoid unnecessary dependencies.
ConfigBuffer rb 8
; Buffer for configuration requests for synchronous events.
ChangeConfigBuffer rb 8
; Buffer for configuration requests for status changes.
AccStatusChange db ?
; Accumulated status change. See 11.12.3 of USB2 spec or comments in code.
HubCharacteristics dw ?
; Copy of usb_hub_descr.wHubCharacteristics.
PowerOnInterval db ?
; Copy of usb_hub_descr.bPwrOn2PwrGood.
;
; Two following fields are written at once by GET_STATUS request
; and must remain in this order.
StatusData dw ?
; Bitfield with 1 shl PORT_* indicating status of the current port.
StatusChange dw ?
; Bitfield with 1 shl PORT_* indicating change in status of the current port.
; Two following fields are written at once by GET_STATUS request
; and must remain in this order.
; The meaning is the same as of StatusData/StatusChange; two following fields
; are used by the synchronous requests to avoid unnecessary interactions with
; the asynchronous handler.
ResetStatusData dw ?
ResetStatusChange dw ?
StatusChangePtr dd ?
; Pointer to StatusChangeBuf.
ConnectedDevicesPtr dd ?
; Pointer to ConnectedDevices.
ConnectedTimePtr dd ?
; Pointer to ConnectedTime.
;
; Variable-length parts:
; DeviceRemovable rb (NumPorts+8)/8
; Bit i+1 = device at port i (zero-based) is non-removable.
; StatusChangeBuf rb (NumPorts+8)/8
; Buffer for status interrupt pipe. Bit 0 = hub status change,
; other bits = status change of the corresponding ports.
; ConnectedDevices rd NumPorts
; Pointers to config pipes for connected devices or zero if no device connected.
; ConnectedTime rd NumPorts
; For initial debounce interval:
; time (in ticks) when a device was connected at that port.
; Normally: -1
ends
 
; Hub descriptor.
struct usb_hub_descr usb_descr
bNbrPorts db ?
; Number of downstream ports.
wHubCharacteristics dw ?
; Bit 0: 0 = all ports are powered at once, 1 = individual port power switching
; Bit 1: reserved, must be zero
; Bit 2: 1 = the hub is part of a compound device
; Bits 3-4: 00 = global overcurrent protection,
; 01 = individual port overcurrent protection,
; 1x = no overcurrent protection
; Bits 5-6: Transaction Translator Think Time, 8*(value+1) full-speed bit times
; Bit 7: 1 = port indicators supported
; Other bits are reserved.
bPwrOn2PwrGood db ?
; Time in 2ms intervals between powering up a port and a port becoming ready.
bHubContrCurrent db ?
; Maximum current requirements of the Hub Controller electronics in mA.
; DeviceRemovable - variable length
; Bit 0 is reserved, bit i+1 = device at port i is non-removable.
; PortPwrCtrlMask - variable length
; Obsolete, exists for compatibility. We ignore it.
ends
 
iglobal
align 4
; Implementation of struct USBFUNC for hubs.
usb_hub_callbacks:
dd usb_hub_callbacks_end - usb_hub_callbacks
dd usb_hub_init
dd usb_hub_disconnect
usb_hub_callbacks_end:
usb_hub_pseudosrv dd usb_hub_callbacks
endg
 
; This procedure is called when new hub is detected.
; It initializes the device.
; Technically, initialization implies sending several USB queries,
; so it is split in several procedures. The first is usb_hub_init,
; other are callbacks which will be called at some time in the future,
; when the device will respond.
; edx = usb_interface_descr, ecx = length rest
proc usb_hub_init
push ebx esi ; save used registers to be stdcall
virtual at esp
rd 2 ; saved registers
dd ? ; return address
.pipe dd ? ; handle of the config pipe
.config dd ? ; pointer to usb_config_descr
.interface dd ? ; pointer to usb_interface_descr
end virtual
; 1. Check that the maximal nesting is not exceeded:
; 5 non-root hubs is the maximum according to the spec.
mov ebx, [.pipe]
push 5
mov eax, ebx
.count_parents:
mov eax, [eax+usb_pipe.DeviceData]
mov eax, [eax+usb_device_data.Hub]
test eax, eax
jz .depth_ok
mov eax, [eax+usb_hub.ConfigPipe]
dec dword [esp]
jnz .count_parents
pop eax
dbgstr 'Hub chain is too long'
jmp .return0
.depth_ok:
pop eax
; Hubs use one IN interrupt endpoint for polling the device
; 2. Locate the descriptor of the interrupt endpoint.
; Loop over all descriptors owned by this interface.
.lookep:
; 2a. Skip the current descriptor.
movzx eax, [edx+usb_descr.bLength]
add edx, eax
sub ecx, eax
jb .errorep
; 2b. Length of data left must be at least sizeof.usb_endpoint_descr.
cmp ecx, sizeof.usb_endpoint_descr
jb .errorep
; 2c. If we have found another interface descriptor but not found our endpoint,
; this is an error: all subsequent descriptors belong to that interface
; (or further interfaces).
cmp [edx+usb_endpoint_descr.bDescriptorType], USB_INTERFACE_DESCR
jz .errorep
; 2d. Ignore all interface-related descriptors except endpoint descriptor.
cmp [edx+usb_endpoint_descr.bDescriptorType], USB_ENDPOINT_DESCR
jnz .lookep
; 2e. Length of endpoint descriptor must be at least sizeof.usb_endpoint_descr.
cmp [edx+usb_endpoint_descr.bLength], sizeof.usb_endpoint_descr
jb .errorep
; 2f. Ignore all endpoints except for INTERRUPT IN.
cmp [edx+usb_endpoint_descr.bEndpointAddress], 0
jge .lookep
mov al, [edx+usb_endpoint_descr.bmAttributes]
and al, 3
cmp al, INTERRUPT_PIPE
jnz .lookep
; We have located the descriptor for INTERRUPT IN endpoint,
; the pointer is in edx.
; 3. Allocate memory for the hub descriptor.
; Maximum length (assuming 255 downstream ports) is 40 bytes.
; Allocate 4 extra bytes to keep wMaxPacketSize.
; 3a. Save registers.
push edx
; 3b. Call the allocator.
movi eax, 44
call malloc
; 3c. Restore registers.
pop ecx
; 3d. If failed, say something to the debug board and return error.
test eax, eax
jz .nomemory
; 3e. Store the pointer in esi. xchg eax,r32 is one byte shorter than mov.
xchg esi, eax
; 4. Open a pipe for the status endpoint with descriptor found in step 1.
movzx eax, [ecx+usb_endpoint_descr.bEndpointAddress]
movzx edx, [ecx+usb_endpoint_descr.bInterval]
movzx ecx, [ecx+usb_endpoint_descr.wMaxPacketSize]
test ecx, (1 shl 11) - 1
jz .free
push ecx
stdcall usb_open_pipe, ebx, eax, ecx, INTERRUPT_PIPE, edx
pop ecx
; If failed, free the memory allocated in step 3,
; say something to the debug board and return error.
test eax, eax
jz .free
; 5. Send control query for the hub descriptor,
; pass status pipe as a callback parameter,
; allow short packets.
and ecx, (1 shl 11) - 1
mov [esi+40], ecx
mov dword [esi], 0xA0 + \ ; class-specific request
(USB_GET_DESCRIPTOR shl 8) + \
(0 shl 16) + \ ; descriptor index 0
(USB_HUB_DESCRIPTOR shl 24)
mov dword [esi+4], 40 shl 16
stdcall usb_control_async, ebx, esi, esi, 40, usb_hub_got_config, eax, 1
; 6. If failed, free the memory allocated in step 3,
; say something to the debug board and return error.
test eax, eax
jz .free
; Otherwise, return 1. usb_hub_got_config will overwrite it later.
xor eax, eax
inc eax
jmp .nothing
.free:
xchg eax, esi
call free
jmp .return0
.errorep:
dbgstr 'Invalid config descriptor for a hub'
jmp .return0
.nomemory:
dbgstr 'No memory for USB hub data'
.return0:
xor eax, eax
.nothing:
pop esi ebx ; restore used registers to be stdcall
retn 12
endp
 
; This procedure is called when the request for the hub descriptor initiated
; by usb_hub_init is finished, either successfully or unsuccessfully.
proc usb_hub_got_config stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
push ebx ; save used registers to be stdcall
; 1. If failed, say something to the debug board, free the buffer
; and stop the initialization.
cmp [status], 0
jnz .invalid
; 2. The length must be at least sizeof.usb_hub_descr.
; Note that [length] includes 8 bytes of setup packet.
cmp [length], 8 + sizeof.usb_hub_descr
jb .invalid
; 3. Sanity checks for the hub descriptor.
mov eax, [buffer]
if USB_DUMP_DESCRIPTORS
mov ecx, [length]
sub ecx, 8
DEBUGF 1,'K : hub config:'
push eax
@@:
DEBUGF 1,' %x',[eax]:2
inc eax
dec ecx
jnz @b
DEBUGF 1,'\n'
pop eax
end if
cmp [eax+usb_hub_descr.bLength], sizeof.usb_hub_descr
jb .invalid
cmp [eax+usb_hub_descr.bDescriptorType], USB_HUB_DESCRIPTOR
jnz .invalid
movzx ecx, [eax+usb_hub_descr.bNbrPorts]
test ecx, ecx
jz .invalid
; 4. We use sizeof.usb_hub_descr bytes plus DeviceRemovable info;
; size of DeviceRemovable is (NumPorts+1) bits, this gives
; floor(NumPorts/8)+1 bytes. Check that all data are present in the
; descriptor and were successfully read.
mov edx, ecx
shr edx, 3
add edx, sizeof.usb_hub_descr + 1
cmp [eax+usb_hub_descr.bLength], dl
jb .invalid
sub [length], 8
cmp [length], edx
jb .invalid
; 5. Allocate the memory for usb_hub structure.
; Total size of variable-length data is ALIGN_UP(floor(NumPorts/8)+1+MaxPacketSize,4)+8*NumPorts.
add edx, [eax+40]
add edx, sizeof.usb_hub - sizeof.usb_hub_descr + 3
and edx, not 3
lea eax, [edx+ecx*8]
push ecx edx
call malloc
pop edx ecx
test eax, eax
jz .nomemory
xchg eax, ebx
; 6. Fill usb_hub structure.
mov [ebx+usb_hub.NumPorts], ecx
add edx, ebx
mov [ebx+usb_hub.ConnectedDevicesPtr], edx
mov eax, [pipe]
mov [ebx+usb_hub.ConfigPipe], eax
mov edx, [eax+usb_pipe.Controller]
mov [ebx+usb_hub.Controller], edx
mov eax, [calldata]
mov [ebx+usb_hub.StatusPipe], eax
push esi edi
mov esi, [buffer]
mov eax, [esi+40]
mov [ebx+usb_hub.MaxPacketSize], eax
; The following commands load bNbrPorts, wHubCharacteristics, bPwrOn2PwrGood.
mov edx, dword [esi+usb_hub_descr.bNbrPorts]
mov dl, 0
; The following command zeroes AccStatusChange and stores
; HubCharacteristics and PowerOnInterval.
mov dword [ebx+usb_hub.AccStatusChange], edx
xor eax, eax
mov [ebx+usb_hub.Actions], eax
; Copy DeviceRemovable data.
lea edi, [ebx+sizeof.usb_hub]
add esi, sizeof.usb_hub_descr
mov edx, ecx
shr ecx, 3
inc ecx
rep movsb
mov [ebx+usb_hub.StatusChangePtr], edi
; Zero ConnectedDevices.
mov edi, [ebx+usb_hub.ConnectedDevicesPtr]
mov ecx, edx
rep stosd
mov [ebx+usb_hub.ConnectedTimePtr], edi
; Set ConnectedTime to -1.
dec eax
mov ecx, edx
rep stosd
pop edi esi
; 7. Replace value of 1 returned from usb_hub_init to the real value.
; Note: hubs are part of the core USB code, so this code can work with
; internals of other parts. Another way, the only possible one for external
; drivers, is to use two memory allocations: one (returned from AddDevice and
; fixed after that) for pointer, another for real data. That would work also,
; but wastes one allocation.
mov eax, [pipe]
mov eax, [eax+usb_pipe.DeviceData]
add eax, [eax+usb_device_data.Interfaces]
.scan:
cmp [eax+usb_interface_data.DriverData], 1
jnz @f
cmp [eax+usb_interface_data.DriverFunc], usb_hub_pseudosrv - USBSRV.usb_func
jz .scan_found
@@:
add eax, sizeof.usb_interface_data
jmp .scan
.scan_found:
mov [eax+usb_interface_data.DriverData], ebx
; 8. Insert the hub structure to the tail of the overall list of all hubs.
mov ecx, usb_hubs_list
mov edx, [ecx+usb_hub.Prev]
mov [ecx+usb_hub.Prev], ebx
mov [edx+usb_hub.Next], ebx
mov [ebx+usb_hub.Prev], edx
mov [ebx+usb_hub.Next], ecx
; 9. Start powering up all ports.
DEBUGF 1,'K : found hub with %d ports\n',[ebx+usb_hub.NumPorts]
lea eax, [ebx+usb_hub.ConfigBuffer]
xor ecx, ecx
mov dword [eax], 23h + \ ; class-specific request to hub port
(USB_SET_FEATURE shl 8) + \
(PORT_POWER shl 16)
mov edx, [ebx+usb_hub.NumPorts]
mov dword [eax+4], edx
stdcall usb_control_async, [ebx+usb_hub.ConfigPipe], eax, ecx, ecx, usb_hub_port_powered, ebx, ecx
.freebuf:
; 10. Free the buffer for hub descriptor and return.
mov eax, [buffer]
call free
pop ebx ; restore used registers to be stdcall
ret
.nomemory:
dbgstr 'No memory for USB hub data'
jmp .freebuf
.invalid:
dbgstr 'Invalid hub descriptor'
jmp .freebuf
endp
 
; This procedure is called when the request to power up some port is completed,
; either successfully or unsuccessfully.
proc usb_hub_port_powered stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; 1. Check whether the operation was successful.
; If not, say something to the debug board and ssstop the initialization.
cmp [status], 0
jnz .invalid
; 2. Check whether all ports were powered.
; If so, go to 4. Otherwise, proceed to 3.
mov eax, [calldata]
dec dword [eax+usb_hub.ConfigBuffer+4]
jz .done
; 3. Power up the next port and return.
lea edx, [eax+usb_hub.ConfigBuffer]
xor ecx, ecx
stdcall usb_control_async, [eax+usb_hub.ConfigPipe], edx, ecx, ecx, usb_hub_port_powered, eax, ecx
.nothing:
ret
.done:
; 4. All ports were powered.
; The hub requires some delay until power will be stable, the delay value
; is provided in the hub descriptor; we have copied that value to
; usb_hub.PowerOnInterval. Note the time and set the corresponding flag
; for usb_hub_process_deferred.
mov ecx, [timer_ticks]
mov [eax+usb_hub.PoweredOnTime], ecx
or [eax+usb_hub.Actions], HUB_WAIT_POWERED
jmp .nothing
.invalid:
dbgstr 'Error while powering hub ports'
jmp .nothing
endp
 
; Requests notification about any changes in hub/ports configuration.
; Called when initial configuration is done and when a previous notification
; has been processed.
proc usb_hub_wait_change
stdcall usb_normal_transfer_async, [eax+usb_hub.StatusPipe], \
[eax+usb_hub.StatusChangePtr], [eax+usb_hub.MaxPacketSize], usb_hub_changed, eax, 1
ret
endp
 
; This procedure is called when something has changed on the hub.
proc usb_hub_changed stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; DEBUGF 1,'K : [%d] int pipe for hub %x\n',[timer_ticks],[calldata]
; 1. Check whether our request has failed.
; If so, say something to the debug board and stop processing notifications.
xor ecx, ecx
cmp [status], ecx
jnz .failed
; 2. If no data were retrieved, restart waiting.
mov eax, [calldata]
cmp [length], ecx
jz .continue
; 3. If size of data retrieved is less than maximal, pad with zeroes;
; this corresponds to 'state of other ports was not changed'
mov ecx, [eax+usb_hub.NumPorts]
shr ecx, 3
inc ecx
sub ecx, [length]
jbe .restart
push eax edi
mov edi, [buffer]
add edi, [length]
xor eax, eax
rep stosb
pop edi eax
.restart:
; State of some elements of the hub was changed.
; Find the first element that was changed,
; ask the hub about nature of the change,
; clear the corresponding change,
; reask the hub about status+change (it is possible that another change
; occurs between the first ask and clearing the change; we won't see that
; change, so we need to query the status after clearing the change),
; continue two previous steps until nothing changes,
; process all changes which were registered.
; When all changes for one element will be processed, return to here and look
; for other changed elements.
mov edx, [eax+usb_hub.StatusChangePtr]
; We keep all observed changes in the special var usb_hub.AccStatusChange;
; it will be logical OR of all observed StatusChange's.
; 4. No observed changes yet, zero usb_hub.AccStatusChange.
xor ecx, ecx
mov [eax+usb_hub.AccStatusChange], cl
; 5. Test whether there was a change in the hub itself.
; If so, query hub state.
btr dword [edx], ecx
jnc .no_hub_change
.next_hub_change:
; DEBUGF 1,'K : [%d] querying status of hub %x\n',[timer_ticks],eax
lea edx, [eax+usb_hub.ChangeConfigBuffer]
lea ecx, [eax+usb_hub.StatusData]
mov dword [edx], 0A0h + \ ; class-specific request from hub itself
(USB_GET_STATUS shl 8)
mov dword [edx+4], 4 shl 16 ; get 4 bytes
stdcall usb_control_async, [eax+usb_hub.ConfigPipe], edx, ecx, 4, usb_hub_status, eax, 0
jmp .nothing
.no_hub_change:
; 6. Find the first port with changed state and clear the corresponding bit
; (so next scan after .restart will not consider this port again).
; If found, go to 8. Otherwise, advance to 7.
inc ecx
.test_port_change:
btr [edx], ecx
jc .found_port_change
inc ecx
cmp ecx, [eax+usb_hub.NumPorts]
jbe .test_port_change
.continue:
; 7. All changes have been processed. Wait for next notification.
call usb_hub_wait_change
.nothing:
ret
.found_port_change:
mov dword [eax+usb_hub.ChangeConfigBuffer+4], ecx
.next_port_change:
; 8. Query port state. Continue work in usb_hub_port_status callback.
; movzx ecx, [eax+usb_hub.ChangeConfigBuffer+4]
; dec ecx
; DEBUGF 1,'K : [%d] querying status of hub %x port %d\n',[timer_ticks],eax,ecx
lea edx, [eax+usb_hub.ChangeConfigBuffer]
mov dword [edx], 0A3h + \ ; class-specific request from hub port
(USB_GET_STATUS shl 8)
mov byte [edx+6], 4 ; data length = 4 bytes
lea ecx, [eax+usb_hub.StatusData]
stdcall usb_control_async, [eax+usb_hub.ConfigPipe], edx, ecx, 4, usb_hub_port_status, eax, 0
jmp .nothing
.failed:
cmp [status], USB_STATUS_CLOSED
jz .nothing
dbgstr 'Querying hub notification failed'
jmp .nothing
endp
 
; This procedure is called when the request of hub status is completed,
; either successfully or unsuccessfully.
proc usb_hub_status stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; 1. Check whether our request has failed.
; If so, say something to the debug board and stop processing notifications.
cmp [status], 0
jnz .failed
; 2. Accumulate observed changes.
mov eax, [calldata]
mov dl, byte [eax+usb_hub.StatusChange]
or [eax+usb_hub.AccStatusChange], dl
.next_change:
; 3. Find the first change. If found, advance to 4. Otherwise, go to 5.
mov cl, C_HUB_OVER_CURRENT
btr dword [eax+usb_hub.StatusChange], 1
jc .clear_hub_change
mov cl, C_HUB_LOCAL_POWER
btr dword [eax+usb_hub.StatusChange], 0
jnc .final
.clear_hub_change:
; 4. Clear the change and continue in usb_hub_change_cleared callback.
lea edx, [eax+usb_hub.ChangeConfigBuffer]
mov dword [edx], 20h + \ ; class-specific request to hub itself
(USB_CLEAR_FEATURE shl 8)
mov [edx+2], cl ; feature selector
and dword [edx+4], 0
stdcall usb_control_async, [eax+usb_hub.ConfigPipe], edx, 0, 0, usb_hub_change_cleared, eax, 0
.nothing:
ret
.final:
; 5. All changes cleared and accumulated, now process them.
; Note: that needs work.
DEBUGF 1,'K : hub status %x\n',[eax+usb_hub.AccStatusChange]:2
test [eax+usb_hub.AccStatusChange], 1
jz .no_local_power
test [eax+usb_hub.StatusData], 1
jz .local_power_lost
dbgstr 'Hub local power is now good'
jmp .no_local_power
.local_power_lost:
dbgstr 'Hub local power is now lost'
.no_local_power:
test [eax+usb_hub.AccStatusChange], 2
jz .no_overcurrent
test [eax+usb_hub.StatusData], 2
jz .no_overcurrent
dbgstr 'Hub global overcurrent'
.no_overcurrent:
; 6. Process possible changes for other ports.
jmp usb_hub_changed.restart
.failed:
dbgstr 'Querying hub status failed'
jmp .nothing
endp
 
; This procedure is called when the request to clear hub change is completed,
; either successfully or unsuccessfully.
proc usb_hub_change_cleared stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; 1. Check whether our request has failed.
; If so, say something to the debug board and stop processing notifications.
cmp [status], 0
jnz .failed
; 2. If there is a change which was observed, but not yet cleared,
; go to the code which clears it.
mov eax, [calldata]
cmp [eax+usb_hub.StatusChange], 0
jnz usb_hub_status.next_change
; 3. Otherwise, go to the code which queries the status.
jmp usb_hub_changed.next_hub_change
.failed:
dbgstr 'Clearing hub change failed'
ret
endp
 
; This procedure is called when the request of port status is completed,
; either successfully or unsuccessfully.
proc usb_hub_port_status stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; 1. Check whether our request has failed.
; If so, say something to the debug board and stop processing notifications.
cmp [status], 0
jnz .failed
; 2. Accumulate observed changes.
mov eax, [calldata]
; movzx ecx, [eax+usb_hub.ChangeConfigBuffer+4]
; dec ecx
; DEBUGF 1,'K : [%d] hub %x port %d status %x change %x\n',[timer_ticks],eax,ecx,[eax+usb_hub.StatusData]:4,[eax+usb_hub.StatusChange]:4
mov dl, byte [eax+usb_hub.StatusChange]
or [eax+usb_hub.AccStatusChange], dl
.next_change:
; 3. Find the first change. If found, advance to 4. Otherwise, go to 5.
; Ignore change in reset status; it is cleared by synchronous code
; (usb_hub_process_deferred), so avoid unnecessary interference.
; mov cl, C_PORT_RESET
btr dword [eax+usb_hub.StatusChange], PORT_RESET
; jc .clear_port_change
mov cl, C_PORT_OVER_CURRENT
btr dword [eax+usb_hub.StatusChange], PORT_OVER_CURRENT
jc .clear_port_change
mov cl, C_PORT_SUSPEND
btr dword [eax+usb_hub.StatusChange], PORT_SUSPEND
jc .clear_port_change
mov cl, C_PORT_ENABLE
btr dword [eax+usb_hub.StatusChange], PORT_ENABLE
jc .clear_port_change
mov cl, C_PORT_CONNECTION
btr dword [eax+usb_hub.StatusChange], PORT_CONNECTION
jnc .final
.clear_port_change:
; 4. Clear the change and continue in usb_hub_port_changed callback.
call usb_hub_clear_port_change
jmp .nothing
.final:
; All changes cleared and accumulated, now process them.
movzx ecx, byte [eax+usb_hub.ChangeConfigBuffer+4]
dec ecx
DEBUGF 1,'K : final: hub %x port %d status %x change %x\n',eax,ecx,[eax+usb_hub.StatusData]:4,[eax+usb_hub.AccStatusChange]:2
; 5. Process connect/disconnect events.
; 5a. Test whether there is such event.
test byte [eax+usb_hub.AccStatusChange], 1 shl PORT_CONNECTION
jz .nodisconnect
; 5b. If there was a connected device, notify the main code about disconnect.
push ebx
mov edx, [eax+usb_hub.ConnectedDevicesPtr]
xor ebx, ebx
xchg ebx, [edx+ecx*4]
test ebx, ebx
jz @f
push eax ecx
call usb_device_disconnected
pop ecx eax
@@:
pop ebx
; 5c. If the disconnect event corresponds to the port which is currently
; resetting, then another request from synchronous code could be in the fly,
; so aborting reset immediately would lead to problems with those requests.
; Thus, just set the corresponding status and let the synchronous code process.
test byte [eax+usb_hub.Actions], (HUB_RESET_SIGNAL or HUB_RESET_RECOVERY)
jz @f
mov edx, [eax+usb_hub.Controller]
cmp [edx+usb_controller.ResettingPort], cl
jnz @f
mov [edx+usb_controller.ResettingStatus], -1
@@:
; 5d. If the current status is 'connected', store the current time as connect
; time and set the corresponding bit for usb_hub_process_deferred.
; Otherwise, set connect time to -1.
; If current time is -1, pretend that the event occured one tick later and
; store zero.
mov edx, [eax+usb_hub.ConnectedTimePtr]
test byte [eax+usb_hub.StatusData], 1 shl PORT_CONNECTION
jz .disconnected
or [eax+usb_hub.Actions], HUB_WAIT_CONNECT
push eax
call usb_hub_store_connected_time
pop eax
jmp @f
.disconnected:
or dword [edx+ecx*4], -1
@@:
.nodisconnect:
; 6. Process port disabling.
test [eax+usb_hub.AccStatusChange], 1 shl PORT_ENABLE
jz .nodisable
test byte [eax+usb_hub.StatusData], 1 shl PORT_ENABLE
jnz .nodisable
; Note: that needs work.
dbgstr 'Port disabled'
.nodisable:
; 7. Process port overcurrent.
test [eax+usb_hub.AccStatusChange], 1 shl PORT_OVER_CURRENT
jz .noovercurrent
test byte [eax+usb_hub.StatusData], 1 shl PORT_OVER_CURRENT
jz .noovercurrent
; Note: that needs work.
dbgstr 'Port over-current'
.noovercurrent:
; 8. Process possible changes for other ports.
jmp usb_hub_changed.restart
.failed:
dbgstr 'Querying port status failed'
.nothing:
ret
endp
 
; Helper procedure to store current time in ConnectedTime,
; advancing -1 to zero if needed.
proc usb_hub_store_connected_time
mov eax, [timer_ticks]
; transform -1 to 0, leave other values as is
cmp eax, -1
sbb eax, -1
mov [edx+ecx*4], eax
ret
endp
 
; Helper procedure for several parts of hub code.
; Sends a request to clear the given feature of the port.
; eax -> usb_hub, cl = feature;
; as is should be called from async code, sync code should set
; edx to ConfigBuffer and call usb_hub_clear_port_change.buffer;
; port number (1-based) should be filled in [edx+4] by previous requests.
proc usb_hub_clear_port_change
lea edx, [eax+usb_hub.ChangeConfigBuffer]
.buffer:
; push edx
; movzx edx, byte [edx+4]
; dec edx
; DEBUGF 1,'K : [%d] hub %x port %d clear feature %d\n',[timer_ticks],eax,edx,cl
; pop edx
mov dword [edx], 23h + \ ; class-specific request to hub port
(USB_CLEAR_FEATURE shl 8)
mov byte [edx+2], cl
and dword [edx+4], 0xFF
stdcall usb_control_async, [eax+usb_hub.ConfigPipe], edx, edx, 0, usb_hub_port_changed, eax, 0
ret
endp
 
; This procedure is called when the request to clear port change is completed,
; either successfully or unsuccessfully.
proc usb_hub_port_changed stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; 1. Check whether our request has failed.
; If so, say something to the debug board and stop processing notifications.
cmp [status], 0
jnz .failed
; 2. If the request was originated by synchronous code, no further processing
; is required.
mov eax, [calldata]
lea edx, [eax+usb_hub.ConfigBuffer]
cmp [buffer], edx
jz .nothing
; 3. If there is a change which was observed, but not yet cleared,
; go to the code which clears it.
cmp [eax+usb_hub.StatusChange], 0
jnz usb_hub_port_status.next_change
; 4. Otherwise, go to the code which queries the status.
jmp usb_hub_changed.next_port_change
.failed:
dbgstr 'Clearing port change failed'
.nothing:
ret
endp
 
; This procedure is called in the USB thread from usb_thread_proc,
; contains synchronous code which should be activated at certain time
; (e.g. reset a recently connected device after debounce interval 100ms).
; Returns the number of ticks when it should be called next time.
proc usb_hub_process_deferred
; 1. Top-of-stack will contain return value; initialize to infinite timeout.
push -1
; 2. If wait for stable power is active, then
; either reschedule wakeup (if time is not over)
; or start processing notifications.
test byte [esi+usb_hub.Actions], HUB_WAIT_POWERED
jz .no_powered
movzx eax, [esi+usb_hub.PowerOnInterval]
; three following instructions are equivalent to edx = ceil(eax / 5) + 1
; 1 extra tick is added to make sure that the interval is at least as needed
; (it is possible that PoweredOnTime was set just before timer interrupt, and
; this test goes on just after timer interrupt)
add eax, 9
; two following instructions are equivalent to edx = floor(eax / 5)
; for any 0 <= eax < 40000000h
mov ecx, 33333334h
mul ecx
mov eax, [timer_ticks]
sub eax, [esi+usb_hub.PoweredOnTime]
sub eax, edx
jge .powered_on
neg eax
pop ecx
push eax
jmp .no_powered
.powered_on:
and [esi+usb_hub.Actions], not HUB_WAIT_POWERED
mov eax, esi
call usb_hub_wait_change
.no_powered:
; 3. If reset is pending, check whether we can start it and start it, if so.
test byte [esi+usb_hub.Actions], HUB_RESET_WAITING
jz .no_wait_reset
mov eax, [esi+usb_hub.Controller]
cmp [eax+usb_controller.ResettingPort], -1
jnz .no_wait_reset
call usb_hub_initiate_reset
.no_wait_reset:
; 4. If reset signalling is active, wait for end of reset signalling
; and schedule wakeup in 1 tick.
test byte [esi+usb_hub.Actions], HUB_RESET_SIGNAL
jz .no_resetting_port
; It has no sense to query status several times per tick.
mov eax, [timer_ticks]
cmp eax, [esi+usb_hub.ResetTime]
jz @f
mov [esi+usb_hub.ResetTime], eax
movzx ecx, byte [esi+usb_hub.ConfigBuffer+4]
mov eax, usb_hub_resetting_port_status
call usb_hub_query_port_status
@@:
pop eax
push 1
.no_resetting_port:
; 5. If reset recovery is active and time is not over, reschedule wakeup.
test byte [esi+usb_hub.Actions], HUB_RESET_RECOVERY
jz .no_reset_recovery
mov eax, [timer_ticks]
sub eax, [esi+usb_hub.ResetTime]
sub eax, USB_RESET_RECOVERY_TIME
jge .reset_done
neg eax
cmp [esp], eax
jb @f
mov [esp], eax
@@:
jmp .no_reset_recovery
.reset_done:
; 6. If reset recovery is active and time is over, clear 'reset recovery' flag,
; notify other code about a new device and let it do further steps.
; If that fails, stop reset process for this port and disable that port.
and [esi+usb_hub.Actions], not HUB_RESET_RECOVERY
; Bits 9-10 of port status encode port speed.
; If PORT_LOW_SPEED is set, the device is low-speed. Otherwise,
; PORT_HIGH_SPEED bit distinguishes full-speed and high-speed devices.
; This corresponds to values of USB_SPEED_FS=0, USB_SPEED_LS=1, USB_SPEED_HS=2.
mov eax, dword [esi+usb_hub.ResetStatusData]
shr eax, PORT_LOW_SPEED
and eax, 3
test al, 1
jz @f
mov al, 1
@@:
; movzx ecx, [esi+usb_hub.ConfigBuffer+4]
; dec ecx
; DEBUGF 1,'K : [%d] hub %x port %d speed %d\n',[timer_ticks],esi,ecx,eax
push esi
mov esi, [esi+usb_hub.Controller]
cmp [esi+usb_controller.ResettingStatus], -1
jz .disconnected_while_reset
mov edx, [esi+usb_controller.HardwareFunc]
call [edx+usb_hardware_func.NewDevice]
pop esi
test eax, eax
jnz .no_reset_recovery
mov eax, esi
call usb_hub_disable_resetting_port
jmp .no_reset_recovery
.disconnected_while_reset:
pop esi
mov eax, esi
call usb_hub_reset_aborted
.no_reset_recovery:
; 7. Handle recent connection events.
; Note: that should be done after step 6, because step 6 can clear
; HUB_RESET_IN_PROGRESS flag.
; 7a. Test whether there is such an event pending. If no, skip this step.
test byte [esi+usb_hub.Actions], HUB_WAIT_CONNECT
jz .no_wait_connect
; 7b. If we have started reset process for another port in the same hub,
; skip this step: the buffer for config requests can be used for that port.
test byte [esi+usb_hub.Actions], HUB_RESET_IN_PROGRESS
jnz .no_wait_connect
; 7c. Clear flag 'there are connection events which should be processed'.
; If there are another connection events, this flag will be set again.
and [esi+usb_hub.Actions], not HUB_WAIT_CONNECT
; 7d. Prepare for loop over all ports.
xor ecx, ecx
.test_wait_connect:
; 7e. For every port test for recent connection event.
; If none, continue the loop for the next port.
mov edx, [esi+usb_hub.ConnectedTimePtr]
mov eax, [edx+ecx*4]
cmp eax, -1
jz .next_wait_connect
or [esi+usb_hub.Actions], HUB_WAIT_CONNECT
; 7f. Test whether initial delay is over.
sub eax, [timer_ticks]
neg eax
sub eax, USB_CONNECT_DELAY
jge .connect_delay_over
; 7g. The initial delay is not over;
; set the corresponding flag again, reschedule wakeup and continue the loop.
neg eax
cmp [esp], eax
jb @f
mov [esp], eax
@@:
jmp .next_wait_connect
.connect_delay_over:
; The initial delay is over.
; It is possible that there was disconnect event during that delay, probably
; with connect event after that. If so, we should restart the waiting. However,
; on the hardware level connect/disconnect events from hubs are implemented
; using polling with interval selected by the hub, so it is possible that
; we have not yet observed that disconnect event.
; Thus, we query port status+change data before all further processing.
; 7h. Send the request for status+change data.
push ecx
; Hub requests expect 1-based port number, not zero-based we operate with.
inc ecx
mov eax, usb_hub_connect_port_status
call usb_hub_query_port_status
pop ecx
; 3i. If request has been submitted successfully, set the flag
; 'reset in progress, config buffer is owned by reset process' and break
; from the loop.
test eax, eax
jz .next_wait_connect
or [esi+usb_hub.Actions], HUB_RESET_IN_PROGRESS
jmp .no_wait_connect
.next_wait_connect:
; 7j. Continue the loop for next port.
inc ecx
cmp ecx, [esi+usb_hub.NumPorts]
jb .test_wait_connect
.no_wait_connect:
; 8. Pop return value from top-of-stack and return.
pop eax
ret
endp
 
; Helper procedure for other code. Called when reset process is aborted.
proc usb_hub_reset_aborted
; Clear 'reset in progress' flag and test for other devices which could be
; waiting for reset.
and [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
push esi
mov esi, [eax+usb_hub.Controller]
call usb_test_pending_port
pop esi
ret
endp
 
; Helper procedure for usb_hub_process_deferred.
; Sends a request to query port status.
; esi -> usb_hub, eax = callback, ecx = 1-based port.
proc usb_hub_query_port_status
; dec ecx
; DEBUGF 1,'K : [%d] [main] hub %x port %d query status\n',[timer_ticks],esi,ecx
; inc ecx
add ecx, 4 shl 16 ; data length = 4
lea edx, [esi+usb_hub.ConfigBuffer]
mov dword [edx], 0A3h + \ ; class-specific request from hub port
(USB_GET_STATUS shl 8)
mov dword [edx+4], ecx
lea ecx, [esi+usb_hub.ResetStatusData]
stdcall usb_control_async, [esi+usb_hub.ConfigPipe], edx, ecx, 4, eax, esi, 0
ret
endp
 
; This procedure is called when the request to query port status
; initiated by usb_hub_process_deferred for testing connection is completed,
; either successfully or unsuccessfully.
proc usb_hub_connect_port_status stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
push esi ; save used register to be stdcall
mov eax, [calldata]
mov esi, [pipe]
; movzx ecx, [eax+usb_hub.ConfigBuffer+4]
; dec ecx
; DEBUGF 1,'K : [%d] [connect test] hub %x port %d status %x change %x\n',[timer_ticks],eax,ecx,[eax+usb_hub.ResetStatusData]:4,[eax+usb_hub.ResetStatusChange]:4
; 1. In any case, clear 'reset in progress' flag.
; If everything is ok, it would be set again.
and [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
; 2. If the request has failed, stop reset process.
cmp [status], 0
jnz .nothing
mov edx, [eax+usb_hub.ConnectedTimePtr]
movzx ecx, byte [eax+usb_hub.ConfigBuffer+4]
dec ecx
; 3. Test whether there was a disconnect event.
test byte [eax+usb_hub.ResetStatusChange], 1 shl PORT_CONNECTION
jz .reset
; 4. There was a disconnect event.
; There is another handler of connect/disconnect events, usb_hub_port_status.
; However, we do not know whether it has already processed this event
; or it will process it sometime later.
; If ConnectedTime is -1, then another handler has already run,
; there was no connection event, so just leave the value as -1.
; Otherwise, there are two possibilities: either another handler has not yet
; run (which is quite likely), or there was a connection event and the other
; handler has run exactly while our request was processed (otherwise our
; request would not been submitted; this is quite unlikely due to timing
; requirements, but not impossible). In this case, set ConnectedTime to the
; current time: in the likely case it prevents usb_hub_process_deferred from immediate
; issuing of another requests (which would be just waste of time);
; in the unlikely case it is still correct (although slightly increases
; the debounce interval).
cmp dword [edx+ecx*4], -1
jz .nothing
call usb_hub_store_connected_time
jmp .nothing
.reset:
; 5. The device remained connected for the entire debounce interval;
; we can proceed with initialization.
; Clear connected time for this port and notify usb_hub_process_deferred that
; the new port is waiting for reset.
or dword [edx+ecx*4], -1
or [eax+usb_hub.Actions], HUB_RESET_IN_PROGRESS + HUB_RESET_WAITING
.nothing:
pop esi ; restore used register to be stdcall
ret
endp
 
; This procedure is called when the request to query port status
; initiated by usb_hub_process_deferred for testing reset status is completed,
; either successfully or unsuccessfully.
proc usb_hub_resetting_port_status stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; 1. If the request has failed, do nothing.
cmp [status], 0
jnz .nothing
; 2. If reset signalling is still active, do nothing.
mov eax, [calldata]
; movzx ecx, [eax+usb_hub.ConfigBuffer+4]
; dec ecx
; DEBUGF 1,'K : hub %x port %d ResetStatusData = %x change = %x\n',eax,ecx,[eax+usb_hub.ResetStatusData]:4,[eax+usb_hub.ResetStatusChange]:4
test byte [eax+usb_hub.ResetStatusData], 1 shl PORT_RESET
jnz .nothing
; 3. Store the current time to start reset recovery interval
; and clear 'reset signalling active' flag.
mov edx, [timer_ticks]
mov [eax+usb_hub.ResetTime], edx
and [eax+usb_hub.Actions], not HUB_RESET_SIGNAL
; 4. If the device has not been disconnected, set 'reset recovery active' bit.
; Otherwise, terminate reset process.
test byte [eax+usb_hub.ResetStatusChange], 1 shl PORT_CONNECTION
jnz .disconnected
or [eax+usb_hub.Actions], HUB_RESET_RECOVERY
.common:
; In any case, clear change of resetting status.
lea edx, [eax+usb_hub.ConfigBuffer]
mov cl, C_PORT_RESET
call usb_hub_clear_port_change.buffer
.nothing:
ret
.disconnected:
call usb_hub_reset_aborted
jmp .common
endp
 
; Helper procedure for usb_hub_process_deferred. Initiates reset signalling
; on the current port (given by 1-based value [ConfigBuffer+4]).
; esi -> usb_hub, eax -> usb_controller
proc usb_hub_initiate_reset
; 1. Store hub+port data in the controller structure.
movzx ecx, [esi+usb_hub.ConfigBuffer+4]
dec ecx
mov [eax+usb_controller.ResettingPort], cl
mov [eax+usb_controller.ResettingHub], esi
; 2. Store the current time and set 'reset signalling active' flag.
mov eax, [timer_ticks]
mov [esi+usb_hub.ResetTime], eax
and [esi+usb_hub.Actions], not HUB_RESET_WAITING
or [esi+usb_hub.Actions], HUB_RESET_SIGNAL
; 3. Send request to the hub to initiate request signalling.
lea edx, [esi+usb_hub.ConfigBuffer]
; DEBUGF 1,'K : [%d] hub %x port %d initiate reset\n',[timer_ticks],esi,ecx
mov dword [edx], 23h + \
(USB_SET_FEATURE shl 8) + \
(PORT_RESET shl 16)
and dword [edx+4], 0xFF
stdcall usb_control_async, [esi+usb_hub.ConfigPipe], edx, 0, 0, usb_hub_reset_started, esi, 0
test eax, eax
jnz @f
mov eax, esi
call usb_hub_reset_aborted
@@:
ret
endp
 
; This procedure is called when the request to start reset signalling initiated
; by usb_hub_initiate_reset is completed, either successfully or unsuccessfully.
proc usb_hub_reset_started stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; If the request is successful, do nothing.
; Otherwise, clear 'reset signalling' flag and abort reset process.
mov eax, [calldata]
; movzx ecx, [eax+usb_hub.ConfigBuffer+4]
; dec ecx
; DEBUGF 1,'K : [%d] hub %x port %d reset started\n',[timer_ticks],eax,ecx
cmp [status], 0
jz .nothing
and [eax+usb_hub.Actions], not HUB_RESET_SIGNAL
dbgstr 'Failed to reset hub port'
call usb_hub_reset_aborted
.nothing:
ret
endp
 
; This procedure is called by the protocol layer if something has failed during
; initial stages of the configuration process, so the device should be disabled
; at hub level.
proc usb_hub_disable_resetting_port
and [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
; movzx ecx, [eax+usb_hub.ConfigBuffer+4]
; dec ecx
; DEBUGF 1,'K : [%d] hub %x port %d disable\n',[timer_ticks],eax,ecx
lea edx, [eax+usb_hub.ConfigBuffer]
mov cl, PORT_ENABLE
jmp usb_hub_clear_port_change.buffer
endp
 
; This procedure is called when the hub is disconnected.
proc usb_hub_disconnect
virtual at esp
dd ? ; return address
.hubdata dd ?
end virtual
; 1. If the hub is disconnected during initial configuration,
; 1 is stored as hub data and there is nothing to do.
mov eax, [.hubdata]
cmp eax, 1
jz .nothing
; 2. Remove the hub from the overall list.
mov ecx, [eax+usb_hub.Next]
mov edx, [eax+usb_hub.Prev]
mov [ecx+usb_hub.Prev], edx
mov [edx+usb_hub.Next], ecx
; 3. If some child is in reset process, abort reset.
push esi
mov esi, [eax+usb_hub.Controller]
cmp [esi+usb_controller.ResettingHub], eax
jnz @f
cmp [esi+usb_controller.ResettingPort], -1
jz @f
push eax
call usb_test_pending_port
pop eax
@@:
pop esi
; 4. Loop over all children and notify other code that they were disconnected.
push ebx
xor ecx, ecx
.disconnect_children:
mov ebx, [eax+usb_hub.ConnectedDevicesPtr]
mov ebx, [ebx+ecx*4]
test ebx, ebx
jz @f
push eax ecx
call usb_device_disconnected
pop ecx eax
@@:
inc ecx
cmp ecx, [eax+usb_hub.NumPorts]
jb .disconnect_children
; 4. Free memory allocated for the hub data.
call free
pop ebx
.nothing:
retn 4
endp
 
; Helper function for USB2 scheduler.
; in: eax -> usb_hub
; out: ecx = TT think time for the hub in FS-bytes
proc usb_get_tt_think_time
movzx ecx, [eax+usb_hub.HubCharacteristics]
shr ecx, 5
and ecx, 3
inc ecx
ret
endp
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/usb/init.inc
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"
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/usb/pipe.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/usb/protocol.inc
0,0 → 1,1019
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
; Implementation of the USB protocol for device enumeration.
; Manage a USB device when it becomes ready for USB commands:
; configure, enumerate, load the corresponding driver(s),
; pass device information to the driver.
 
; =============================================================================
; ================================= Constants =================================
; =============================================================================
; USB standard request codes
USB_GET_STATUS = 0
USB_CLEAR_FEATURE = 1
USB_SET_FEATURE = 3
USB_SET_ADDRESS = 5
USB_GET_DESCRIPTOR = 6
USB_SET_DESCRIPTOR = 7
USB_GET_CONFIGURATION = 8
USB_SET_CONFIGURATION = 9
USB_GET_INTERFACE = 10
USB_SET_INTERFACE = 11
USB_SYNCH_FRAME = 12
 
; USB standard descriptor types
USB_DEVICE_DESCR = 1
USB_CONFIG_DESCR = 2
USB_STRING_DESCR = 3
USB_INTERFACE_DESCR = 4
USB_ENDPOINT_DESCR = 5
USB_DEVICE_QUALIFIER_DESCR = 6
USB_OTHER_SPEED_CONFIG_DESCR = 7
USB_INTERFACE_POWER_DESCR = 8
 
; Compile-time setting. If set, the code will dump all descriptors as they are
; read to the debug board.
USB_DUMP_DESCRIPTORS = 1
 
; According to the USB specification (9.2.6.3),
; any device must response to SET_ADDRESS in 50 ms, or 5 timer ticks.
; Of course, our world is far from ideal.
; I have seen devices that just NAK everything when being reset from working
; state, but start to work after second reset.
; Our strategy is as follows: give 2 seconds for the first attempt,
; this should be enough for normal devices and not too long to detect buggy ones.
; If the device continues NAKing, reset it and retry several times,
; doubling the interval: 2s -> 4s -> 8s -> 16s. Give up after that.
; Numbers are quite arbitrary.
TIMEOUT_SET_ADDRESS_INITIAL = 200
TIMEOUT_SET_ADDRESS_LAST = 1600
 
; =============================================================================
; ================================ Structures =================================
; =============================================================================
; USB descriptors. See USB specification for detailed explanations.
; First two bytes of every descriptor have the same meaning.
struct usb_descr
bLength db ?
; Size of this descriptor in bytes
bDescriptorType db ?
; One of USB_*_DESCR constants.
ends
 
; USB device descriptor
struct usb_device_descr usb_descr
bcdUSB dw ?
; USB Specification Release number in BCD, e.g. 110h = USB 1.1
bDeviceClass db ?
; USB Device Class Code
bDeviceSubClass db ?
; USB Device Subclass Code
bDeviceProtocol db ?
; USB Device Protocol Code
bMaxPacketSize0 db ?
; Maximum packet size for zero endpoint
idVendor dw ?
; Vendor ID
idProduct dw ?
; Product ID
bcdDevice dw ?
; Device release number in BCD
iManufacturer db ?
; Index of string descriptor describing manufacturer
iProduct db ?
; Index of string descriptor describing product
iSerialNumber db ?
; Index of string descriptor describing serial number
bNumConfigurations db ?
; Number of possible configurations
ends
 
; USB configuration descriptor
struct usb_config_descr usb_descr
wTotalLength dw ?
; Total length of data returned for this configuration
bNumInterfaces db ?
; Number of interfaces in this configuration
bConfigurationValue db ?
; Value for SET_CONFIGURATION control request
iConfiguration db ?
; Index of string descriptor describing this configuration
bmAttributes db ?
; Bit 6 is SelfPowered, bit 5 is RemoteWakeupSupported,
; bit 7 must be 1, other bits must be 0
bMaxPower db ?
; Maximum power consumption from the bus in 2mA units
ends
 
; USB interface descriptor
struct usb_interface_descr usb_descr
; The following two fields work in pair. Sometimes one interface can work
; in different modes; e.g. videostream from web-cameras requires different
; bandwidth depending on resolution/quality/compression settings.
; Each mode of each interface has its own descriptor with its own endpoints
; following; all descriptors for one interface have the same bInterfaceNumber,
; and different bAlternateSetting.
; By default, any interface operates in mode with bAlternateSetting = 0.
; Often this is the only mode. If there are another modes, the active mode
; is selected by SET_INTERFACE(bAlternateSetting) control request.
bInterfaceNumber db ?
bAlternateSetting db ?
bNumEndpoints db ?
; Number of endpoints used by this interface, excluding zero endpoint
bInterfaceClass db ?
; USB Interface Class Code
bInterfaceSubClass db ?
; USB Interface Subclass Code
bInterfaceProtocol db ?
; USB Interface Protocol Code
iInterface db ?
; Index of string descriptor describing this interface
ends
 
; USB endpoint descriptor
struct usb_endpoint_descr usb_descr
bEndpointAddress db ?
; Lower 4 bits form endpoint number,
; upper bit is 0 for OUT endpoints and 1 for IN endpoints,
; other bits must be zero
bmAttributes db ?
; Lower 2 bits form transfer type, one of *_PIPE,
; other bits must be zero for non-isochronous endpoints;
; refer to the USB specification for meaning in isochronous case
wMaxPacketSize dw ?
; Lower 11 bits form maximum packet size,
; next two bits specify the number of additional transactions per microframe
; for high-speed periodic endpoints, other bits must be zero.
bInterval db ?
; Interval for polling endpoint for data transfers.
; Isochronous and high-speed interrupt endpoints: poll every 2^(bInterval-1)
; (micro)frames
; Full/low-speed interrupt endpoints: poll every bInterval frames
; High-speed bulk/control OUT endpoints: maximum NAK rate
ends
 
; =============================================================================
; =================================== Code ====================================
; =============================================================================
 
; When a new device is ready to be configured, a controller-specific code
; calls usb_new_device.
; The sequence of further actions:
; * open pipe for the zero endpoint (usb_new_device);
; maximum packet size is not known yet, but it must be at least 8 bytes,
; so it is safe to send packets with <= 8 bytes
; * issue SET_ADDRESS control request (usb_new_device)
; * set the new device address in the pipe (usb_set_address_callback)
; * notify a controller-specific code that initialization of other ports
; can be started (usb_set_address_callback)
; * issue GET_DESCRIPTOR control request for first 8 bytes of device descriptor
; (usb_after_set_address)
; * first 8 bytes of device descriptor contain the true packet size for zero
; endpoint, so set the true packet size (usb_get_descr8_callback)
; * first 8 bytes of a descriptor contain the full size of this descriptor,
; issue GET_DESCRIPTOR control request for the full device descriptor
; (usb_after_set_endpoint_size)
; * issue GET_DESCRIPTOR control request for first 8 bytes of configuration
; descriptor (usb_get_descr_callback)
; * issue GET_DESCRIPTOR control request for full configuration descriptor
; (usb_know_length_callback)
; * issue SET_CONFIGURATION control request (usb_set_config_callback)
; * parse configuration descriptor, load the corresponding driver(s),
; pass the configuration descriptor to the driver and let the driver do
; the further work (usb_got_config_callback)
 
; This function is called from controller-specific part
; when a new device is ready to be configured.
; in: ecx -> pseudo-pipe, part of usb_pipe
; in: esi -> usb_controller
; in: [esi+usb_controller.ResettingHub] is the pointer to usb_hub for device,
; NULL if the device is connected to the root hub
; in: [esi+usb_controller.ResettingPort] is the port for the device, zero-based
; in: [esi+usb_controller.ResettingSpeed] is the speed of the device, one of
; USB_SPEED_xx.
; out: eax = 0 <=> failed, the caller should disable the port.
proc usb_new_device
push ebx edi ; save used registers to be stdcall
; 1. Check whether we're here because we were trying to reset
; already-registered device in hope to fix something serious.
; If so, skip allocation and go to 6.
movzx eax, [esi+usb_controller.ResettingPort]
mov edx, [esi+usb_controller.ResettingHub]
test edx, edx
jz .test_roothub
mov edx, [edx+usb_hub.ConnectedDevicesPtr]
mov ebx, [edx+eax*4]
jmp @f
.test_roothub:
mov ebx, [esi+usb_controller.DevicesByPort+eax*4]
@@:
test ebx, ebx
jnz .try_set_address
; 2. Allocate resources. Any device uses the following resources:
; - device address in the bus
; - memory for device data
; - pipe for zero endpoint
; If some allocation fails, we must undo our actions. Closing the pipe
; is a hard task, so we avoid it and open the pipe as the last resource.
; The order for other two allocations is quite arbitrary.
; 2a. Allocate a bus address.
push ecx
call usb_set_address_request
pop ecx
; 2b. If failed, just return zero.
test eax, eax
jz .nothing
; 2c. Allocate memory for device data.
; For now, we need sizeof.usb_device_data and extra 8 bytes for GET_DESCRIPTOR
; input and output, see usb_after_set_address. Later we will reallocate it
; to actual size needed for descriptors.
movi eax, sizeof.usb_device_data + 8
push ecx
call malloc
pop ecx
; 2d. If failed, free the bus address and return zero.
test eax, eax
jz .nomemory
; 2e. Open pipe for endpoint zero.
; For now, we do not know the actual maximum packet size;
; for full-speed devices it can be any of 8, 16, 32, 64 bytes,
; low-speed devices must have 8 bytes, high-speed devices must have 64 bytes.
; Thus, we must use some fake "maximum packet size" until the actual size
; will be known. However, the maximum packet size must be at least 8, and
; initial stages of the configuration process involves only packets of <= 8
; bytes, they will be transferred correctly as long as
; the fake "maximum packet size" is also at least 8.
; Thus, any number >= 8 is suitable for actual hardware.
; However, software emulation of EHCI in VirtualBox assumes that high-speed
; control transfers are those originating from pipes with max packet size = 64,
; even on early stages of the configuration process. This is incorrect,
; but we have no specific preferences, so let VirtualBox be happy and use 64
; as the fake "maximum packet size".
push eax
; We will need many zeroes.
; "push edi" is one byte, "push 0" is two bytes; save space, use edi.
xor edi, edi
stdcall usb_open_pipe, ecx, edi, 64, edi, edi
; Put pointer to pipe into ebx. "xchg eax,reg" is one byte, mov is two bytes.
xchg eax, ebx
pop eax
; 2f. If failed, free the memory, the bus address and return zero.
test ebx, ebx
jz .freememory
; 3. Store pointer to device data in the pipe structure.
mov [ebx+usb_pipe.DeviceData], eax
; 4. Init device data, using usb_controller.Resetting* variables.
mov [eax+usb_device_data.Timer], edi
mov dword [eax+usb_device_data.DeviceDescriptor], TIMEOUT_SET_ADDRESS_INITIAL
mov [eax+usb_device_data.TTHub], edi
mov [eax+usb_device_data.TTPort], 0
mov [eax+usb_device_data.NumInterfaces], edi
mov [eax+usb_device_data.DeviceDescrSize], 0
mov dl, [esi+usb_controller.ResettingSpeed]
mov [eax+usb_device_data.Speed], dl
mov [eax+usb_device_data.NumPipes], 1
push ebx
cmp dl, USB_SPEED_HS
jz .nott
mov ebx, [esi+usb_controller.ResettingHub]
test ebx, ebx
jz .nott
mov cl, [esi+usb_controller.ResettingPort]
mov edx, [ebx+usb_hub.ConfigPipe]
mov edx, [edx+usb_pipe.DeviceData]
cmp [edx+usb_device_data.TTHub], 0
jz @f
mov cl, [edx+usb_device_data.TTPort]
mov ebx, [edx+usb_device_data.TTHub]
jmp .has_tt
@@:
cmp [edx+usb_device_data.Speed], USB_SPEED_HS
jnz .nott
.has_tt:
mov [eax+usb_device_data.TTHub], ebx
mov [eax+usb_device_data.TTPort], cl
.nott:
pop ebx
mov [eax+usb_device_data.ConfigDataSize], edi
mov [eax+usb_device_data.Interfaces], edi
movzx ecx, [esi+usb_controller.ResettingPort]
mov [eax+usb_device_data.Port], cl
mov edx, [esi+usb_controller.ResettingHub]
mov [eax+usb_device_data.Hub], edx
; 5. Store pointer to the config pipe in the hub data.
; Config pipe serves as device identifier.
; Root hubs use the array inside usb_controller structure,
; non-root hubs use the array immediately after usb_hub structure.
test edx, edx
jz .roothub
mov edx, [edx+usb_hub.ConnectedDevicesPtr]
mov [edx+ecx*4], ebx
jmp @f
.roothub:
mov [esi+usb_controller.DevicesByPort+ecx*4], ebx
@@:
call usb_reinit_pipe_list
; 6. Issue SET_ADDRESS control request, using buffer filled in step 2a.
; 6a. Configure timer to force reset after timeout.
; Note: we can't use self-destructing timer, because we need to be able to cancel it,
; and for self-destructing timer we could have race condition in cancelling/destructing.
; DEBUGF 1,'K : pipe %x\n',ebx
.try_set_address:
xor edi, edi
mov edx, [ebx+usb_pipe.DeviceData]
stdcall timer_hs, [edx+usb_device_data.DeviceDescriptor], 7FFFFFFFh, usb_abort_pipe, ebx
test eax, eax
jz .nothing
mov edx, [ebx+usb_pipe.DeviceData]
mov [edx+usb_device_data.Timer], eax
; 6b. If it succeeded, setup timer to configure wait timeout.
lea eax, [esi+usb_controller.SetAddressBuffer]
stdcall usb_control_async, ebx, eax, edi, edi, usb_set_address_callback, edi, edi
; Use the return value from usb_control_async as our return value;
; if it is zero, then something has failed.
.nothing:
; 7. Return.
pop edi ebx ; restore used registers to be stdcall
ret
; Handlers of failures in steps 2b, 2d, 2f.
.freememory:
call free
jmp .freeaddr
.nomemory:
dbgstr 'No memory for device data'
.freeaddr:
mov ecx, dword [esi+usb_controller.SetAddressBuffer+2]
bts [esi+usb_controller.ExistingAddresses], ecx
xor eax, eax
jmp .nothing
endp
 
; Helper procedure for usb_new_device.
; Allocates a new USB address and fills usb_controller.SetAddressBuffer
; with data for SET_ADDRESS(allocated_address) request.
; out: eax = 0 <=> failed
; Destroys edi.
proc usb_set_address_request
; There are 128 bits, one for each possible address.
; Note: only the USB thread works with usb_controller.ExistingAddresses,
; so there is no need for synchronization.
; We must find a bit set to 1 and clear it.
; 1. Find the first dword which has a nonzero bit = which is nonzero.
mov ecx, 128/32
lea edi, [esi+usb_controller.ExistingAddresses]
xor eax, eax
repz scasd
; 2. If all dwords are zero, return an error.
jz .error
; 3. The dword at [edi-4] is nonzero. Find the lowest nonzero bit.
bsf eax, [edi-4]
; Now eax = bit number inside the dword at [edi-4].
; 4. Clear the bit.
btr [edi-4], eax
; 5. Generate the address by edi = memory address and eax = bit inside dword.
; Address = eax + 8 * (edi-4 - (esi+usb_controller.ExistingAddress)).
sub edi, esi
lea edi, [eax+(edi-4-usb_controller.ExistingAddresses)*8]
; 6. Store the allocated address in SetAddressBuffer and fill remaining fields.
; Note that usb_controller is zeroed at allocation, so only command byte needs
; to be filled.
mov byte [esi+usb_controller.SetAddressBuffer+1], USB_SET_ADDRESS
mov dword [esi+usb_controller.SetAddressBuffer+2], edi
; 7. Return non-zero value in eax.
inc eax
.nothing:
ret
.error:
dbgstr 'cannot allocate USB address'
xor eax, eax
jmp .nothing
endp
 
; This procedure is called by USB stack when SET_ADDRESS request initiated by
; usb_new_device is completed, either successfully or unsuccessfully.
; Note that USB stack uses esi = pointer to usb_controller.
proc usb_set_address_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
push ebx ; save ebx to be stdcall
mov ebx, [pipe]
; 1. In any case, cancel the timer.
mov eax, [ebx+usb_pipe.DeviceData]
stdcall cancel_timer_hs, [eax+usb_device_data.Timer]
mov eax, [ebx+usb_pipe.DeviceData]
mov [eax+usb_device_data.Timer], 0
; Load data to registers for further references.
mov ecx, dword [esi+usb_controller.SetAddressBuffer+2]
mov eax, [esi+usb_controller.HardwareFunc]
; 2. Check whether the device has accepted new address. If so, proceed to 3.
; Otherwise, go to 4 if killed by usb_set_address_timeout or to 5 otherwise.
cmp [status], USB_STATUS_CANCELLED
jz .timeout
cmp [status], 0
jnz .error
; 3. Address accepted.
; 3a. The controller-specific structure for the control pipe still uses
; zero address. Call the controller-specific function to change it to
; the actual address.
; Note that the hardware could cache the controller-specific structure,
; so setting the address could take some time until the cache is evicted.
; Thus, the call is asynchronous; meet us in usb_after_set_address when it will
; be safe to continue.
; dbgstr 'address set in device'
call [eax+usb_hardware_func.SetDeviceAddress]
; 3b. If the port is in non-root hub, clear 'reset in progress' flag.
; In any case, proceed to 6.
mov eax, [esi+usb_controller.ResettingHub]
test eax, eax
jz .return
and [eax+usb_hub.Actions], not HUB_RESET_IN_PROGRESS
.return:
; 6. Address configuration done, we can proceed with other ports.
; Call the worker function for that.
call usb_test_pending_port
.wakeup:
push esi edi
call usb_wakeup
pop edi esi
.nothing:
pop ebx ; restore ebx to be stdcall
ret
.timeout:
; 4. Device continues to NAK the request. Reset it and retry.
mov edx, [ebx+usb_pipe.DeviceData]
mov ecx, [edx+usb_device_data.DeviceDescriptor]
add ecx, ecx
cmp ecx, TIMEOUT_SET_ADDRESS_LAST
ja .error
mov [edx+usb_device_data.DeviceDescriptor], ecx
dbgstr 'Timeout in USB device initialization, trying to reset...'
cmp [esi+usb_controller.ResettingHub], 0
jz .reset_roothub
push esi
mov esi, [esi+usb_controller.ResettingHub]
call usb_hub_initiate_reset
pop esi
jmp .nothing
.reset_roothub:
movzx ecx, [esi+usb_controller.ResettingPort]
call [eax+usb_hardware_func.InitiateReset]
jmp .wakeup
.error:
; 5. Device error: device not responding, disconnect etc.
DEBUGF 1,'K : error %d in SET_ADDRESS, USB device disabled\n',[status]
; 5a. The address has not been accepted. Mark it as free.
bts dword [esi+usb_controller.ExistingAddresses], ecx
; 5b. Disable the port with bad device.
; For the root hub, call the controller-specific function and go to 6.
; For non-root hubs, let the hub code do its work and return (the request
; could take some time, the hub code is responsible for proceeding).
cmp [esi+usb_controller.ResettingHub], 0
jz .roothub
mov eax, [esi+usb_controller.ResettingHub]
call usb_hub_disable_resetting_port
jmp .nothing
.roothub:
movzx ecx, [esi+usb_controller.ResettingPort]
call [eax+usb_hardware_func.PortDisable]
jmp .return
endp
 
; This procedure is called from usb_subscription_done when the hardware cache
; is cleared after request from usb_set_address_callback.
; in: ebx -> usb_pipe
proc usb_after_set_address
; dbgstr 'address set for controller'
; Issue control transfer GET_DESCRIPTOR(DEVICE_DESCR) for first 8 bytes.
; Remember, we still do not know the actual packet size;
; 8-bytes-request is safe.
; usb_new_device has allocated 8 extra bytes besides sizeof.usb_device_data;
; use them for both input and output.
mov eax, [ebx+usb_pipe.DeviceData]
add eax, usb_device_data.DeviceDescriptor
mov dword [eax], \
80h + \ ; device-to-host, standard, device-wide
(USB_GET_DESCRIPTOR shl 8) + \ ; request
(0 shl 16) + \ ; descriptor index: there is only one
(USB_DEVICE_DESCR shl 24) ; descriptor type
mov dword [eax+4], 8 shl 16 ; data length
stdcall usb_control_async, ebx, eax, eax, 8, usb_get_descr8_callback, eax, 0
ret
endp
 
; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE_DESCR)
; request initiated by usb_after_set_address is completed, either successfully
; or unsuccessfully.
; Note that USB stack uses esi = pointer to usb_controller.
proc usb_get_descr8_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; mov eax, [buffer]
; DEBUGF 1,'K : descr8: l=%x; %x %x %x %x %x %x %x %x\n',[length],\
; [eax]:2,[eax+1]:2,[eax+2]:2,[eax+3]:2,[eax+4]:2,[eax+5]:2,[eax+6]:2,[eax+7]:2
push edi ebx ; save used registers to be stdcall
mov ebx, [pipe]
; 1. Check whether the operation was successful.
; If not, say something to the debug board and stop the initialization.
cmp [status], 0
jnz .error
; 2. Length of descriptor must be at least sizeof.usb_device_descr bytes.
; If not, say something to the debug board and stop the initialization.
mov eax, [ebx+usb_pipe.DeviceData]
cmp [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bLength], sizeof.usb_device_descr
jb .error
; 3. Now first 8 bytes of device descriptor are known;
; set DeviceDescrSize accordingly.
mov [eax+usb_device_data.DeviceDescrSize], 8
; 4. The controller-specific structure for the control pipe still uses
; the fake "maximum packet size". Call the controller-specific function to
; change it to the actual packet size from the device.
; Note that the hardware could cache the controller-specific structure,
; so changing it could take some time until the cache is evicted.
; Thus, the call is asynchronous; meet us in usb_after_set_endpoint_size
; when it will be safe to continue.
movzx ecx, [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bMaxPacketSize0]
mov eax, [esi+usb_controller.HardwareFunc]
call [eax+usb_hardware_func.SetEndpointPacketSize]
.nothing:
; 5. Return.
pop ebx edi ; restore used registers to be stdcall
ret
.error:
dbgstr 'error with USB device descriptor'
jmp .nothing
endp
 
; This procedure is called from usb_subscription_done when the hardware cache
; is cleared after request from usb_get_descr8_callback.
; in: ebx -> usb_pipe
proc usb_after_set_endpoint_size
; 1. Reallocate memory for device data:
; add memory for now-known size of device descriptor and extra 8 bytes
; for further actions.
; 1a. Allocate new memory.
mov eax, [ebx+usb_pipe.DeviceData]
movzx eax, [eax+usb_device_data.DeviceDescriptor+usb_device_descr.bLength]
; save length for step 2
push eax
add eax, sizeof.usb_device_data + 8
call malloc
; 1b. If failed, say something to the debug board and stop the initialization.
test eax, eax
jz .nomemory
; 1c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
push eax
push esi edi
mov esi, [ebx+usb_pipe.DeviceData]
mov [ebx+usb_pipe.DeviceData], eax
mov edi, eax
mov eax, esi
mov ecx, sizeof.usb_device_data / 4
rep movsd
pop edi esi
call usb_reinit_pipe_list
; 1d. Free the old memory.
call free
pop eax
; 2. Issue control transfer GET_DESCRIPTOR(DEVICE) for full descriptor.
; restore length saved in step 1a
pop edx
add eax, sizeof.usb_device_data
mov dword [eax], \
80h + \ ; device-to-host, standard, device-wide
(USB_GET_DESCRIPTOR shl 8) + \ ; request
(0 shl 16) + \ ; descriptor index: there is only one
(USB_DEVICE_DESCR shl 24) ; descriptor type
and dword [eax+4], 0
mov [eax+6], dl ; data length
stdcall usb_control_async, ebx, eax, eax, edx, usb_get_descr_callback, eax, 0
; 3. Return.
ret
.nomemory:
dbgstr 'No memory for device data'
ret
endp
 
; This procedure is called by USB stack when GET_DESCRIPTOR(DEVICE)
; request initiated by usb_after_set_endpoint_size is completed,
; either successfully or unsuccessfully.
proc usb_get_descr_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; Note: the prolog is the same as in usb_get_descr8_callback.
push edi ebx ; save used registers to be stdcall
; 1. Check whether the operation was successful.
; If not, say something to the debug board and stop the initialization.
cmp [status], 0
jnz usb_get_descr8_callback.error
; The full descriptor is known, dump it if specified by compile-time option.
if USB_DUMP_DESCRIPTORS
mov eax, [buffer]
mov ecx, [length]
sub ecx, 8
jbe .skipdebug
DEBUGF 1,'K : device descriptor:'
@@:
DEBUGF 1,' %x',[eax]:2
inc eax
dec ecx
jnz @b
DEBUGF 1,'\n'
.skipdebug:
end if
; 2. Check that bLength is the same as was in the previous request.
; If not, say something to the debug board and stop the initialization.
; It is important, because usb_after_set_endpoint_size has allocated memory
; according to the old bLength. Note that [length] for control transfers
; includes 8 bytes of setup packet, so data length = [length] - 8.
mov eax, [buffer]
movzx ecx, [eax+usb_device_descr.bLength]
add ecx, 8
cmp [length], ecx
jnz usb_get_descr8_callback.error
; Amuse the user if she is watching the debug board.
mov cl, [eax+usb_device_descr.bNumConfigurations]
DEBUGF 1,'K : found USB device with ID %x:%x, %d configuration(s)\n',\
[eax+usb_device_descr.idVendor]:4,\
[eax+usb_device_descr.idProduct]:4,\
cl
; 3. If there are no configurations, stop the initialization.
cmp [eax+usb_device_descr.bNumConfigurations], 0
jz .nothing
; 4. Copy length of device descriptor to device data structure.
movzx edx, [eax+usb_device_descr.bLength]
mov [eax+usb_device_data.DeviceDescrSize-usb_device_data.DeviceDescriptor], dl
; 5. Issue control transfer GET_DESCRIPTOR(CONFIGURATION). We do not know
; the full length of that descriptor, so start with first 8 bytes, they contain
; the full length.
; usb_after_set_endpoint_size has allocated 8 extra bytes after the
; device descriptor, use them for both input and output.
add eax, edx
mov dword [eax], \
80h + \ ; device-to-host, standard, device-wide
(USB_GET_DESCRIPTOR shl 8) + \ ; request
(0 shl 16) + \ ; descriptor index: there is only one
(USB_CONFIG_DESCR shl 24) ; descriptor type
mov dword [eax+4], 8 shl 16 ; data length
stdcall usb_control_async, [pipe], eax, eax, 8, usb_know_length_callback, eax, 0
.nothing:
; 6. Return.
pop ebx edi ; restore used registers to be stdcall
ret
endp
 
; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
; request initiated by usb_get_descr_callback is completed,
; either successfully or unsuccessfully.
proc usb_know_length_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
push ebx ; save used registers to be stdcall
; 1. Check whether the operation was successful.
; If not, say something to the debug board and stop the initialization.
cmp [status], 0
jnz .error
; 2. Get the total length of data associated with config descriptor and store
; it in device data structure. The total length must be at least
; sizeof.usb_config_descr bytes; if not, say something to the debug board and
; stop the initialization.
mov eax, [buffer]
mov edx, [pipe]
movzx ecx, [eax+usb_config_descr.wTotalLength]
mov eax, [edx+usb_pipe.DeviceData]
cmp ecx, sizeof.usb_config_descr
jb .error
mov [eax+usb_device_data.ConfigDataSize], ecx
; 3. Reallocate memory for device data:
; include usb_device_data structure, device descriptor,
; config descriptor with all associated data, and extra bytes
; sufficient for 8 bytes control packet and for one usb_interface_data struc.
; Align extra bytes to dword boundary.
if sizeof.usb_interface_data > 8
.extra_size = sizeof.usb_interface_data
else
.extra_size = 8
end if
; 3a. Allocate new memory.
movzx edx, [eax+usb_device_data.DeviceDescrSize]
lea eax, [ecx+edx+sizeof.usb_device_data+.extra_size+3]
and eax, not 3
push eax
call malloc
pop edx
; 3b. If failed, say something to the debug board and stop the initialization.
test eax, eax
jz .nomemory
; 3c. Copy data from old memory to new memory and switch the pointer in usb_pipe.
push eax
mov ebx, [pipe]
push esi edi
mov esi, [ebx+usb_pipe.DeviceData]
mov edi, eax
mov [ebx+usb_pipe.DeviceData], eax
mov eax, esi
movzx ecx, [esi+usb_device_data.DeviceDescrSize]
sub edx, .extra_size
mov [esi+usb_device_data.Interfaces], edx
add ecx, sizeof.usb_device_data + 8
mov edx, ecx
shr ecx, 2
and edx, 3
rep movsd
mov ecx, edx
rep movsb
pop edi esi
call usb_reinit_pipe_list
; 3d. Free old memory.
call free
pop eax
; 4. Issue control transfer GET_DESCRIPTOR(CONFIGURATION) for full descriptor.
movzx ecx, [eax+usb_device_data.DeviceDescrSize]
mov edx, [eax+usb_device_data.ConfigDataSize]
lea eax, [eax+ecx+sizeof.usb_device_data]
mov dword [eax], \
80h + \ ; device-to-host, standard, device-wide
(USB_GET_DESCRIPTOR shl 8) + \ ; request
(0 shl 16) + \ ; descriptor index: there is only one
(USB_CONFIG_DESCR shl 24) ; descriptor type
and dword [eax+4], 0
mov word [eax+6], dx ; data length
stdcall usb_control_async, [pipe], eax, eax, edx, usb_set_config_callback, eax, 0
.nothing:
; 5. Return.
pop ebx ; restore used registers to be stdcall
ret
.error:
dbgstr 'error with USB configuration descriptor'
jmp .nothing
.nomemory:
dbgstr 'No memory for device data'
jmp .nothing
endp
 
; This procedure is called by USB stack when GET_DESCRIPTOR(CONFIGURATION)
; request initiated by usb_know_length_callback is completed,
; either successfully or unsuccessfully.
proc usb_set_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
; Note that the prolog is the same as in usb_know_length_callback.
push ebx ; save used registers to be stdcall
; 1. Check whether the operation was successful.
; If not, say something to the debug board and stop the initialization.
xor ecx, ecx
mov ebx, [pipe]
cmp [status], ecx
jnz usb_know_length_callback.error
; The full descriptor is known, dump it if specified by compile-time option.
if USB_DUMP_DESCRIPTORS
mov eax, [buffer]
mov ecx, [length]
sub ecx, 8
jbe .skip_debug
DEBUGF 1,'K : config descriptor:'
@@:
DEBUGF 1,' %x',[eax]:2
inc eax
dec ecx
jnz @b
DEBUGF 1,'\n'
.skip_debug:
xor ecx, ecx
end if
; 2. Issue control transfer SET_CONFIGURATION to activate this configuration.
; Usually this is the only configuration.
; Use extra bytes allocated by usb_know_length_callback;
; offset from device data start is stored in Interfaces.
mov eax, [ebx+usb_pipe.DeviceData]
mov edx, [buffer]
add eax, [eax+usb_device_data.Interfaces]
mov dl, [edx+usb_config_descr.bConfigurationValue]
mov dword [eax], USB_SET_CONFIGURATION shl 8
mov dword [eax+4], ecx
mov byte [eax+2], dl
stdcall usb_control_async, [pipe], eax, ecx, ecx, usb_got_config_callback, [buffer], ecx
pop ebx ; restore used registers to be stdcall
ret
endp
 
; This procedure is called by USB stack when SET_CONFIGURATION
; request initiated by usb_set_config_callback is completed,
; either successfully or unsuccessfully.
; If successfully, the device is configured and ready to work,
; pass the device to the corresponding driver(s).
proc usb_got_config_callback stdcall, pipe:dword, status:dword, buffer:dword, length:dword, calldata:dword
locals
InterfacesData dd ?
NumInterfaces dd ?
driver dd ?
endl
; 1. If there was an error, say something to the debug board and stop the
; initialization.
cmp [status], 0
jz @f
dbgstr 'USB error in SET_CONFIGURATION'
ret
@@:
push ebx edi ; save used registers to be stdcall
; 2. Sanity checks: the total length must be the same as before (because we
; have allocated memory assuming the old value), length of config descriptor
; must be at least sizeof.usb_config_descr (we use fields from it),
; there must be at least one interface.
mov ebx, [pipe]
mov ebx, [ebx+usb_pipe.DeviceData]
mov eax, [calldata]
mov edx, [ebx+usb_device_data.ConfigDataSize]
cmp [eax+usb_config_descr.wTotalLength], dx
jnz .invalid
cmp [eax+usb_config_descr.bLength], 9
jb .invalid
movzx edx, [eax+usb_config_descr.bNumInterfaces]
test edx, edx
jnz @f
.invalid:
dbgstr 'error: invalid configuration descriptor'
jmp .nothing
@@:
; 3. Store the number of interfaces in device data structure.
mov [ebx+usb_device_data.NumInterfaces], edx
; 4. If there is only one interface (which happens quite often),
; the memory allocated in usb_know_length_callback is sufficient.
; Otherwise (which also happens quite often), reallocate device data.
; 4a. Check whether there is only one interface. If so, skip this step.
cmp edx, 1
jz .has_memory
; 4b. Allocate new memory.
mov eax, [ebx+usb_device_data.Interfaces]
lea eax, [eax+edx*sizeof.usb_interface_data]
call malloc
; 4c. If failed, say something to the debug board and
; stop the initialization.
test eax, eax
jnz @f
dbgstr 'No memory for device data'
jmp .nothing
@@:
; 4d. Copy data from old memory to new memory and switch the pointer in usb_pipe.
push eax
push esi
mov ebx, [pipe]
mov edi, eax
mov esi, [ebx+usb_pipe.DeviceData]
mov [ebx+usb_pipe.DeviceData], eax
mov eax, esi
mov ecx, [esi+usb_device_data.Interfaces]
shr ecx, 2
rep movsd
pop esi
call usb_reinit_pipe_list
; 4e. Free old memory.
call free
pop ebx
.has_memory:
; 5. Initialize interfaces table: zero all contents.
mov edi, [ebx+usb_device_data.Interfaces]
add edi, ebx
mov [InterfacesData], edi
mov ecx, [ebx+usb_device_data.NumInterfaces]
if sizeof.usb_interface_data <> 8
You have changed sizeof.usb_interface_data? Modify this place too.
end if
add ecx, ecx
xor eax, eax
rep stosd
; No interfaces are found yet.
mov [NumInterfaces], eax
; 6. Get the pointer to config descriptor data.
; Note: if there was reallocation, [buffer] is not valid anymore,
; so calculate value based on usb_device_data.
movzx eax, [ebx+usb_device_data.DeviceDescrSize]
lea eax, [eax+ebx+sizeof.usb_device_data]
mov [calldata], eax
mov ecx, [ebx+usb_device_data.ConfigDataSize]
; 7. Loop over all descriptors,
; scan for interface descriptors with bAlternateSetting = 0,
; load the corresponding driver, call its AddDevice function.
.descriptor_loop:
; While in loop: eax points to the current descriptor,
; ecx = number of bytes left, the iteration starts only if ecx is nonzero,
; edx = size of the current descriptor.
; 7a. The first byte is always accessible; it contains the length of
; the current descriptor. Validate that the length is at least 2 bytes,
; and the entire descriptor is readable (the length is at most number of
; bytes left).
movzx edx, [eax+usb_descr.bLength]
cmp edx, sizeof.usb_descr
jb .invalid
cmp ecx, edx
jb .invalid
; 7b. Check descriptor type. Ignore all non-INTERFACE descriptor.
cmp byte [eax+usb_descr.bDescriptorType], USB_INTERFACE_DESCR
jz .interface
.next_descriptor:
; 7c. Advance pointer, decrease length left, if there is still something left,
; continue the loop.
add eax, edx
sub ecx, edx
jnz .descriptor_loop
.done:
.nothing:
pop edi ebx ; restore used registers to be stdcall
ret
.interface:
; 7d. Validate the descriptor length.
cmp edx, sizeof.usb_interface_descr
jb .next_descriptor
; 7e. If bAlternateSetting is nonzero, this descriptor actually describes
; another mode of already known interface and belongs to the already loaded
; driver; amuse the user and continue to 7c.
cmp byte [eax+usb_interface_descr.bAlternateSetting], 0
jz @f
DEBUGF 1,'K : note: alternate setting with %x/%x/%x\n',\
[eax+usb_interface_descr.bInterfaceClass]:2,\
[eax+usb_interface_descr.bInterfaceSubClass]:2,\
[eax+usb_interface_descr.bInterfaceProtocol]:2
jmp .next_descriptor
@@:
; 7f. Check that the new interface does not overflow allocated table.
mov edx, [NumInterfaces]
inc edx
cmp edx, [ebx+usb_device_data.NumInterfaces]
ja .invalid
; 7g. We have found a new interface. Advance bookkeeping vars.
mov [NumInterfaces], edx
add [InterfacesData], sizeof.usb_interface_data
; 7h. Save length left and pointer to the current interface descriptor.
push ecx eax
; Amuse the user if she is watching the debug board.
DEBUGF 1,'K : USB interface class/subclass/protocol = %x/%x/%x\n',\
[eax+usb_interface_descr.bInterfaceClass]:2,\
[eax+usb_interface_descr.bInterfaceSubClass]:2,\
[eax+usb_interface_descr.bInterfaceProtocol]:2
; 7i. Select the correct driver based on interface class.
; For hubs, go to 7j. Otherwise, go to 7k.
; Note: this should be rewritten as table-based lookup when more drivers will
; be available.
cmp byte [eax+usb_interface_descr.bInterfaceClass], 9
jz .found_hub
mov edx, usb_hid_name
cmp byte [eax+usb_interface_descr.bInterfaceClass], 3
jz .load_driver
mov edx, usb_print_name
cmp byte [eax+usb_interface_descr.bInterfaceClass], 7
jz .load_driver
mov edx, usb_stor_name
cmp byte [eax+usb_interface_descr.bInterfaceClass], 8
jz .load_driver
mov edx, usb_other_name
jmp .load_driver
.found_hub:
; 7j. Hubs are a part of USB stack, thus, integrated into the kernel.
; Use the pointer to hub callbacks and go to 7m.
mov eax, usb_hub_pseudosrv - USBSRV.usb_func
jmp .driver_loaded
.load_driver:
; 7k. Load the corresponding driver.
push ebx esi edi
stdcall get_service, edx
pop edi esi ebx
; 7l. If failed, say something to the debug board and go to 7p.
test eax, eax
jnz .driver_loaded
dbgstr 'failed to load class driver'
jmp .next_descriptor2
.driver_loaded:
; 7m. Call AddDevice function of the driver.
; Note that top of stack contains a pointer to the current interface,
; saved by step 7h.
mov [driver], eax
mov eax, [eax+USBSRV.usb_func]
pop edx
push edx
; Note: usb_hub_init assumes that edx points to usb_interface_descr,
; ecx = length rest; if you change the code, modify usb_hub_init also.
stdcall [eax+USBFUNC.add_device], [pipe], [calldata], edx
; 7n. If failed, say something to the debug board and go to 7p.
test eax, eax
jnz .store_data
dbgstr 'USB device initialization failed'
jmp .next_descriptor2
.store_data:
; 7o. Store the returned value and the driver handle to InterfacesData.
; Note that step 7g has already advanced InterfacesData.
mov edx, [InterfacesData]
mov [edx+usb_interface_data.DriverData-sizeof.usb_interface_data], eax
mov eax, [driver]
mov [edx+usb_interface_data.DriverFunc-sizeof.usb_interface_data], eax
.next_descriptor2:
; 7p. Restore registers saved in step 7h, get the descriptor length and
; continue to 7c.
pop eax ecx
movzx edx, byte [eax+usb_descr.bLength]
jmp .next_descriptor
endp
 
; Driver names, see step 7i of usb_got_config_callback.
iglobal
usb_hid_name db 'usbhid',0
usb_stor_name db 'usbstor',0
usb_print_name db 'usbprint',0
usb_other_name db 'usbother',0
endg
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus/usb/common.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bus
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/crc.inc
0,0 → 1,42
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; This crc32 routine doesn't use precomputed table to allow different
; polynomials, which is the first param.
; Partial hash in assumed to be eax (both in and out).
; Usage:
; 1. mov eax, -1
; 2. stdcall crypto.crc32 zero or more times
; 3. xor eax, -1
proc crc_32 _poly, _buffer, _length
push ebx ecx edx esi
 
mov esi, [_buffer]
.next_byte:
dec [_length]
js .done
movzx ebx, byte[esi]
inc esi
mov ecx, 8
.next_bit:
mov edx, eax
xor edx, ebx
shr eax, 1
test edx, 1
jz @f
xor eax, [_poly]
@@:
shr ebx, 1
dec ecx
jnz .next_bit
jmp .next_byte
.done:
pop esi edx ecx ebx
ret
endp
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/unicode.inc
0,0 → 1,117
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2020-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; Version 2, or (at your option) any later version. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
unicode.utf8.decode:
test ecx, ecx
jz .error
movzx eax, byte[esi]
test al, al
jns .read1
shl al, 2
jnc .error
shl al, 1
jnc .read2
shl al, 1
jnc .read3
shl al, 1
jnc .read4
jmp .error
.read1:
sub ecx, 1
add esi, 1
jmp .done
.read2:
cmp ecx, 2
jb .error
shl eax, 5
mov al, [esi+1]
shl al, 1
jnc .error
shl al, 1
jc .error
shr eax, 2
sub ecx, 2
add esi, 2
jmp .done
.read3:
cmp ecx, 3
jb .error
shl eax, 4
mov al, [esi+1]
shl al, 1
jnc .error
shl al, 1
jc .error
shl eax, 6
mov al, [esi+2]
shl al, 1
jnc .error
shl al, 1
jc .error
shr eax, 2
sub ecx, 3
add esi, 3
jmp .done
.read4:
cmp ecx, 4
jb .error
shl eax, 3
mov al, [esi+1]
shl al, 1
jnc .error
shl al, 1
jc .error
shl eax, 6
mov al, [esi+2]
shl al, 1
jnc .error
shl al, 1
jc .error
shl eax, 6
mov al, [esi+3]
shl al, 1
jnc .error
shl al, 1
jc .error
shr eax, 2
sub ecx, 4
add esi, 4
jmp .done
.error:
.done:
ret
 
 
unicode.cp866.encode:
call uni2ansi_char
ret
 
 
unicode.utf16.encode:
cmp eax, 0x110000
jae .error
cmp eax, 0x10000
jae .write2
cmp eax, 0xe000
jae .write1
cmp eax, 0xd800
jb .write1
jmp .error
.write1:
jmp .done
.write2:
sub eax, 0x10000
shl eax, 6
shr ax, 6
or eax, 0xdc00d800
jmp .done
.done:
.error:
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/kernel32.inc
0,0 → 1,79
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
include "core/sync.inc" ; macros for synhronization objects
include "core/sys32.inc" ; process management
include "core/sched.inc" ; process scheduling
include "core/syscall.inc"
include "core/fpu.inc" ; all fpu/sse support
include "core/memory.inc"
include "core/mtrr.inc"
include "core/heap.inc"
include "core/malloc.inc" ; small kernel heap
include "core/taskman.inc"
include "core/dll.inc"
include "core/peload.inc"
include "core/exports.inc"
include "core/string.inc"
include "core/v86.inc" ; 16-bit mode machine
include "core/irq.inc" ; interrupt handling functions
include "core/apic.inc"
include "core/hpet.inc"
include "core/timers.inc"
include "core/clipboard.inc"
include "core/slab.inc"
 
include "acpi/acpi.inc"
 
include "posix/posix.inc"
 
include "boot/shutdown.inc" ; kernel shutdown
 
include "video/vesa20.inc"
include "video/blitter.inc"
include "video/vga.inc" ; VGA 16 color functions
include "video/cursors.inc"
include "video/framebuffer.inc"
 
include "gui/window.inc"
include "gui/event.inc"
include "gui/font.inc"
include "gui/button.inc"
include "gui/mouse.inc" ; cursor
include "gui/skincode.inc" ; windows' skin
 
include "hid/keyboard.inc"
include "hid/mousedrv.inc"
include "hid/set_dtc.inc" ; setting date,time,clock and alarm-clock
 
include "sound/playnote.inc" ; player Note for PC Speaker
 
include "bus/pci/pci32.inc"
include "bus/usb/init.inc"
 
include "blkdev/flp_drv.inc" ; floppy driver
include "blkdev/fdc.inc"
include "blkdev/cd_drv.inc" ; CD driver
include "blkdev/ide_cache.inc" ; CD cache
include "blkdev/hd_drv.inc" ; HDD driver
include "blkdev/bd_drv.inc" ; BIOS disks driver
include "blkdev/rd.inc" ; ramdisk driver
include "blkdev/disk.inc" ; support for plug-n-play disks
include "blkdev/disk_cache.inc" ; caching for plug-n-play disks
 
include "fs/fs_lfn.inc" ; sysfunction 70
 
include "network/stack.inc"
 
include "crc.inc" ; checksums
include "unicode.inc"
 
; include "imports.inc"
; include "core/ext_lib.inc"
; include "core/conf_lib.inc"
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/Tupfile.lua
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")
/kernel/branches/kolibrios-pe-clevermouse/data16.inc
0,0 → 1,87
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
flm db 0
preboot_lfb db 0
preboot_bootlog db 0
boot_drive db 0
 
align 4
old_ints_h:
dw 0x400
dd 0
dw 0
 
if ~ defined extended_primary_loader ; restart from memory is not supported in extended primary loader cfg
kernel_restart_bootblock:
db 1 ; version
dw 1 ; floppy image is in memory
dd 0 ; cannot save parameters
end if
 
; table for move to extended memory (int 15h, ah=87h)
align 8
movedesc:
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
 
db 0xff,0xff,0x0,0xa0,0x00,0x93,0x0,0x0
db 0xff,0xff,0x0,0x00,0x10,0x93,0x0,0x0
 
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
 
fwmovedesc:
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
 
db 0xff,0xff,0x0,0x00,0x10,0x93,0x0,0x0
db 0xff,0xff,0x0,0xa0,0x00,0x93,0x0,0x0
 
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
 
if defined extended_primary_loader
; look in PrimaryLoader.txt for the description
bootdevice dw 0 ; ax from primary loader
bootfs dw 0 ; bx from primary loader
bootcallback dd 0 ; ds:si from primary loader
; data for configuration file loading, look in PrimaryLoader.txt
config_file_struct:
dw 0, 4000h ; load to 4000:0000
dw 16 ; read no more than 16*4K = 64K
db 'config.ini',0
; data for configuration file parsing
macro config_variable string,parser
{
local len
len dw 0
db string
store word $ - len - 2 at len
dw parser
}
config_file_variables:
config_variable 'timeout', parse_timeout
config_variable 'resolution', parse_resolution
config_variable 'vbemode', parse_vbemode
config_variable 'biosdisks', parse_biosdisks
config_variable 'imgfrom', parse_imgfrom
config_variable 'syspath', parse_syspath
dw 0
; data for image file loading, look in PrimaryLoader.txt
image_file_struct:
dw 0, 4000h ; load to 4000:0000
dw 16 ; read no more than 16*4K = 64K
db 'kolibri.img',0
end if
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/readme-ext-loader.txt
0,0 → 1,55
При компиляции ядра можно задать - например, в lang.inc, - дополнительный
параметр extended_primary_loader=1; он переключает ядро на альтернативный
способ загрузки. Загрузка несовместима
с основой версией ядра; требуется специальный первичный загрузчик, существующие
собраны в папке bootloader/extended_primary_loader.
Есть варианты загрузки с FAT12/FAT16/FAT32/ISO,
есть вариант загрузчика, встраивающегося в загрузку Windows. Встраивание
в GRUB аналогично описанному для основного способа загрузки -
последним загрузчиком в цепочке
при этом оказывается тот, который установлен в образе дискеты FAT12.
 
При загрузке поддерживается опрос параметров из файла config.ini,
но не поддерживается сохранение выбранных параметров. Файл config.ini
ищется рядом с первичным загрузчиком, как и ядро kernel.mnt; в случае
загрузчика с дискеты эти файлы располагаются на самой дискете,
в случае других загрузчиков - рядом с первичным загрузчиком вне образа.
 
Если config.ini не найден, используются умолчальные значения. Если
config.ini найден, то он разбивается на строчки, строчки должны иметь
вид <параметр>=<значение>, перед параметром и вокруг знака равенства
могут быть пробелы, всё, что идёт в строке после значения, игнорируется.
Параметры чувствительны к регистру символов.
Строки, не имеющие такого вида, а также строки, в которых параметр неизвестен,
а также строки, в которых значение недопустимо, игнорируются.
 
Все числа должны быть целыми неотрицательными, записанными в десятичной
системе счисления. Булевские значения кодируются следующим образом:
0=off=no соответствует выключенному параметру, 1=on=yes - включённому.
 
Известные параметры:
 
timeout=<число секунд> задаёт время ожидания в экране выбора параметров.
Если таймаут больше 9, используется значение 9. Значение по умолчанию 5.
 
resolution=<ширина>*<высота> или <ширина>x<высота> задаёт желаемое
разрешение графического режима. Если такого графического режима,
устраивающего систему, не найдено, параметр игнорируется. По умолчанию
пробуются последовательно разрешения 1024*768, 800*600, 640*480.
 
vbemode=<номер видеорежима VBE> задаёт желаемый графический режим.
Если такой режим не существует или не устраивает систему, параметр
игнорируется. Параметр более приоритетен, чем resolution. Умолчального
значения нет.
 
biosdisks=<включить доступ к дискам через BIOS> - булевский параметр.
Умолчальное значение 1.
 
imgfrom=<источник рамдиска>. 1 - грузить дискету, 2 - грузить файл
kolibri.img, находящийся рядом с первичным загрузчиком. Умолчальное
значение 1 при загрузке с дискеты и 2 в противном случае.
 
syspath=<путь к директории /sys> - строка.
Умолчальное значение /RD/1. Может быть и не корнем раздела, например
/HD0/1/KOLIBRIOS. Ядро должно уметь работать с носителем без подгружаемых
драйверов.
/kernel/branches/kolibrios-pe-clevermouse/memmap.inc
0,0 → 1,272
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; MEMORY MAP
;
; Boot:
;
; BOOT_LO / boot_data structure
; 0:9000 byte bits per pixel
; 0:9001 word scanline length
; 0:9008 word vesa video mode
; 0:900A word X res
; 0:900C word Y res
; 0:9014 dword Vesa 1.2 pm bank switch
; 0:9018 dword Vesa 2.0 LFB address
; 0:901C byte 0 or 1 : enable MTRR graphics acceleration
; 0:901D byte (0 or 1) start the first app (right now it's LAUNCHER) after kernel is loaded?
; 0:901E byte If nonzero, duplicates debug output to the screen.
; 0:901F byte DMA write : 1=yes, 2=no
; 0:9020 8bytes pci data
; 0:9030 byte shutdown type (see sysfn 18.9)
; 0:9040 dword entry point of APM BIOS
; 0:9044 word version (BCD)
; 0:9046 word flags
; 0:9050 word APM_CODE_32
; 0:9052 word APM_CODE_16
; 0:9054 word APM_DATA_16
; 0:907F byte number of BIOS hard disks
; 0:9080 Nbytes BIOS hard disks
; 0:9100 word available physical memory map: number of blocks
; 0:9104 available physical memory map: blocks
;
; Runtime:
;
; 0x00000000 -> 0x7FFFFFFF application 2Gb
 
; 0x80000000 -> 0FFF physical page zero - do not write
; (used by int 13h in some configurations)
;
; 0x80001000 -> 2FFF window_data - 256 entries
;
; 0000 dword x start
; 0004 dword y start
; 0008 dword x size
; 000C dword y size
; 0010 dword color of work area
; 0014 dword color of grab bar
; 0018 dword color of frames
; 001C dword window flags, +30 = window drawn, +31 redraw flag
;
; 3000 -> 4FFF task list - 256 entries
;
; 00 dword process count
; 04 dword no of processes
; 10 dword base of running process at 0x3000+
;
; 20 dword application event mask
; 24 dword PID - process identification number
; 2a byte slot state: 0=running, 1,2=suspended
; 3=zombie, 4=terminate,
; 5=waiting for event, 9 = not used
; 2e byte window number on screen
; 30 dword exact position in memory
; 34 dword counter sum
; 38 dword time stamp counter add
; 3c dword cpu usage in cpu timer tics
;
;
; 5000 -> 68FF free (6k6)
; 6900 -> 6EFF saved picture under mouse pointer (1k5)
;
; 6F00 -> 6FFF free (256)
;
; 7000 -> 7FFF used CD driver
;
; 8000 -> A3FF used FLOPPY driver
;
; A400 -> B0FF free (3k3), unused ACTIVE_PROC_STACK
 
; B100 -> B307 IDT for int_0x00..int_0x40
 
; B308 -> BFFF free (3k3)
 
; C000 -> C3FF window stack C000 no of windows - all in words
; C402 -> C7FF window position in stack
; D000 -> D1FF FDC controller
; D200 -> D3FF FDC controller for Fat12
; D400 -> DFFF free (3k)
; E000 byte multitasking started
; E020 dword putpixel address
; E024 dword getpixel address
; E030 dword Vesa 1.2 pm bank switch address
; E034 -> F1FF free (4k5)
; F200 dword mousepicture -pointer
; F204 dword mouse appearance counter
; F208 -> F2FF free (248)
; F300 dword x & y temp for windowmove
; F304 -> F3FF free (252)
; F400 byte no of keys in buffer
; F401 byte 'buffer'
; F402 -> F4FF reserved for keys
; F500 byte no of buttons in buffer
; F501 dword 'buffer'
; F502 -> F5FF reserved for buttons
; F600 dword tsc / second
; F604 byte (unused?) mouse port: 1 ps2, 2 com1, 3 com2
; F605 -> FAFF free (1k2)
; FB00 -> FB0F mouse memory 00 chunk count, that includes:
; FB08 word -- mouse H-scroll
; FB0A word -- mouse x
; FB0C word -- mouse y
; FB0E word -- mouse V-scroll
; FB10 -> FB17 mouse color mem
; FB21 x move
; FB22 y move
; FB28 high bits temp
; FB30 color temp
; FB40 byte buttons down
; FB44 byte 0 mouse down -> do not draw
; FB4A -> FB4D FB4A-B x-under - FB4C-D y-under
; FBF1 byte bits per pixel
; FC00 -> FCFE com1/ps2 buffer
; FCFF com1/ps2 buffer count starting from FC00
; FD00 -> FDFF free (256)
; FE00 dword screen x size
; FE04 dword screen y size
; FE08 dword screen y multiplier
; FE0C dword screen mode
; FE10 -> FE7F free (112)
; FE80 dword address of LFB in physical
; FE84 dword address of applications memory start in physical ?
; FE88 dword address of button list
; FE8C dword memory to use
; FE90 -> FEFF free (112)
; FF00 byte 1 = system shutdown request
; FF01 byte task activation request?
; FFF0 byte >0 if redraw background request from app
; FFF1 byte free
; FFF2 write and read bank in screen
; FFF4 byte 0 if first mouse draw & do not return picture under
; FFF5 byte 1 do not draw pointer
; FFFF byte do not change task for 1/100 sec.
;
; 0x80010000 -> 7BC00 kernel, 32-bit run-time code (up to 431k)
;
; 0x8007CC00 -> 7DBFF stack at boot time (4k)
; 0x8007E000 -> 7FFFF main page directory
; 0x80080000 -> 8FFFF additional app info, in 256 byte steps - 256 entries
;
; 00 11db name of app running
; 0x10 dword pointer to fpu save area
; 0x14 dword event count
; 0x18 dword user fpu exceptoins handler
; 0x1c dword user sse exceptions handler
; 20 dword PL0 stack base
; 24 dword user heap base
; 28 dword user heap top
; 2c dword window cursor handle
; 30 dword first event in list
; 34 dword last event in list
; 38 dword first kernel object in list
; 3c dword last kernel object in list
; 40 dword thread esp
; 44 dword io permission map page 0
; 48 dword io permission map page 1
; 4c dword debug state: 1= load debug registers
; 50 dword current directory ptr
; 54 dword wait timeout
; 58 dword thread TSS._esp0 (= pl0 stack base + size except for V86)
; 5C-7F unused
;
; 80 dword address of random shaped window area
; 84 byte shape area scale
; 88 dword free
; 8C dword application memory size
; 90 dword window X position save
; 94 dword window Y position save
; 98 dword window X size save
; 9C dword window Y size save
; A0 dword IPC memory start
; A4 dword IPC memory size
; A8 dword event bits: mouse, stack,..
; AC dword 0 or debugger slot
; B0 dword free
; B4 byte keyboard mode: 0 = keymap, 1 = scancodes
; B8 dword physical address of directory table
; BC dword address of debug event memory
; C0 5 dd thread debug registers: DR0,DR1,DR2,DR3,DR7
;
; 0x80090000 -> 9FFFF free (64k)
; 0x800A0000 -> AFFFF screen access area
; 0x800B0000 -> FFFFF bios rest in peace -area (320k) ?
; 0x80100000 -> 27FFFF diskette image (1m5)
; 0x80280000 -> 283FFF free (16k)
;
; 0x80284000 -> 28BFFF HDD DMA AREA (32k)
; 0x8028C000 -> 297FFF free (48k)
;
; 0x80298000 -> 29FFFF auxiliary table for background smoothing code (32k)
;
; 0x802A0000 -> 2B00FF wav device buffer (64k)
; 0x802A0000 -> 2B00FF wav device status (256)
;
; 0x802B0100 -> 2B3FFD free (15k7)
;
; 0x802B3FEE -> 2B3FEF button info (64K+ 16 + 2 byte)
; 2B3FEE 0000 word number of buttons
; 2B3FF0 first button entry
;
; button entry at 0x10
; +0000 word process number
; +0002 word button id number : bits 00-15
; +0004 word x start
; +0006 word x size
; +0008 word y start
; +000A word y size
; +000C word button id number : bits 16-31
;
; 0x802C4000 -> 2C9FFF area for fast getting offset to LFB (24k)
; BPSLine_calc_area
; 0x802CA000 -> 2CFFFF area for fast getting offset to _WinMapAddress (24k)
; d_width_calc_area
;
; 0x802D0000 -> 2DFFFF reserved port area (64k)
;
; 0000 dword no of port areas reserved
; 0010 dword process id
; dword start port
; dword end port
; dword 0
;
; 0x802E0000 -> 2EFFFF irq data area (64k) ;BOOT_VAR
;
; 0x802F0000 -> 317fff free (160k)
;
; 0x80318000 -> 31ffff skin_data (32k)
;
; 0x80320000 -> 323FF3 draw data - 256 entries (4k)
; 00 dword draw limit - x start
; 04 dword draw limit - y start
; 08 dword draw limit - x end
; 0C dword draw limit - y end
;
; 0x8032BFF4 -> 32BFFF background info
; 0x80323FF4 BgrDrawMode
; 0x80323FF8 BgrDataWidth
; 0x80323FFC BgrDataHeight
;
; 0x80324000 page map (length b = memsize shr 15)
; 0x80324000 + b start of static pagetables
 
; 0x803FFFFF <- no direct address translation beyond this point
; =============================================================
 
; 0x805FF000 -> 5FFF80 TSS
; 0x80600000 -> 601FFF i/o maps
 
; 0x80800000 -> kernel heap
; 0x80FFFFFF heap min limit
; 0xFDBFFFFF heap max limit
 
; 0xF0000000 -> 0xF1FFFFFF PCI-express extended config space
; 0xFDC00000 -> 0xFDFFFFFF page tables 4Mb
; 0xFE000000 -> 0xFFFFFFFF LFB 32Mb
; 0xFE000000 -> 0xFE7FFFFF application available LFB 8Mb
; 0xFE800000 -> 0xFFFFFFFF kernel LFB part 24 Mb
 
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/dev_fd.inc
0,0 → 1,38
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
;***************************************************
; clear the DRIVE_DATA table,
; search for FDDs and add them into the table
; author - Mario79
;***************************************************
xor eax, eax
mov edi, DRIVE_DATA
mov ecx, DRIVE_DATA_SIZE/4
cld
rep stosd
 
mov al, 0x10
out 0x70, al
mov cx, 0xff
wait_cmos:
dec cx
test cx, cx
jnz wait_cmos
in al, 0x71
mov [DRIVE_DATA], al
test al, al
jz @f
 
stdcall attach_int_handler, 6, FDCInterrupt, 0
DEBUGF 1, "K : Set IDE IRQ6 return code %x\n", eax
call floppy_init
@@:
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/dev_hdcd.inc
0,0 → 1,475
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; HDD and CD search
 
cmp [ecx+IDE_DATA.ProgrammingInterface], 0
je EndFindHDD
FindHDD:
xor ebx, ebx
inc ebx
mov [DeviceNumber], 0
cmp ecx, IDE_controller_1
jz .find
add bl, 5
add [DeviceNumber], sizeof.HD_DATA*4
cmp ecx, IDE_controller_2
jz .find
add bl, 5
add [DeviceNumber], sizeof.HD_DATA*4
.find:
mov [ChannelNumber], 1
mov [DiskNumber], 0
call FindHDD_1
inc [DiskNumber]
call FindHDD_2
inc [ChannelNumber]
dec [DiskNumber]
call FindHDD_2
inc [DiskNumber]
call FindHDD_2
jmp EndFindHDD
;-----------------------------------------------------------------------------
FindHDD_2:
add [DeviceNumber], sizeof.HD_DATA
shl byte [ebx+DRIVE_DATA], 2
FindHDD_1:
DEBUGF 1, "K : Channel %d ",[ChannelNumber]:1
DEBUGF 1, "Disk %d\n",[DiskNumber]:1
push ecx ebx
call ReadHDD_ID
cmp [DevErrorCode], 7
je .end
cmp [DevErrorCode], 0
jne .FindCD
cmp [Sector512+6], word 16
ja .FindCD
cmp [Sector512+12], word 255
ja .FindCD
pop ebx
movzx eax, [DeviceNumber]
mov ecx, [Sector512+120]
mov dword[eax+hd0_data.sectors], ecx
and dword[eax+hd0_data.sectors+4], 0
bt word [Sector512+166], 10
jnc .Print_Device_Name
mov [eax+hd0_data.hd48], 1
mov ecx, [Sector512+200]
mov dword[eax+hd0_data.sectors], ecx
mov ecx, [Sector512+204]
mov dword[eax+hd0_data.sectors+4], ecx
jmp .Print_Device_Name
;--------------------------------------
.FindCD:
call DeviceReset
cmp [DevErrorCode], 0
jne .end
call ReadCD_ID
cmp [DevErrorCode], 0
jne .end
pop ebx
inc byte [ebx+DRIVE_DATA]
;--------------------------------------
.Print_Device_Name:
inc byte [ebx+DRIVE_DATA]
pop ecx
pushad
movzx ebx, [ChannelNumber]
dec ebx
shl ebx, 1
add bl, [DiskNumber]
shl ebx, 1
call calculate_IDE_device_values_storage
;--------------------------------------
.copy_dev_name:
mov esi, Sector512+27*2
mov edi, dev_name
mov ecx, 20
cld
;--------------------------------------
@@:
lodsw
xchg ah, al
stosw
loop @b
DEBUGF 1, "K : Dev: %s \n", dev_name
xor eax, eax
mov ax, [Sector512+64*2]
DEBUGF 1, "K : PIO possible modes %x\n", al
mov ax, [Sector512+51*2]
mov al, ah
call convert_Sector512_value
DEBUGF 1, "K : PIO set mode %x\n", ah
mov ax, [Sector512+63*2]
DEBUGF 1, "K : Multiword DMA possible modes %x\n", al
mov al, ah
call convert_Sector512_value
DEBUGF 1, "K : Multiword DMA set mode %x\n", ah
mov ax, [Sector512+88*2]
DEBUGF 1, "K : Ultra DMA possible modes %x\n", al
mov [ebx+IDE_DEVICE.UDMA_possible_modes], al
mov al, ah
call convert_Sector512_value
DEBUGF 1, "K : Ultra DMA set mode %x\n", ah
mov [ebx+IDE_DEVICE.UDMA_set_mode], ah
popad
ret
 
.end:
DEBUGF 1, "K : Device not found\n"
pop ebx ecx
ret
;-----------------------------------------------------------------------------
calculate_IDE_device_values_storage:
cmp ecx, IDE_controller_1
jne @f
 
add ebx, IDE_device_1
jmp .exit
;--------------------------------------
@@:
cmp ecx, IDE_controller_2
jne @f
 
add ebx, IDE_device_2
jmp .exit
;--------------------------------------
@@:
add ebx, IDE_device_3
;--------------------------------------
.exit:
ret
;-----------------------------------------------------------------------------
convert_Sector512_value:
mov ecx, 8
xor ah, ah
;--------------------------------------
@@:
test al, 1b
jnz .end
 
shr al, 1
inc ah
loop @b
 
xor ah, ah
;--------------------------------------
.end:
ret
;-----------------------------------------------------------------------------
; Address of reading sector in LBA mode
uglobal
SectorAddress dd ?
dev_name:
rb 41
endg
;-----------------------------------------------------------------------------
;*************************************************
;* READING THE HARD DISK IDENTIFIER *
;* Input parameters are passed through the global*
;* variables: *
;* ChannelNumber - channel number (1 or 2); *
;* DiskNumber - disk number on channel (0 or 1) *
;* Block of identificational data is reading *
;* to Sector512 array. *
;*************************************************
ReadHDD_ID:
; set up CHS mode
mov [ATAAddressMode], 0
; send device identification command
mov [ATAFeatures], 0
mov [ATAHead], 0
mov [ATACommand], 0xEC
call SendCommandToHDD
cmp [DevErrorCode], 0 ; check the error code
jne @@End ; finish, saving the error code
 
mov dx, [ATABasePortAddr]
add dx, 7 ; address of state register
mov ecx, 0xffff
@@WaitCompleet:
; Check command execution time
dec ecx
jz @@Error1 ; timeout error
; Check if ready or not
in al, dx
test al, 80h ; BSY signal state
jnz @@WaitCompleet
 
test al, 1 ; ERR signal state
jnz @@Error6
 
test al, 08h ; DRQ signal state
jz @@WaitCompleet
; Receive data block from controller
mov edi, Sector512
mov dx, [ATABasePortAddr]; data register
mov cx, 256 ; number of word to receive
rep insw ; receive data block
ret
; write the error code
@@Error1:
mov [DevErrorCode], 1
ret
@@Error6:
mov [DevErrorCode], 6
@@End:
ret
;-----------------------------------------------------------------------------
uglobal
; Standart base addresses of channels 1 or 2
StandardATABases dw ?, ? ; 1F0h, 170h
; Channel number
ChannelNumber db ?
; Disk number
DiskNumber db ?
DeviceNumber db ?
; Base address of ATA controller's port group
ATABasePortAddr dw ?
; ATA-command parameters
ATAFeatures db ? ; features
ATASectorCount db ? ; count of processing sectors
ATASectorNumber db ? ; initial sector number
ATACylinder dw ? ; initial cylinder number
ATAHead db ? ; initial head number
ATAAddressMode db ? ; addressing mode (0 - CHS, 1 - LBA)
ATACommand db ? ; executing command number
; Error code (0 - no errors, 1 - waiting time limit exceed
; 2 - incorrect code of addressing mode,
; 3 - incorrect channel number, 4 - incorrect disk number,
; 5 - incorrect head number, 6 - command execution error,
; 7 - time out when choosing channel)
DevErrorCode dd ?
endg
;-----------------------------------------------------------------------------
;****************************************************
;* SEND COMMAND TO GIVEN DISK *
;* Input parameters are passed through the global *
;* variables: *
;* ChannelNumber - channel number (1 or 2); *
;* DiskNumber - disk number (0 or 1); *
;* ATAFeatures - "features"; *
;* ATASectorCount - sector count; *
;* ATASectorNumber - initial sector number; *
;* ATACylinder - initial cylinder number; *
;* ATAHead - initial head number; *
;* ATAAddressMode - addressing mode (0-CHS, 1-LBA); *
;* ATACommand - command code. *
;* If the function finished successfully: *
;* in ATABasePortAddr - base address of HDD; *
;* in DevErrorCode - zero. *
;* If error has occured then in DevErrorCode will *
;* be the error code. *
;****************************************************
SendCommandToHDD:
; Check the addressing mode code
cmp [ATAAddressMode], 1
ja @@Err2
; Check the channel number correctness
movzx ebx, [ChannelNumber]
dec ebx
cmp ebx, 1
ja @@Err3
; Set the base address
shl ebx, 1
mov ax, [ebx+StandardATABases]
mov [ATABasePortAddr], ax
; Waiting for HDD ready to receive a command
; Choose desired disk
mov dx, [ATABasePortAddr]
add dx, 6 ; address of the heads register
mov al, [DiskNumber]
cmp al, 1 ; check the disk number
ja @@Err4
 
shl al, 4
or al, 10100000b
out dx, al
; Waiting for disk ready
inc dx
mov ecx, 0xfff
@@WaitHDReady:
; Check waiting time
dec ecx
jz @@Err1
; Read the state register
in al, dx
; Check the state of BSY signal
test al, 80h
jnz @@WaitHDReady
; Check the state of DRQ signal
test al, 08h
jnz @@WaitHDReady
; load command to controller's registers
cli
mov dx, [ATABasePortAddr]
inc dx ; "features" register
mov al, [ATAFeatures]
out dx, AL
inc dx ; sector counter
mov al, [ATASectorCount]
out dx, AL
inc dx ; sector number register
mov al, [ATASectorNumber]
out dx, AL
inc dx ; cylinder number (low byte)
mov ax, [ATACylinder]
out dx, AL
inc dx ; cylinder number (high byte)
mov al, AH
out dx, AL
inc dx ; head number / disk number
mov al, [DiskNumber]
shl al, 4
cmp [ATAHead], 0xF ; check head number
ja @@Err5
 
or al, [ATAHead]
or al, 10100000b
mov ah, [ATAAddressMode]
shl ah, 6
or al, ah
out dx, al
; Send command
mov al, [ATACommand]
inc dx ; command register
out dx, al
sti
; reset the error sign
mov [DevErrorCode], 0
ret
; write error code
@@Err1:
mov [DevErrorCode], 7
ret
@@Err2:
mov [DevErrorCode], 2
ret
@@Err3:
mov [DevErrorCode], 3
ret
@@Err4:
mov [DevErrorCode], 4
ret
@@Err5:
mov [DevErrorCode], 5
; finish work
ret
;-----------------------------------------------------------------------------
;*************************************************
;* READ ATAPI DEVICE IDENTIFIER *
;* Input parameters are passed through the global*
;* variables: *
;* ChannelNumber - channel number; *
;* DiskNumber - disk number on channel. *
;* Block of identificational data is reading *
;* to Sector512 array. * *
;*************************************************
ReadCD_ID:
; Set CHS mode
mov [ATAAddressMode], 0
; Send command for device identification
mov [ATAFeatures], 0
mov [ATASectorCount], 0
mov [ATASectorNumber], 0
mov [ATACylinder], 0
mov [ATAHead], 0
mov [ATACommand], 0xA1
call SendCommandToHDD
cmp [DevErrorCode], 0 ; check the error code
jne @@End_1 ; finish, saving the error code
; Wait for HDD data ready
mov dx, [ATABasePortAddr]
add dx, 7 ; port 1х7h
mov ecx, 0xffff
@@WaitCompleet_1:
; Check time
dec ecx
jz @@Error1_1 ; time out error
; Check readyness
in al, dx
test al, 80h ; BSY signal state
jnz @@WaitCompleet_1
 
test al, 1 ; ERR signal state
jnz @@Error6_1
 
test al, 08h ; DRQ signal state
jz @@WaitCompleet_1
; Receive data block from controller
mov edi, Sector512 ; offset Sector512
mov dx, [ATABasePortAddr] ; port 1x0h
mov cx, 256 ; words read count
rep insw
ret
; write the error code
@@Error1_1:
mov [DevErrorCode], 1
ret
@@Error6_1:
mov [DevErrorCode], 6
@@End_1:
ret
;-----------------------------------------------------------------------------
;*************************************************
;* DEVICE RESET *
;* Input parameters are passed through the global*
;* variables: *
;* ChannelNumber - channel number (1 or 2); *
;* DiskNumber - disk number (0 or 1). *
;*************************************************
DeviceReset:
; Check the channel number correctness
movzx ebx, [ChannelNumber]
dec ebx
cmp ebx, 1
ja @@Err3_2
; Set base address
shl ebx, 1
mov dx, [ebx+StandardATABases]
mov [ATABasePortAddr], dx
; Choose desired disk
add dx, 6 ; address of heads register
mov al, [DiskNumber]
cmp al, 1 ; check disk number
ja @@Err4_2
 
shl al, 4
or al, 10100000b
out dx, al
; Send the "Reset" command
mov al, 0x8
inc dx ; command register
out dx, al
mov ecx, 0x80000
@@WaitHDReady_1:
; Check waiting time
dec ecx
je @@Err1_2 ; time out error
; read the state register
in al, dx
; Check the state of BSY signal
test al, 80h
jnz @@WaitHDReady_1
; reset the error sign
mov [DevErrorCode], 0
ret
; error processing
@@Err1_2:
mov [DevErrorCode], 1
ret
@@Err3_2:
mov [DevErrorCode], 3
ret
@@Err4_2:
mov [DevErrorCode], 4
; write error code
ret
;-----------------------------------------------------------------------------
EndFindHDD:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/biosdisk.inc
0,0 → 1,122
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2008-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
; Detect all BIOS hard drives.
; diamond, 2008
; Do not include USB mass storages. CleverMouse, 2013
; Read the number of sectors, bytes per sector. dunkaist, 2017
 
xor cx, cx
mov es, cx
mov di, BOOT_LO.bios_hd
mov byte [es:di-1], cl
cmp [preboot_biosdisk], 1
jnz bdde
mov dl, 80h
bdds:
mov ah, 15h
push cx dx di
int 13h
pop di dx cx
jc bddc
test ah, ah
jz bddc
inc cx
; We are going to call int 13h/func 48h, Extended get drive parameters.
; The latest version of the EDD specification is 3.0.
; There are two slightly incompatible variants for version 3.0;
; original one from Phoenix in 1998, see e.g.
; http://www.t10.org/t13/technical/d98120r0.pdf, and T13 draft,
; http://www.t13.org/documents/UploadedDocuments/docs2004/d1572r3-EDD3.pdf
; T13 draft addresses more possible buses, so it gives additional 8 bytes
; for device path.
; Most BIOSes follow Phoenix, but T13 version is also known to be used
; (e.g. systems based on AMD Geode).
; Fortunately, there is an in/out length field, so
; it is easy to tell what variant was selected by the BIOS:
; Phoenix-3.0 has 42h bytes, T13-3.0 has 4Ah bytes.
; Note that 2.0 has 1Eh bytes, 1.1 has 1Ah bytes; both variants of 3.0 have
; the same structure for first 1Eh bytes, compatible with previous versions.
; Note also that difference between Phoenix-3.0 and T13-3.0 starts near the
; end of the structure, so the current code doesn't even need to distinguish.
; It needs, however, give at least 4Ah bytes as input and expect that BIOS
; could return 42h bytes as output while still giving all the information.
mov ah, 48h
push ds
push es
pop ds
mov si, 0xA000
mov word [si], 4Ah
mov ah, 48h
int 13h
pop ds
jc bddc2
cmp word [es:si], 1Eh
jb .noide
cmp word [es:si+1Ah], 0xFFFF
jz .noide
inc byte [es:BOOT_LO.bios_hd_cnt]
mov al, dl
stosb
push ds
push si
lds si, [es:si+1Ah]
mov al, [si+6]
and al, 0xF
stosb
mov al, byte [si+4]
shr al, 4
and ax, 1
cmp word [si], 1F0h
jz @f
inc ax
inc ax
cmp word [si], 170h
jz @f
or ax, -1
; mov ax, -1
@@:
stosw
pop si
pop ds
jmp bddc3
.noide:
cmp word [es:si], 42h
jb .nousb
cmp word [es:si+28h], 'US'
jnz .nousb
cmp byte [es:si+2Ah], 'B'
jz bddc2
.nousb:
inc byte [es:BOOT_LO.bios_hd_cnt]
mov al, dl
stosb
xor ax, ax
stosb
dec ax
stosw
; mov al, 0
; stosb
; mov ax, -1
; stosw
bddc3:
movzx eax, word[es:si+24]
stosd
mov eax, [es:si+16]
stosd
mov eax, [es:si+20]
stosd
bddc2:
cmp cl, [es:0x475]
jae bdde
bddc:
inc dl
jnz bdds
bdde:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/biosmem.inc
0,0 → 1,46
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2009-2017. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
; Query physical memory map from BIOS.
; diamond, 2009
 
push ds
; first call to fn E820
mov eax, 0xE820
xor ebx, ebx
mov es, bx
mov ds, bx
mov di, BOOT_LO.memmap_blocks
mov [BOOT_LO.memmap_block_cnt], ebx ; no blocks yet
mov ecx, 20
mov edx, 'PAMS' ; 'SMAP'
int 15h
jc no_E820
cmp eax, 'PAMS'
jnz no_E820
e820_mem_loop:
; cmp byte [di+16], 1 ; ignore non-free areas
; jnz e820_mem_next
inc byte [BOOT_LO.memmap_block_cnt]
add di, sizeof.e820entry
e820_mem_next:
; consequent calls to fn E820
test ebx, ebx
jz e820_test_done
cmp byte [BOOT_LO.memmap_block_cnt], MAX_MEMMAP_BLOCKS
jz e820_test_done
mov eax, 0xE820
int 15h
jc e820_test_done
jmp e820_mem_loop
no_E820:
; let's hope for mem_test from init.inc
e820_test_done:
pop ds
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/vortex86.inc
0,0 → 1,158
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
; 20/11/2013 yogev_ezra: Initial version (Vortex86 SoC type detection)
; 26/11/2013 yogev_ezra: Added CPU speed modifier and MMX support flag detection
; Thanks for help to: dunkaist, eAndrew, hidnplayr, Mario
 
$Revision$
 
VORTEX86DEBUG = 0 ; For testing in emulators and in non-Vortex86 CPU computers, set this to 1
VORTEX86DEBUGVALUE = 'DMP5' ; FAKE port output = used for testing
NORTH_BRIDGE = 0x80000000 ; Base address of Vortex86 PCI North Bridge
SOUTH_BRIDGE = 0x80003800 ; Base address of Vortex86 PCI South Bridge
 
; Detect Vortex86 CPU and generate CPU name in string format (PCI address at 93H~90H in Vortex86 North Bridge contains SoC type)
; Available Vortex86 CPU codes taken from Coreboot project. New codes should be added to "Vortex86SoClist" below
; #define DMP_CPUID_SX 0x31504d44 ("DMP1")
; #define DMP_CPUID_DX 0x32504d44 ("DMP2")
; #define DMP_CPUID_MX 0x33504d44 ("DMP3")
; #define DMP_CPUID_DX2 0x34504d44 ("DMP4")
; #define DMP_CPUID_MX_PLUS 0x35504d44 ("DMP5")
; #define DMP_CPUID_EX 0x37504d44 ("DMP7")
 
iglobal
Vortex86CPUcode dd ? ; Vortex86 CPU code in HEX format (4 bytes), can be shown as string if converted to ASCII characters
Vortex86CPUid db 0 ; Vortex86 CPU id in integer format (1=Vortex86SX, 2=Vortex86DX, ...)
Vortex86SoCname db 'Vortex86 ',0 ; This variable will hold the full name of Vortex86 SoC
Vortex86SoClist: ; List of Vortex86 CPUs known today. Add new record to this list when new CPU becomes available
db 0x31, 'SX ' ; id=1
db 0x32, 'DX ' ; id=2
db 0x33, 'MX ' ; id=3 MMX is available starting from CPU code 'MX' (id=3)
db 0x34, 'DX2' ; id=4
db 0x35, 'MX+' ; id=5
db 0x37, 'EX ' ; id=7
Vortex86SoCnum = ($ - Vortex86SoClist) / 4 ; Calculate the total number of known Vortex86 CPUs
endg
 
; When in debug mode, perform SoC detection regardless of the actual CPU vendor (even for vendors other than DMP)
; When in normal (not debug) mode, check the CPU vendor first, and perform SoC detection only if vendor is 'Vortex86 SoC'
if ~ VORTEX86DEBUG
cmp [cpu_vendor], 'Vort'
jnz .Vortex86end ; If the CPU vendor is not 'Vortex86 SoC', skip the SoC detection
end if
 
mov eax, NORTH_BRIDGE+0x90 ; 0x80000090 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
call .Vortex86PCIreg ; Get the CPU code from Vortex86 SoC North Bridge PCI register (Register Offset: 93H~90H)
 
if VORTEX86DEBUG ; When in debug mode, pretend that we received port output equal to "VORTEX86DEBUGVALUE"
mov eax, VORTEX86DEBUGVALUE
end if
DEBUGF 1, "K : Vortex86 SoC type register (93H~90H) returned 0x"
test eax, eax ; Check whether the port output was '\0'
jz .nullPCIoutput ; In case the result is '\0' (NULL), skip further testing and exit
mov [Vortex86CPUcode], eax ; Save HEX CPU code to Vortex86CPUcode (so it can be used later)
DEBUGF 1, "%x (%s): ", eax, Vortex86CPUcode ; Print the CPU code (as HEX and as string) to debug log
 
mov ebx, 0x444d5000 ; Apply Vortex86 CPU code mask (all Vortex86 SoC have ID in form of "0xNN504d44")
bswap eax ; Assumed it is Vortex86 SoC, the highest byte identifies the exact CPU, so move it to the lowest byte
mov bl, al ; Copy SoC type to BL since EAX (that includes AL) is used implicitly in "LODSD" command below
cmp eax, ebx ; Now see whether the 3 higher bytes were "0x504d44" (which means it's Vortex86)
jnz .notVortex86 ; If it's not Vortex86 - go say so and exit
 
sub al, 0x30 ; Current Vortex86 CPU codes are in the range of 31h-37h, so convert them to integer (1,2,...)
mov [Vortex86CPUid], al ; Save the CPUid (1=Vortex86SX, 2=Vortex86DX, ..., 7=Vortex86EX, ...)
mov esi, Vortex86SoClist ; ESI points to the start of Vortex86SoClist (used implicitly in "LODSD" command below)
xor ecx, ecx ; Zero ECX (it is used as counter)
cld ; Clears the DF flag in the EFLAGS register (DF=0 --> String operations increment ESI)
@@:
inc ecx ; Increment our counter
cmp ecx, Vortex86SoCnum ; Check if we iterated Vortex86SoCnum times already (i.e. went over the entire Vortex86SoClist)
ja .unknownVortex86 ; If the entire list was tested and our CPU is not in that list, it is unknown Vortex86 SoC
lodsd ; Load DWORD at address DS:ESI into EAX (puts 1 line from Vortex86SoClist into EAX, then increments ESI)
cmp bl, al ; Check if our CPU matches the current record in the list
jne @b ; No match --> repeat with next record
 
shr eax, 8 ; Match found --> drop the SoC type code from Vortex86SoClist name and replace it with \0
mov dword [Vortex86SoCname+8], eax ; Concatenate it with prefix to receive complete SoC name (\0 is string termination)
 
DEBUGF 1, "%s (id=%d)\n", Vortex86SoCname, [Vortex86CPUid]:1 ; Say what we have found (CPU name and id)
jmp .Vortex86
 
.notVortex86: ; In case this register is used by other CPUs for other purpose, it's interesting what it contains
DEBUGF 1, "not a Vortex86 CPU\n"
jmp .Vortex86end
 
.unknownVortex86: ; It is Vortex86 CPU, but it's not in the list above
DEBUGF 1, "unknown Vortex86 CPU (id=%d)\n", [Vortex86CPUid]:1 ; Inform the user that the CPU is Vortex86 but name is unknown
 
.Vortex86:
mov eax, NORTH_BRIDGE+0x60 ; 0x80000060 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
call .Vortex86PCIreg ; Get current flags of Vortex86SoC North Bridge STRAP Register (Register Offset: 63h~60h)
DEBUGF 1, "K : Vortex86 STRAP Register (63h~60h) returned 0x%x\n",eax
 
mov eax, SOUTH_BRIDGE+0xC0 ; 0x800038C0 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
call .Vortex86PCIreg ; Flags of Vortex86 South Bridge Internal Peripheral Feature Control Register (Register Offset: C3h~C0h)
DEBUGF 1, "K : Vortex86 Internal Peripheral Feature Control Register (C3h~C0h) returned 0x%x\n",eax
 
mov eax, SOUTH_BRIDGE+0xCC ; 0x800038CC = PCI Configuration Address Register to read from (8-bit register - accessed as BYTE)
call .Vortex86PCIreg ; Flags of Vortex86 South Bridge Internal Peripheral Feature Control Register III (Register Offset: CCh)
DEBUGF 1, "K : Vortex86 Internal Peripheral Feature Control Register III (CCh) returned 0x%x\n",al
mov eax, NORTH_BRIDGE+0xA0 ; 0x800000A0 = PCI Configuration Address Register to read from (32-bit register - accessed as DWORD)
call .Vortex86PCIreg ; Get current flags of Vortex86SoC North Bridge Host Control Register (Register Offset: A3h~A0h)
DEBUGF 1, "K : Vortex86 Host Control Register (A3h~A0h) returned 0x%x: CPU speed is ",eax
mov bl, al ; The lower byte of Vortex86 Host Control Register contains CPU speed modifier and MMX support status
mov bh, al ; Backup the current AL value, so later we can test whether the value has changed
and bl, 00000111b ; CPU speed modifier is stored in bits 0-2. Value=0 means MAX speed, other values - speed reduction
jz .Vortex86CPUspeedMAX ; 0s in bits 0-2: CPU is at MAX speed (no need to modify)
inc ebx ; The actual value is 1 less than 'Divide by' setting (value '001' means 'Divide by 2', etc.)
DEBUGF 1, "reduced (divide by %d).\nK : Vortex86 changing CPU speed to ", bl ; Print the current CPU speed modifier to the log
and al, 11111000b ; At least one of the bits 0-2 contains 1: CPU is at reduced speed. Set bits 0-2 to 0s to change to MAX
.Vortex86CPUspeedMAX:
DEBUGF 1, "MAX\n" ; Now the CPU should be running at MAX speed (don't write the value to PCI port yet)
 
cmp [Vortex86CPUid], 3 ; MMX is available starting from CPU code 'MX' (id=3)
jb .skipVortex86MMX ; No MMX support - skip MMX support status detection (for id=1,2)
DEBUGF 1, "K : Vortex86 MMX support status: MMX is " ; Bits 5-6 in Host Control Register contain MMX status
test al, 100000b ; On MMX-capable Vortex86 SoC, Bit5 = is MMX enabled? (1=Yes/0=No)
jnz .Vortex86MMXenabled ; MMX is already enabled (Bit5=1)
DEBUGF 1, "DISABLED - enabling it for this session\n" ; Print to the log that MMX is disabled
or al, 100000b ; Enable MMX support (don't write the value to PCI port yet)
jmp .AfterMMXenabled
.Vortex86MMXenabled:
DEBUGF 1, "ENABLED\n" ; Print to the log that MMX is enabled
.AfterMMXenabled:
DEBUGF 1, "K : Vortex86 MMX report to CPUID: " ; Print to the log what CPUID command knowns about MMX support
test al, 1000000b ; On MMX-capable Vortex86 SoC, Bit6 = report MMX support to CPUID? (1=Yes/0=No)
jnz .Vortex86MMXreported ; MMX is already reported to CPUID (Bit6=1)
DEBUGF 1, "OFF - turning it ON for this session\n" ; Print to the log that MMX will now be reported to CPUID
or al, 1000000b ; Turn on MMX reporting to CPUID (don't write the value to PCI port yet)
jmp .skipVortex86MMX
.Vortex86MMXreported:
DEBUGF 1, "ON\n" ; Print to the log that MMX reporting to CPUID is enabled
 
.skipVortex86MMX:
cmp bh, al ; Check whether AL has changed before (if it did, we need to write it back to PCI port)
jz .Vortex86end ; No change - no need to write to the port
out dx, al ; Write the changed data to PCI port
DEBUGF 1, "K : Vortex86 Host Control Register (A3h~A0h) new value is 0x%x\n",eax
jmp .Vortex86end
 
.Vortex86PCIreg: ; Procedure receives input register value in EAX, and returns the output value also in EAX
mov dx, 0xcf8 ; CF8h = Vortex86 PCI Configuration Address port
out dx, eax ; Send request to PCI address port to retrieve data from this address
mov dl, 0xfc ; CFCh = Vortex86 PCI Configuration Data port
in eax, dx ; Read data from PCI data port
ret
.nullPCIoutput: ; Emulators and non-Vortex86 CPU computers will usually return \0 in this register
DEBUGF 1, "0 (NULL)\n"
 
.Vortex86end:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/sear_par.inc
0,0 → 1,280
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
search_partitions:
push ecx
; 1. Fill missing parameters in HD_DATA structures.
xor eax, eax
mov edx, IDE_controller_1
mov ax, [edx + IDE_DATA.BAR0_val]
mov [hd0_data.hdbase], ax
mov [hd1_data.hdbase], ax
mov ax, [edx + IDE_DATA.BAR2_val]
mov [hd2_data.hdbase], ax
mov [hd3_data.hdbase], ax
 
mov edx, IDE_controller_2
mov ax, [edx + IDE_DATA.BAR0_val]
mov [hd4_data.hdbase], ax
mov [hd5_data.hdbase], ax
mov ax, [edx + IDE_DATA.BAR2_val]
mov [hd6_data.hdbase], ax
mov [hd7_data.hdbase], ax
 
mov edx, IDE_controller_3
mov ax, [edx + IDE_DATA.BAR0_val]
mov [hd8_data.hdbase], ax
mov [hd9_data.hdbase], ax
mov ax, [edx + IDE_DATA.BAR2_val]
mov [hd10_data.hdbase], ax
mov [hd11_data.hdbase], ax
; 2. Notify the system about /hd* disks.
; For every existing disk, call ide_disk_add with correct parameters.
; Generate name "hdN" on the stack; this is 4 bytes including terminating zero.
;-----------------------------------------------------------------------------
; 2a. /hd0: exists if mask 0x40 in [DRIVE_DATA+1] is set,
; data: hd0_data,
; number of partitions: [DRIVE_DATA+2]
test [DRIVE_DATA+1], byte 0x40
jz @f
 
push 'hd0'
mov eax, esp ; name
mov edx, hd0_data
call ide_disk_add
mov [DRIVE_DATA+2], al
pop ecx ; restore the stack
;-----------------------------------------------------------------------------
@@:
; 2b. /hd1: exists if mask 0x10 in [DRIVE_DATA+1] is set,
; data: hd1_data,
; number of partitions: [DRIVE_DATA+3]
test [DRIVE_DATA+1], byte 0x10
jz @f
 
push 'hd1'
mov eax, esp
mov edx, hd1_data
call ide_disk_add
mov [DRIVE_DATA+3], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2c. /hd2: exists if mask 4 in [DRIVE_DATA+1] is set,
; data: hd2_data,
; number of partitions: [DRIVE_DATA+4]
test [DRIVE_DATA+1], byte 4
jz @f
 
push 'hd2'
mov eax, esp
mov edx, hd2_data
call ide_disk_add
mov [DRIVE_DATA+4], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2d. /hd3: exists if mask 1 in [DRIVE_DATA+1] is set,
; data: hd3_data,
; number of partitions: [DRIVE_DATA+5]
test [DRIVE_DATA+1], byte 1
jz @f
 
push 'hd3'
mov eax, esp
mov edx, hd3_data
call ide_disk_add
mov [DRIVE_DATA+5], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2e. /hd4: exists if mask 0x40 in [DRIVE_DATA+6] is set,
; data: hd4_data,
; number of partitions: [DRIVE_DATA+7]
test [DRIVE_DATA+6], byte 0x40
jz @f
 
push 'hd4'
mov eax, esp ; name
mov edx, hd4_data
call ide_disk_add
mov [DRIVE_DATA+7], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2f. /hd5: exists if mask 0x10 in [DRIVE_DATA+6] is set,
; data: hd5_data,
; number of partitions: [DRIVE_DATA+8]
test [DRIVE_DATA+6], byte 0x10
jz @f
 
push 'hd5'
mov eax, esp
mov edx, hd5_data
call ide_disk_add
mov [DRIVE_DATA+8], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2g. /hd6: exists if mask 4 in [DRIVE_DATA+6] is set,
; data: hd6_data,
; number of partitions: [DRIVE_DATA+9]
test [DRIVE_DATA+6], byte 4
jz @f
 
push 'hd6'
mov eax, esp
mov edx, hd6_data
call ide_disk_add
mov [DRIVE_DATA+9], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2h. /hd7: exists if mask 1 in [DRIVE_DATA+6] is set,
; data: hd7_data,
; number of partitions: [DRIVE_DATA+10]
test [DRIVE_DATA+6], byte 1
jz @f
 
push 'hd7'
mov eax, esp
mov edx, hd7_data
call ide_disk_add
mov [DRIVE_DATA+10], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2i. /hd8: exists if mask 0x40 in [DRIVE_DATA+11] is set,
; data: hd8_data,
; number of partitions: [DRIVE_DATA+12]
test [DRIVE_DATA+11], byte 0x40
jz @f
 
push 'hd8'
mov eax, esp ; name
mov edx, hd8_data
call ide_disk_add
mov [DRIVE_DATA+12], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2j. /hd9: exists if mask 0x10 in [DRIVE_DATA+11] is set,
; data: hd9_data,
; number of partitions: [DRIVE_DATA+13]
test [DRIVE_DATA+11], byte 0x10
jz @f
 
push 'hd9'
mov eax, esp
mov edx, hd9_data
call ide_disk_add
mov [DRIVE_DATA+13], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2k. /hd10: exists if mask 4 in [DRIVE_DATA+11] is set,
; data: hd10_data,
; number of partitions: [DRIVE_DATA+14]
test [DRIVE_DATA+14], byte 4
jz @f
 
push 'hd10'
mov eax, esp
mov edx, hd10_data
call ide_disk_add
mov [DRIVE_DATA+9], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 2l. /hd11: exists if mask 1 in [DRIVE_DATA+11] is set,
; data: hd11_data,
; number of partitions: [DRIVE_DATA+15]
test [DRIVE_DATA+11], byte 1
jz @f
 
push 'hd11'
mov eax, esp
mov edx, hd11_data
call ide_disk_add
mov [DRIVE_DATA+15], al
pop ecx
;-----------------------------------------------------------------------------
@@:
; 3. Notify the system about /bd* disks.
; 3a. Check whether there are BIOS disks. If no, skip step 3.
xor esi, esi
cmp esi, [NumBiosDisks]
jz .nobd
; Loop over all disks.
push 0
push 'bd'
.bdloop:
; 3b. Get the drive number for using in /bd* name.
lea eax, [esi*4]
movzx eax, [BiosDisksData+eax*4+BiosDiskData.DriveNumber]
sub al, 80h
; 3c. Convert eax to decimal and store starting with [esp+3].
; First 2 bytes in [esp] are "bd".
lea edi, [esp+2]
; store digits in the stack, ending with -'0'
push -'0'
@@:
xor edx, edx
iglobal
align 4
_10 dd 10
endg
div [_10]
push edx
test eax, eax
jnz @b
; restore digits from the stack, this reverses the order;
; add '0', stop, when zero is reached
@@:
pop eax
add al, '0'
stosb
jnz @b
; 3e. Call the API with userdata = 80h + ecx.
mov eax, esp
lea edx, [esi+80h]
stdcall disk_add, bd_callbacks, eax, edx, 0
test eax, eax
jz @f
stdcall disk_media_changed, eax, 1
@@:
; 3f. Continue the loop.
inc esi
cmp esi, [NumBiosDisks]
jnz .bdloop
pop ecx ecx ; restore stack after name
.nobd:
jmp end_search_partitions
;-----------------------------------------------------------------------------
; Helper procedure for search_partitions, adds one IDE disk.
; For compatibility, number of partitions for IDE disks is kept in a separate
; variable, so the procedure returns number of partitions.
; eax -> name, edx -> disk data
proc ide_disk_add
stdcall disk_add, ide_callbacks, eax, edx, 0
test eax, eax
jz @f
push eax
stdcall disk_media_changed, eax, 1
pop eax
mov eax, [eax+DISK.NumPartitions]
cmp eax, 255
jbe @f
mov eax, 255
@@:
ret
endp
;-----------------------------------------------------------------------------
end_search_partitions:
pop ecx
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/init_ata.inc
0,0 → 1,492
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2014-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
;-----------------------------------------------------------------------------
; find the IDE controller in the device list
;-----------------------------------------------------------------------------
mov ecx, IDE_controller_1
mov esi, pcidev_list
;--------------------------------------
align 4
.loop:
mov esi, [esi+PCIDEV.fd]
cmp esi, pcidev_list
jz find_IDE_controller_done
 
mov eax, [esi+PCIDEV.class]
; shr eax, 4
; cmp eax, 0x01018
shr eax, 7
cmp eax, 0x010180 shr 7
jnz .loop
;--------------------------------------
.found:
mov eax, [esi+PCIDEV.class]
DEBUGF 1, 'K : IDE controller programming interface %x\n', eax
mov [ecx+IDE_DATA.ProgrammingInterface], eax
mov [ecx+IDE_DATA.pcidev], esi
 
mov ah, [esi+PCIDEV.bus]
mov al, 2
mov bh, [esi+PCIDEV.devfn]
;--------------------------------------
mov dx, 0x1F0
test byte [esi+PCIDEV.class], 1
jz @f
mov bl, 0x10
push eax
call pci_read_reg
and eax, 0xFFFC
mov edx, eax
pop eax
@@:
DEBUGF 1, 'K : BAR0 IDE base addr %x\n', dx
mov [StandardATABases], dx
mov [ecx+IDE_DATA.BAR0_val], dx
;--------------------------------------
mov dx, 0x3F4
test byte [esi+PCIDEV.class], 1
jz @f
mov bl, 0x14
push eax
call pci_read_reg
and eax, 0xFFFC
mov edx, eax
pop eax
@@:
DEBUGF 1, 'K : BAR1 IDE base addr %x\n', dx
mov [ecx+IDE_DATA.BAR1_val], dx
;--------------------------------------
mov dx, 0x170
test byte [esi+PCIDEV.class], 4
jz @f
mov bl, 0x18
push eax
call pci_read_reg
and eax, 0xFFFC
mov edx, eax
pop eax
@@:
DEBUGF 1, 'K : BAR2 IDE base addr %x\n', dx
mov [StandardATABases+2], dx
mov [ecx+IDE_DATA.BAR2_val], dx
;--------------------------------------
mov dx, 0x374
test byte [esi+PCIDEV.class], 4
jz @f
mov bl, 0x1C
push eax
call pci_read_reg
and eax, 0xFFFC
mov edx, eax
pop eax
@@:
DEBUGF 1, 'K : BAR3 IDE base addr %x\n', dx
mov [ecx+IDE_DATA.BAR3_val], dx
;--------------------------------------
mov bl, 0x20
push eax
call pci_read_reg
and eax, 0xFFFC
DEBUGF 1, 'K : BAR4 IDE controller register base addr %x\n', ax
mov [ecx+IDE_DATA.RegsBaseAddres], ax
pop eax
;--------------------------------------
mov bl, 0x3C
push eax
call pci_read_reg
and eax, 0xFF
DEBUGF 1, 'K : IDE Interrupt %x\n', al
mov [ecx+IDE_DATA.Interrupt], ax
pop eax
 
add ecx, sizeof.IDE_DATA
;--------------------------------------
jmp .loop
;-----------------------------------------------------------------------------
uglobal
align 4
;--------------------------------------
IDE_controller_pointer dd ?
;--------------------------------------
IDE_controller_1 IDE_DATA
IDE_controller_2 IDE_DATA
IDE_controller_3 IDE_DATA
;--------------------------------------
cache_ide0 IDE_CACHE
cache_ide1 IDE_CACHE
cache_ide2 IDE_CACHE
cache_ide3 IDE_CACHE
cache_ide4 IDE_CACHE
cache_ide5 IDE_CACHE
cache_ide6 IDE_CACHE
cache_ide7 IDE_CACHE
cache_ide8 IDE_CACHE
cache_ide9 IDE_CACHE
cache_ide10 IDE_CACHE
cache_ide11 IDE_CACHE
;--------------------------------------
IDE_device_1 rd 2
IDE_device_2 rd 2
IDE_device_3 rd 2
;--------------------------------------
endg
 
;--------------------------------------
; set Bus Master bit of Command PCI register
;--------------------------------------
set_pci_command_bus_master:
PCI_COMMAND_BUS_MASTER = 0x0004
push eax ecx
 
mov ecx, [ecx+IDE_DATA.pcidev]
mov ah, [ecx+PCIDEV.bus]
mov al, 1 ; word
mov bh, [ecx+PCIDEV.devfn]
mov bl, 0x4 ; Command register
push eax
call pci_read_reg
mov ecx, eax
pop eax
test ecx, PCI_COMMAND_BUS_MASTER ; already set?
jnz @f
or ecx, PCI_COMMAND_BUS_MASTER
call pci_write_reg
@@:
pop ecx eax
ret
 
;-----------------------------------------------------------------------------
; START of initialisation IDE ATA code
;-----------------------------------------------------------------------------
Init_IDE_ATA_controller:
cmp [ecx+IDE_DATA.ProgrammingInterface], 0
jne @f
 
ret
;--------------------------------------
@@:
mov esi, boot_disabling_ide
call boot_log
;--------------------------------------
; Disable IDE interrupts, because the search
; for IDE partitions is in the PIO mode.
;--------------------------------------
.disable_IDE_interrupt:
; Disable interrupts in IDE controller for PIO
mov al, 2
mov dx, [ecx+IDE_DATA.BAR1_val] ;0x3F4
add dx, 2 ;0x3F6
out dx, al
mov dx, [ecx+IDE_DATA.BAR3_val] ;0x374
add dx, 2 ;0x376
out dx, al
;-----------------------------------------------------------------------------
; set current ata bases
@@:
mov ax, [ecx+IDE_DATA.BAR0_val]
mov [StandardATABases], ax
mov ax, [ecx+IDE_DATA.BAR2_val]
mov [StandardATABases+2], ax
 
mov esi, boot_detecthdcd
call boot_log
;--------------------------------------
include 'dev_hdcd.inc'
;--------------------------------------
ret
;-----------------------------------------------------------------------------
Init_IDE_ATA_controller_2:
cmp [ecx+IDE_DATA.ProgrammingInterface], 0
jne @f
 
ret
;--------------------------------------
@@:
mov dx, [ecx+IDE_DATA.RegsBaseAddres]
; test whether it is our interrupt?
add dx, 2
in al, dx
test al, 100b
jz @f
; clear Bus Master IDE Status register
; clear Interrupt bit
out dx, al
;--------------------------------------
@@:
add dx, 8
; test whether it is our interrupt?
in al, dx
test al, 100b
jz @f
; clear Bus Master IDE Status register
; clear Interrupt bit
out dx, al
;--------------------------------------
@@:
; read status register and remove the interrupt request
mov dx, [ecx+IDE_DATA.BAR0_val] ;0x1F0
add dx, 0x7 ;0x1F7
in al, dx
mov dx, [ecx+IDE_DATA.BAR2_val] ;0x170
add dx, 0x7 ;0x177
in al, dx
;-----------------------------------------------------------------------------
; push eax edx
; mov dx, [ecx+IDE_DATA.RegsBaseAddres]
; xor eax, eax
; add dx, 2
; in al, dx
; DEBUGF 1, "K : Primary Bus Master IDE Status Register %x\n", eax
 
; add dx, 8
; in al, dx
; DEBUGF 1, "K : Secondary Bus Master IDE Status Register %x\n", eax
; pop edx eax
 
; cmp [ecx+IDE_DATA.RegsBaseAddres], 0
; setnz [ecx+IDE_DATA.dma_hdd]
;-----------------------------------------------------------------------------
; set interrupts for IDE Controller
;-----------------------------------------------------------------------------
pushfd
cli
.enable_IDE_interrupt:
mov esi, boot_enabling_ide
call boot_log
; Enable interrupts in IDE controller for DMA
xor ebx, ebx
cmp ecx, IDE_controller_2
jne @f
 
add ebx, 5
jmp .check_DRIVE_DATA
;--------------------------------------
@@:
cmp ecx, IDE_controller_3
jne .check_DRIVE_DATA
 
add ebx, 10
;--------------------------------------
.check_DRIVE_DATA:
mov al, 0
mov ah, [ebx+DRIVE_DATA+1]
test ah, 10100000b ; check for ATAPI devices
jz @f
;--------------------------------------
.ch1_pio_set_ATAPI:
DEBUGF 1, "K : IDE CH1 PIO, because ATAPI drive present\n"
jmp .ch1_pio_set_for_all
;--------------------------------------
.ch1_pio_set_no_devices:
DEBUGF 1, "K : IDE CH1 PIO because no devices\n"
jmp .ch1_pio_set_for_all
;-------------------------------------
.ch1_pio_set:
DEBUGF 1, "K : IDE CH1 PIO because device not support UDMA\n"
;-------------------------------------
.ch1_pio_set_for_all:
mov [ecx+IDE_DATA.dma_hdd_channel_1], al
jmp .ch2_check
;--------------------------------------
@@:
xor ebx, ebx
call calculate_IDE_device_values_storage
 
test ah, 1010000b
jz .ch1_pio_set_no_devices
 
test ah, 1000000b
jz @f
 
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al
je .ch1_pio_set
 
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al
je .ch1_pio_set
;--------------------------------------
@@:
test ah, 10000b
jz @f
 
add ebx, 2
 
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al
je .ch1_pio_set
 
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al
je .ch1_pio_set
;--------------------------------------
@@:
mov dx, [ecx+IDE_DATA.BAR1_val] ;0x3F4
add dx, 2 ;0x3F6
out dx, al
call set_pci_command_bus_master
DEBUGF 1, "K : IDE CH1 DMA enabled\n"
mov [ecx+IDE_DATA.dma_hdd_channel_1], byte 1
;--------------------------------------
.ch2_check:
test ah, 1010b ; check for ATAPI devices
jz @f
;--------------------------------------
.ch2_pio_set_ATAPI:
DEBUGF 1, "K : IDE CH2 PIO, because ATAPI drive present\n"
jmp .ch2_pio_set_for_all
;--------------------------------------
.ch2_pio_set_no_devices:
DEBUGF 1, "K : IDE CH2 PIO because no devices\n"
jmp .ch2_pio_set_for_all
;--------------------------------------
.ch2_pio_set:
DEBUGF 1, "K : IDE CH2 PIO because device not support UDMA\n"
;--------------------------------------
.ch2_pio_set_for_all:
mov [ecx+IDE_DATA.dma_hdd_channel_2], al
jmp .set_interrupts_for_IDE_controllers
;--------------------------------------
@@:
mov ebx, 4
call calculate_IDE_device_values_storage
 
test ah, 101b
jz .ch2_pio_set_no_devices
 
test ah, 100b
jz @f
 
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al
je .ch2_pio_set
 
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al
je .ch2_pio_set
;--------------------------------------
@@:
test ah, 1b
jz @f
 
add ebx, 2
 
cmp [ebx+IDE_DEVICE.UDMA_possible_modes], al
je .ch2_pio_set
 
cmp [ebx+IDE_DEVICE.UDMA_set_mode], al
je .ch2_pio_set
;--------------------------------------
@@:
mov dx, [ecx+IDE_DATA.BAR3_val] ;0x374
add dx, 2 ;0x376
out dx, al
call set_pci_command_bus_master
DEBUGF 1, "K : IDE CH2 DMA enabled\n"
mov [ecx+IDE_DATA.dma_hdd_channel_2], byte 1
;--------------------------------------
.set_interrupts_for_IDE_controllers:
mov esi, boot_set_int_IDE
call boot_log
;--------------------------------------
mov eax, [ecx+IDE_DATA.ProgrammingInterface]
; cmp ax, 0x0180
; je .pata_ide
 
; cmp ax, 0x018a
; jne .sata_ide
 
test al, 1 ; 0 - legacy PCI mode, 1 - native PCI mode
jnz .sata_ide
;--------------------------------------
.pata_ide:
cmp [ecx+IDE_DATA.RegsBaseAddres], 0
je .end_set_interrupts
 
push ecx
stdcall attach_int_handler, 14, IDE_irq_14_handler, ecx
pop ecx
DEBUGF 1, "K : Set IDE IRQ14 return code %x\n", eax
push ecx
stdcall attach_int_handler, 15, IDE_irq_15_handler, ecx
DEBUGF 1, "K : Set IDE IRQ15 return code %x\n", eax
pop ecx
 
jmp .end_set_interrupts
;--------------------------------------
.sata_ide:
; cmp ax, 0x0185
; je .sata_ide_1
 
; cmp ax, 0x018f
; jne .end_set_interrupts
;--------------------------------------
;.sata_ide_1:
; Some weird controllers generate an interrupt even if IDE interrupts
; are disabled and no IDE devices. For example, notebook ASUS K72F -
; IDE controller 010185 generates false interrupt when we work with
; the IDE controller 01018f. For this reason, the interrupt handler
; does not need to be installed if both channel IDE controller
; running in PIO mode.
 
; ...unfortunately, PCI interrupt can be shared with other devices
; which could enable it without consulting IDE code.
; So install the handler anyways and try to process
; even those interrupts which we are not expecting.
cmp [ecx+IDE_DATA.RegsBaseAddres], 0
je .end_set_interrupts
 
mov ax, [ecx+IDE_DATA.Interrupt]
movzx eax, al
push ecx
stdcall attach_int_handler, eax, IDE_common_irq_handler, ecx
pop ecx
DEBUGF 1, "K : Set IDE IRQ%d return code %x\n", [ecx+IDE_DATA.Interrupt]:1, eax
;--------------------------------------
.end_set_interrupts:
popfd
ret
;-----------------------------------------------------------------------------
; END of initialisation IDE ATA code
;-----------------------------------------------------------------------------
find_IDE_controller_done:
mov ecx, IDE_controller_1
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller
mov ecx, IDE_controller_2
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller
mov ecx, IDE_controller_3
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller
;-----------------------------------------------------------------------------
mov esi, boot_getcache
call boot_log
include 'getcache.inc'
;-----------------------------------------------------------------------------
mov esi, boot_detectpart
call boot_log
include 'sear_par.inc'
;-----------------------------------------------------------------------------
mov esi, boot_init_sys
call boot_log
call Parser_params
 
if ~ defined extended_primary_loader
; ramdisk image should be loaded by extended primary loader if it exists
; READ RAMDISK IMAGE FROM HD
include '../boot/rdload.inc'
end if
;-----------------------------------------------------------------------------
mov ecx, IDE_controller_1
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller_2
mov ecx, IDE_controller_2
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller_2
mov ecx, IDE_controller_3
mov [IDE_controller_pointer], ecx
call Init_IDE_ATA_controller_2
;-----------------------------------------------------------------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/disks.inc
0,0 → 1,15
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
include 'dev_fd.inc'
include 'dev_hdcd.inc'
include 'getcache.inc'
include 'sear_par.inc'
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect/getcache.inc
0,0 → 1,209
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
;-----------------------------------------------------------------------------
pusha
 
mov eax, [pg_data.pages_free]
; 1/32
shr eax, 5
; round off up to 8 pages
shr eax, 3
shl eax, 3
; translate pages in butes *4096
shl eax, 12
; check a upper size of the cache, no more than 1 Mb on the physical device
cmp eax, 1024*1024
jbe @f
 
mov eax, 1024*1024
jmp .continue
;--------------------------------------
@@:
; check a lower size of the cache, not less than 128 Kb on the physical device
cmp eax, 128*1024
jae .continue
 
mov eax, 128*1024
;--------------------------------------
.continue:
push ecx
mov ecx, 12
mov esi, cache_ide0+IDE_CACHE.size
cld
@@:
mov [esi], eax
add esi, sizeof.IDE_CACHE
loop @b
 
pop ecx
 
xor eax, eax
mov [hdd_appl_data], 1 ;al
mov [cd_appl_data], 1
;--------------------------------------
test byte [DRIVE_DATA+1], 0x80
je @f
 
mov esi, cache_ide0
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+1], 0x20
je @f
 
mov esi, cache_ide1
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+1], 8
je @f
 
mov esi, cache_ide2
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+1], 2
je @f
 
mov esi, cache_ide3
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+6], 0x80
je @f
 
mov esi, cache_ide4
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+6], 0x20
je @f
 
mov esi, cache_ide5
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+6], 8
je @f
 
mov esi, cache_ide6
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+6], 2
je @f
 
mov esi, cache_ide7
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+11], 0x80
je @f
 
mov esi, cache_ide8
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+11], 0x20
je @f
 
mov esi, cache_ide9
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+11], 8
je @f
 
mov esi, cache_ide10
call get_cache_ide
;--------------------------------------
@@:
test byte [DRIVE_DATA+11], 2
je end_get_cache
 
mov esi, cache_ide11
call get_cache_ide
 
jmp end_get_cache
;-----------------------------------------------------------------------------
get_cache_ide:
and [esi+IDE_CACHE.search_start], 0
and [esi+IDE_CACHE.appl_search_start], 0
 
push ecx
; DEBUGF 1, "K : IDE_CACHE.size %x\n", [esi+IDE_CACHE.size]
stdcall kernel_alloc, [esi+IDE_CACHE.size]
mov [esi+IDE_CACHE.pointer], eax
pop ecx
 
mov edx, eax
mov eax, [esi+IDE_CACHE.size]
shr eax, 3
; DEBUGF 1, "K : IDE_CACHE.system_data_size %x\n", eax
mov [esi+IDE_CACHE.system_data_size], eax
mov ebx, eax
imul eax, 7
; DEBUGF 1, "K : IDE_CACHE.appl_data_size %x\n", eax
mov [esi+IDE_CACHE.appl_data_size], eax
add ebx, edx
mov [esi+IDE_CACHE.data_pointer], ebx
 
.cd:
push ecx
mov eax, [esi+IDE_CACHE.system_data_size]
call calculate_for_cd
add eax, [esi+IDE_CACHE.pointer]
mov [esi+IDE_CACHE.system_data], eax
mov [esi+IDE_CACHE.system_sad_size], ecx
 
push edi
mov edi, [esi+IDE_CACHE.pointer]
call clear_ide_cache
pop edi
 
mov eax, [esi+IDE_CACHE.appl_data_size]
call calculate_for_cd
add eax, [esi+IDE_CACHE.data_pointer]
mov [esi+IDE_CACHE.appl_data], eax
mov [esi+IDE_CACHE.appl_sad_size], ecx
 
push edi
mov edi, [esi+IDE_CACHE.data_pointer]
call clear_ide_cache
pop edi
 
pop ecx
ret
;-----------------------------------------------------------------------------
calculate_for_cd:
push eax
mov ebx, eax
shr eax, 11
shl eax, 3
sub ebx, eax
shr ebx, 11
mov ecx, ebx
shl ebx, 11
pop eax
sub eax, ebx
dec ecx
ret
;-----------------------------------------------------------------------------
clear_ide_cache:
push eax
shl ecx, 1
xor eax, eax
cld
rep stosd
pop eax
ret
;-----------------------------------------------------------------------------
end_get_cache:
popa
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/detect
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/fdo.inc
0,0 → 1,456
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2019. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
;
; Formatted Debug Output (FDO)
; Copyright (c) 2005-2006, mike.dld
; Created: 2005-01-29, Changed: 2006-11-10
;
; For questions and bug reports, mail to mike.dld@gmail.com
;
; Available format specifiers are: %s, %d, %u, %x (with partial width support)
;
 
; to be defined:
; __DEBUG__ equ 1
; __DEBUG_LEVEL__ equ 5
 
_esp equ esp
 
macro put_board {
call sys_msg_board
}
 
macro debug_func name {
if used name
name@of@func equ name
}
 
macro debug_beginf {
align 4
name@of@func:
}
 
debug_endf fix end if
 
macro DEBUGS _sign,[_str] {
common
local tp
tp equ 0
match _arg:_num,_str \{
DEBUGS_N _sign,_num,_arg
tp equ 1
\}
match =0 _arg,tp _str \{
DEBUGS_N _sign,,_arg
\}
}
 
macro DEBUGS_N _sign,_num,[_str] {
common
pushf
pushad
local ..str,..label,is_str
is_str = 0
forward
if _str eqtype ''
is_str = 1
end if
common
if is_str = 1
jmp ..label
..str db _str,0
..label:
mov edx, ..str
else
esp equ esp+4*8+4
mov edx, _str
esp equ _esp
end if
if ~_num eq
if _num eqtype eax
if _num in <eax,ebx,ecx,edx,edi,ebp,esp>
mov esi, _num
else if ~_num eq esi
movzx esi, _num
end if
else if _num eqtype 0
mov esi, _num
else
local tp
tp equ 0
match [_arg],_num \{
mov esi, dword[_arg]
tp equ 1
\}
match =0 =dword[_arg],tp _num \{
mov esi, dword[_arg]
tp equ 1
\}
match =0 =word[_arg],tp _num \{
movzx esi, word[_arg]
tp equ 1
\}
match =0 =byte[_arg],tp _num \{
movzx esi, byte[_arg]
tp equ 1
\}
match =0,tp \{
'Error: specified string width is incorrect'
\}
end if
else
mov esi, 0x7FFFFFFF
end if
call fdo_debug_outstr
popad
popf
}
 
macro DEBUGD _sign,_dec {
local tp
tp equ 0
match _arg:_num,_dec \{
DEBUGD_N _sign,_num,_arg
tp equ 1
\}
match =0 _arg,tp _dec \{
DEBUGD_N _sign,,_arg
\}
}
 
macro DEBUGD_N _sign,_num,_dec {
pushf
pushad
if (~_num eq)
if (_dec eqtype eax | _dec eqtype 0)
'Error: precision allowed only for in-memory variables'
end if
if (~_num in <1,2,4>)
if _sign
'Error: 1, 2 and 4 are only allowed for precision in %d'
else
'Error: 1, 2 and 4 are only allowed for precision in %u'
end if
end if
end if
if _dec eqtype eax
if _dec in <ebx,ecx,edx,esi,edi,ebp,esp>
mov eax, _dec
else if ~_dec eq eax
if _sign = 1
movsx eax, _dec
else
movzx eax, _dec
end if
end if
else if _dec eqtype 0
mov eax, _dec
else
; add esp,4*8+4
esp equ esp+4*8+4
if _num eq
mov eax, dword _dec
else if _num = 1
if _sign = 1
movsx eax, byte _dec
else
movzx eax, byte _dec
end if
else if _num = 2
if _sign = 1
movsx eax, word _dec
else
movzx eax, word _dec
end if
else
mov eax, dword _dec
end if
esp equ _esp
; sub esp,4*8+4
end if
mov cl, _sign
call fdo_debug_outdec
popad
popf
}
 
macro DEBUGH _sign,_hex {
local tp
tp equ 0
match _arg:_num,_hex \{
DEBUGH_N _sign,_num,_arg
tp equ 1
\}
match =0 _arg,tp _hex \{
DEBUGH_N _sign,,_arg
\}
}
 
macro DEBUGH_N _sign,_num,_hex {
pushf
pushad
if (~_num eq) & (~_num in <1,2,3,4,5,6,7,8>)
'Error: 1..8 are only allowed for precision in %x'
end if
if _hex eqtype eax
if _hex in <eax,ebx,ecx,edx,esi,edi,ebp,esp>
if ~_hex eq eax
mov eax, _hex
end if
mov edx, 8
else if _hex in <ax,bx,cx,dx,si,di,bp,sp>
if ~_hex eq ax
movzx eax, _hex
end if
if (_num eq)
mov edx, 4
end if
else if _hex in <al,ah,bl,bh,cl,ch,dl,dh>
if ~_hex eq al
movzx eax, _hex
end if
if (_num eq)
mov edx, 2
end if
end if
else if _hex eqtype 0
mov eax, _hex
else
; add esp,4*8+4
esp equ esp+4*8+4
mov eax, dword _hex
esp equ _esp
; sub esp,4*8+4
end if
if ~_num eq
mov edx, _num
else
if ~_hex eqtype eax
mov edx, 8
end if
end if
call fdo_debug_outhex
popad
popf
}
 
;-----------------------------------------------------------------------------
 
debug_func fdo_debug_outchar
debug_beginf
pushad
movzx ecx, al
mov ebx, 1
put_board
popad
ret
debug_endf
 
debug_func fdo_debug_outstr
debug_beginf
mov ebx, 1
.l1:
dec esi
js .l2
movzx ecx, byte[edx]
or cl, cl
jz .l2
put_board
inc edx
jmp .l1
.l2:
ret
debug_endf
 
debug_func fdo_debug_outdec
debug_beginf
or cl, cl
jz @f
or eax, eax
jns @f
neg eax
push eax
mov al, '-'
call fdo_debug_outchar
pop eax
@@:
movi ecx, 10
push -'0'
.l1:
xor edx, edx
div ecx
push edx
test eax, eax
jnz .l1
.l2:
pop eax
add al, '0'
jz .l3
call fdo_debug_outchar
jmp .l2
.l3:
ret
debug_endf
 
debug_func fdo_debug_outhex
__fdo_hexdigits db '0123456789ABCDEF'
debug_beginf
mov cl, dl
neg cl
add cl, 8
shl cl, 2
rol eax, cl
.l1:
rol eax, 4
push eax
and eax, 0x0000000F
mov al, [__fdo_hexdigits+eax]
call fdo_debug_outchar
pop eax
dec edx
jnz .l1
ret
debug_endf
 
;-----------------------------------------------------------------------------
 
macro DEBUGF _level,_format,[_arg] {
common
if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__
local ..f1,f2,a1,a2,c1,c2,c3,..lbl
_debug_str_ equ __debug_str_ # a1
a1 = 0
c2 = 0
c3 = 0
f2 = 0
repeat ..lbl-..f1
virtual at 0
db _format,0,0
load c1 word from %-1
end virtual
if c1 = '%s'
virtual at 0
db _format,0,0
store word 0 at %-1
load c1 from f2-c2
end virtual
if c1 <> 0
DEBUGS 0,_debug_str_+f2-c2
end if
c2 = c2 + 1
f2 = %+1
DEBUGF_HELPER S,a1,0,_arg
else if c1 = '%x'
virtual at 0
db _format,0,0
store word 0 at %-1
load c1 from f2-c2
end virtual
if c1 <> 0
DEBUGS 0,_debug_str_+f2-c2
end if
c2 = c2 + 1
f2 = %+1
DEBUGF_HELPER H,a1,0,_arg
else if c1 = '%d' | c1 = '%u'
local c4
if c1 = '%d'
c4 = 1
else
c4 = 0
end if
virtual at 0
db _format,0,0
store word 0 at %-1
load c1 from f2-c2
end virtual
if c1 <> 0
DEBUGS 0,_debug_str_+f2-c2
end if
c2 = c2 + 1
f2 = %+1
DEBUGF_HELPER D,a1,c4,_arg
else if c1 = '\n'
c3 = c3 + 1
end if
end repeat
virtual at 0
db _format,0,0
load c1 from f2-c2
end virtual
if (c1<>0)&(f2<>..lbl-..f1-1)
DEBUGS 0,_debug_str_+f2-c2
end if
virtual at 0
..f1 db _format,0
..lbl:
__debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3
end virtual
end if
}
 
macro DEBUGFG _level, _group, _format, [_arg] {
common
if _group eqtype
DEBUGF _level, _format,_arg
else
if _level >= _group
DEBUGF 999, _format,_arg
end if
end if
}
 
macro __include_debug_strings dummy,[_id,_fmt,_len] {
common
local c1,a1,a2
forward
if defined _len & ~_len eq
_id:
a1 = 0
a2 = 0
repeat _len
virtual at 0
db _fmt,0,0
load c1 word from %+a2-1
end virtual
if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u')
db 0
a2 = a2 + 1
else if (c1='\n')
dw $0A0D
a1 = a1 + 1
a2 = a2 + 1
else
db c1 and 0x0FF
end if
end repeat
db 0
end if
}
 
macro DEBUGF_HELPER _letter,_num,_sign,[_arg] {
common
local num
num = 0
forward
if num = _num
DEBUG#_letter _sign,_arg
end if
num = num+1
common
_num = _num+1
}
 
macro include_debug_strings {
if __DEBUG__ = 1
match dbg_str,__debug_strings \{
__include_debug_strings dbg_str
\}
end if
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/build.bat
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/bootbios.asm
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:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/Makefile
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/build.sh
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
}
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/startos.ini
0,0 → 1,98
; Copyright (c) 2009, <Lrz>
; 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.
;*****************************************************************************
 
; это комментарий
[loader]
; секция [loader] содержит параметры загрузчика
; в течение timeout секунд загрузчик будет ждать реакции пользователя,
; если её не последует, будет загружена конфигурация, указанная в default
timeout=5
default=kolibri_EE
; прочие секции - по одной на каждую конфигурацию
; и по одной на каждый вторичный модуль
[main]
name="Kord OS v 0.00001"
descript="This is x64 OS microkernel"
kernel=kord/kord001.ker
module=kord/fat.mod
module=kord/ntfs.mod
RamdiskFS=fat
RamdiskSector=512
RamdiskCluster=1
RamdiskSize=1440K
RamdiskFile=kord/launcher,launcher
RamdiskFile=kord/filema~1/kfar,"File Managers/kfar"
[beta]
name="Kord OS v 0.00002 beta"
descript="This is x64 OS microkernel version 2"
kernel=kord/kord002.ker
module=kord/fat.mod
module=kord/ntfs.mod
RamdiskFS=fat
RamdiskSector=512
RamdiskCluster=1
RamdiskSize=1440K
RamdiskFile=kord/launcher,launcher
RamdiskFile=kord/filema~1/kfar,"File Managers/kfar"
[kolibri_EE]
name="KOLIBRY EXCLUSIVE EDITION"
descript="KOLIBRY EXCLUSIVE EDITION BEST OF THE BEST opetation system"
LoaderModule=kolibri/kolibri.ldm
RamdiskFS=FAT
RamdiskSector=512
RamdiskCluster=1
RamdiskSize=1440K
LoaderRamImage=kolibri.img
RamdiskPATH=/kolibri/
RamdiskFile=@menu,@menu
RamdiskFile=@TASKBAR,@TASKBAR
RamdiskFile=@RB,@TASKBAR
 
[legacy_kolibri]
name="KolibriOS"
descript="Standart KolibriOS"
LoaderModule=kord/kolibri.ldm
RamdiskFS=fat
RamdiskSector=512
RamdiskCluster=1
RamdiskSize=1440K
RamdiskPATH=/kolibri/
RamdiskFile=@menu,@menu
RamdiskFile=@TASKBAR,@TASKBAR
RamdiskFile=@RB,@RB
RamdiskFile=@rcher,@rcher
RamdiskFile=@ss,@ss
RamdiskFile=ac97snd,ac97snd
RamdiskFile=animage,animage
RamdiskFile=AUTOEXEC.CMD,AUTOEXEC.CMD
RamdiskFile=AUTORUN.DAT,AUTORUN.DAT
RamdiskFile=calc,calc
RamdiskFile=calendar,calendar
RamdiskFile=progs/cdp,cdp
RamdiskFile=cmd,cmd
RamdiskFile=config.inc,config.inc
RamdiskFile=copy2,copy2
 
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/cdfs/bootsect.asm
0,0 → 1,1024
; 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.
;*****************************************************************************
 
jmp far 0:real_start
; special text
org $+0x7C00
real_start:
; initialize
xor ax, ax
mov ss, ax
mov sp, 0x7C00
mov ds, ax
mov es, ax
cld
sti
mov [bootdrive], dl
; check LBA support
mov ah, 41h
mov bx, 55AAh
int 13h
mov si, aNoLBA
jc err_
cmp bx, 0AA55h
jnz err_
test cl, 1
jz err_
; get file system information
; scan for Primary Volume Descriptor
db 66h
push 10h-1
pop eax
pvd_scan_loop:
mov cx, 1
inc eax
mov bx, 0x1000
call read_sectors
jnc @f
fatal_read_err:
mov si, aReadError
err_:
call out_string
mov si, aPressAnyKey
call out_string
xor ax, ax
int 16h
int 18h
jmp $
@@:
push ds
pop es
cmp word [bx+1], 'CD'
jnz pvd_scan_loop
cmp word [bx+3], '00'
jnz pvd_scan_loop
cmp byte [bx+5], '1'
jnz pvd_scan_loop
; we have found ISO9660 descriptor, look for type
cmp byte [bx], 1 ; Primary Volume Descriptor?
jz pvd_found
cmp byte [bx], 0xFF ; Volume Descriptor Set Terminator?
jnz pvd_scan_loop
; Volume Descriptor Set Terminator reached, no PVD found - fatal error
mov si, no_pvd
jmp err_
pvd_found:
add bx, 80h
mov ax, [bx]
mov [lb_size], ax
; calculate number of logical blocks in one sector
mov ax, 800h
cwd
div word [bx]
mov [lb_per_sec], ax
; get location of root directory
mov di, root_location
movzx eax, byte [bx+1Dh]
add eax, [bx+1Eh]
stosd
; get memory size
int 12h
mov si, nomem_str
cmp ax, 71000h / 400h
jb err_
shr ax, 1
sub ax, 60000h / 800h
mov [size_rest], ax
mov [free_ptr], 60000h / 800h
; load path table
; if size > 62K => it's very strange, avoid using it
; if size > (size of cache)/2 => avoid using it too
mov ecx, [bx+4]
cmp ecx, 0x10000 - 0x800
ja nopathtable
shr ax, 1
cmp ax, 0x20
jae @f
shl ax, 11
cmp cx, ax
ja nopathtable
@@:
; size is ok, try to load it
mov [pathtable_size], cx
mov eax, [bx+12]
xor edx, edx
div dword [lb_per_sec]
imul dx, [bx]
mov [pathtable_start], dx
add cx, dx
call cx_to_sectors
xor bx, bx
push 6000h
pop es
call read_sectors
jc nopathtable
; path table has been loaded
inc [use_path_table]
sub [size_rest], cx
add [free_ptr], cx
nopathtable:
; init cache
mov ax, [size_rest]
mov [cache_size], ax
mov ax, [free_ptr]
mov [cache_start], ax
; load secondary loader
mov di, secondary_loader_info
call load_file
test bx, bx
jnz noloader
; set registers for secondary loader
mov ah, [bootdrive]
mov al, 'c'
mov bx, 'is'
mov si, callback
jmp far [si-callback+secondary_loader_info] ; jump to 1000:0000
 
noloader:
mov si, aKernelNotFound
jmp err_
 
read_sectors:
; es:bx = pointer to data
; eax = first sector
; cx = number of sectors
pushad
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
db 66h
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, [cs:bootdrive]
mov ah, 42h
int 13h
jc diskreaderr
; restore stack
add sp, 10h
; increase current sector & buffer; decrease number of sectors
movzx esi, cx
mov ax, es
shl cx, 7
add ax, cx
mov es, ax
pop cx
pop ax
add eax, esi
sub cx, si
jnz do_read_sectors
pop ds
popad
ret
diskreaderr:
add sp, 10h + 2*2
pop ds
popad
stc
out_string.ret:
ret
 
out_string:
; in: ds:si -> ASCIIZ string
lodsb
test al, al
jz .ret
mov ah, 0Eh
mov bx, 7
int 10h
jmp out_string
 
aNoLBA db 'The drive does not support LBA!',0
aReadError db 'Read error',0
no_pvd db 'Primary Volume Descriptor not found!',0
nomem_str db 'No memory',0
aPressAnyKey db 13,10,'Press any key...',13,10,0
 
load_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 = 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)
; parse path to the file
lea si, [di+6]
mov eax, [cs:root_location]
cmp [cs:use_path_table], 0
jz parse_dir
; scan for path in path table
push di
push 6000h
pop es
mov di, [cs:pathtable_start] ; es:di = pointer to current entry in path table
mov dx, 1 ; dx = number of current entry in path table, start from 1
mov cx, [cs:pathtable_size]
pathtable_newparent:
mov bx, dx ; bx = number of current parent in path table: root = 1
scan_path_table_e:
call is_last_component
jnc path_table_scanned
scan_path_table_i:
cmp word [es:di+6], bx
jb .next
ja path_table_notfound
call test_filename1
jc .next
@@:
lodsb
cmp al, '/'
jnz @b
jmp pathtable_newparent
.next:
; go to next entry
inc dx
movzx ax, byte [es:di]
add ax, 8+1
and al, not 1
add di, ax
sub cx, ax
ja scan_path_table_i
path_table_notfound:
pop di
mov ax, -1
mov dx, ax
mov bx, 2 ; file not found
ret
path_table_scanned:
movzx eax, byte [es:di+1]
add eax, [es:di+2]
pop di
parse_dir:
; eax = logical block, ds:di -> information structure, ds:si -> file name
; was the folder already read?
push di ds
push cs
pop ds
mov [cur_desc_end], 2000h
mov bx, cachelist
.scan1:
mov bx, [bx+2]
cmp bx, cachelist
jz .notfound
cmp [bx+4], eax
jnz .scan1
.found:
; yes; delete this item from the list (the following code will append this item to the tail)
mov di, [bx]
push word [bx+2]
pop word [di+2]
mov di, [bx+2]
push word [bx]
pop word [di]
mov di, bx
jmp .scan
.notfound:
; no; load first sector of the folder to get its size
push eax
push si
mov si, 1
call load_phys_sector_for_lb_force
mov bx, si
pop si
pop eax
jnc @f
; read error - return
.readerr:
pop ds
.readerr2:
pop di
mov ax, -1
mov dx, ax
mov bx, 3
ret
@@:
; first item of the folder describes the folder itself
; do not cache too big folders: size < 64K and size <= (total cache size)/2
cmp word [bx+12], 0
jnz .nocache
mov cx, [cache_size] ; cx = cache size in sectors
shr cx, 1 ; cx = (cache size)/2
cmp cx, 0x20
jae @f
shl cx, 11
cmp [bx+10], cx
ja .nocache
@@:
; we want to cache this folder; get space for it
mov cx, [bx+10]
call cx_to_sectors
jnz .yescache
.nocache:
push dword [bx+10]
pop dword [cur_nocache_len]
call lb_to_sector
push ds
pop es
pop ds
.nocache_loop:
push eax
mov dx, 1800h
call scan_for_filename_in_sector
mov cx, dx
pop eax
jnc .j_scandone
sub cx, bx
sub word [es:cur_nocache_len], cx
sbb word [es:cur_nocache_len+2], 0
jb .j_scandone
ja @f
cmp word [es:cur_nocache_len], 0
jz .j_scandone
@@:
mov cx, 1
inc eax
push es
mov bx, 1000h
call read_sectors
pop es
jc .readerr2
jmp .nocache_loop
.j_scandone:
jmp .scandone
.yescache:
push bx
mov bx, [cachelist.head]
.freeloop:
cmp cx, [size_rest]
jbe .sizeok
@@:
; if we are here: there is not enough free space, so we must delete old folders' data
; N.B. We know that after deleting some folders the space will be available (size <= (total cache size)/2).
; one loop iteration: delete data of one folder
pusha
mov dx, [bx+10]
mov es, dx ; es = segment of folder data to be deleted
xor di, di
mov ax, [bx+8]
add ax, 0x7FF
rcr ax, 1
shr ax, 10
push ax
shl ax, 11-4 ; get number of paragraphs in folder data to be deleted
mov cx, [cache_size]
add cx, [cache_start]
push ds
push ax
add ax, dx
mov ds, ax
pop ax
shl cx, 11-4
sub cx, dx ; cx = number of paragraphs to be moved
push si
xor si, si
; move cx paragraphs from ds:si to es:di to get free space in the end of cache
@@:
sub cx, 1000h
jbe @f
push cx
mov cx, 8000h
rep movsw
mov cx, ds
add cx, 1000h
mov ds, cx
mov cx, es
add cx, 1000h
mov es, cx
pop cx
jmp @b
@@:
add cx, 1000h
shl cx, 3
rep movsw
pop si
pop ds
; correct positions in cache for existing items
mov cx, 80h
mov di, 8400h
.correct:
cmp [di+10], dx
jbe @f
sub [di+10], ax
@@:
add di, 12
loop .correct
; some additional space is free now
pop ax
add [size_rest], ax
sub [free_ptr], ax
; add cache item to the list of free items
mov dx, [bx]
mov ax, [free_cache_item]
mov [bx], ax
mov [free_cache_item], bx
mov bx, dx
; current iteration done
popa
jmp .freeloop
.sizeok:
mov [cachelist.head], bx
mov word [bx+2], cachelist
; allocate new item in cache
mov di, [free_cache_item]
test di, di
jz .nofree
push word [di]
pop [free_cache_item]
jmp @f
.nofree:
mov di, [last_cache_item]
add [last_cache_item], 12
@@:
pop bx
push si di
; mov [di+4], eax ; start of folder
scasd
stosd
push ax
mov ax, [free_ptr]
shl ax, 11-4
mov [di+10-8], ax
mov es, ax
pop ax
add [free_ptr], cx
sub [size_rest], cx
; read folder data
; first sector is already in memory, 0000:bx
pusha
mov cx, [bx+10]
mov [di+8-8], cx ; folder size in bytes
mov si, bx
xor di, di
mov cx, 0x1800
sub cx, si
rep movsb
pop ax
push di
popa
; read rest of folder
mov esi, dword [lb_per_sec]
add eax, esi
dec si
not si
and ax, si
mov si, word [bx+10]
mov bx, di
pop di
sub si, bx
jbe @f
mov [cur_limit], esi
call read_many_bytes
pop si
jnc .scan
jmp .readerr
@@:
pop si
.scan:
; now we have required cache item; append it to the end of list
mov bx, [cachelist.tail]
mov [cachelist.tail], di
mov [di+2], bx
mov word [di], cachelist
mov [bx], di
; scan for given filename
mov es, [di+10]
mov dx, [di+8]
pop ds
xor bx, bx
call scan_for_filename_in_sector
.scandone:
push cs
pop es
mov bx, 2000h
cmp bx, [es:cur_desc_end]
jnz filefound
j_notfound:
jmp path_table_notfound
filefound:
@@:
lodsb
test al, al
jz @f
cmp al, '/'
jnz @b
@@:
mov cl, [es:bx+8]
test al, al
jz @f
; parse next component of file name
test cl, 2 ; directory?
jz j_notfound
mov eax, [es:bx]
pop di
jmp parse_dir
@@:
test cl, 2 ; directory?
jnz j_notfound ; do not allow read directories as regular files
; ok, now load the file
pop di
les bx, [di]
call normalize
movzx esi, word [di+4] ; esi = limit in 4K blocks
shl esi, 12 ; esi = limit in bytes
push cs
pop ds
mov [cur_limit], esi
mov di, 2000h
loadloop:
and [cur_start], 0
.loadnew:
mov esi, [cur_limit]
mov eax, [cur_start]
add esi, eax
mov [overflow], 1
sub esi, [di+4]
jb @f
xor esi, esi
dec [overflow]
@@:
add esi, [di+4] ; esi = number of bytes to read
mov [cur_start], esi
sub esi, eax
jz .loadcontinue
xor edx, edx
div dword [lb_size] ; eax = number of logical blocks to skip,
mov [first_byte], dx; [first_byte] = number of bytes to skip in 1st block
cmp byte [di+10], 0
jnz .interleaved
add eax, [di]
; read esi bytes from logical block eax to buffer es:bx
call read_many_bytes.with_first
jc .readerr3
.loadcontinue:
mov [cur_chunk], di
add di, 11
cmp di, [cur_desc_end]
jae @f
cmp [cur_limit], 0
jnz loadloop
@@:
mov bx, [overflow]
.calclen:
; calculate length of file
xor ax, ax
xor dx, dx
mov di, 2000h
@@:
add ax, [di+4]
adc dx, [di+6]
add di, 11
cmp di, [cur_desc_end]
jb @b
ret
.interleaved:
mov [cur_unit_limit], esi
push esi
; skip first blocks
movzx ecx, byte [di+9] ; Unit Size
movzx esi, byte [di+10] ; Interleave Gap
add si, cx
mov edx, [di]
@@:
sub eax, ecx
jb @f
add edx, esi
jmp @b
@@:
add ecx, eax ; ecx = number of logical blocks to skip
lea eax, [ecx+edx] ; eax = first logical block
pop esi
.interleaved_loop:
; get number of bytes in current file unit
push eax
movzx eax, byte [di+9]
sub ax, cx
imul eax, dword [lb_size]
cmp eax, esi
ja .i2
.i1:
xchg esi, eax
.i2:
pop eax
sub [cur_unit_limit], esi
push eax
; read esi bytes from logical block eax to buffer es:bx
call read_many_bytes.with_first
pop eax
jnc @f
.readerr3:
mov bx, 3
jmp .calclen
@@:
mov esi, [cur_unit_limit]
test esi, esi
jz .loadcontinue
movzx ecx, byte [di+9] ; add Unit Size
add cl, byte [di+10] ; add Interleave Gap
adc ch, 0
add eax, ecx
xor cx, cx
mov [first_byte], cx
jmp .interleaved_loop
 
cx_to_sectors:
add cx, 7FFh
rcr cx, 1
shr cx, 10
ret
 
is_last_component:
; in: ds:si -> name
; out: CF set <=> current component is not last (=> folder)
push si
@@:
lodsb
test al, al
jz @f
cmp al, '/'
jnz @b
stc
@@:
pop si
ret
 
test_filename1:
; in: ds:si -> filename, es:di -> path table item
; out: CF set <=> no match
pusha
mov cl, [es:di]
add di, 8
jmp test_filename2.start
test_filename2:
; in: ds:si -> filename, es:bx -> directory item
; out: CF set <=> no match
pusha
mov cl, [es:bx+32]
lea di, [bx+33]
.start:
mov ch, 0
@@:
lodsb
test al, al
jz .test1
cmp al, '/'
jz .test1
call toupper
mov ah, al
mov al, [es:di]
call toupper
inc di
cmp al, ah
loopz @b
jnz .next1
; if we have reached this point: current name is done
lodsb
test al, al
jz .ret
cmp al, '/'
jz .ret
; if we have reached this point: current name is done, but input name continues
; so they do not match
jmp .next1
.test1:
; if we have reached this point: input name is done, but current name continues
; "filename.ext;version" in ISO-9660 represents file "filename.ext"
; "filename." and "filename.;version" are also possible for "filename"
cmp byte [es:di], '.'
jnz @f
inc di
dec cx
jz .ret
@@:
cmp byte [es:di], ';'
jnz .next1
jmp .ret
.next1:
stc
.ret:
popa
ret
 
toupper:
; in: al=symbol
; out: al=symbol in uppercase
cmp al, 'a'
jb .ret
cmp al, 'z'
ja .ret
sub al, 'a'-'A'
.ret:
ret
 
scan_for_filename_in_sector:
; in: ds:si->filename, es:bx->folder data, dx=limit
; out: CF=0 if found
push bx
.loope:
push bx
.loop:
cmp bx, dx
jae .notfound
cmp byte [es:bx], 0
jz .loopd
test byte [es:bx+25], 4 ; ignore files with Associated bit
jnz .next
call test_filename2
jc .next
push ds es di
push es
pop ds
push cs
pop es
mov di, [es:cur_desc_end]
movzx eax, byte [bx+1]
add eax, [bx+2]
stosd ; first logical block
mov eax, [bx+10]
stosd ; length
mov al, [bx+25]
stosb ; flags
mov ax, [bx+26]
stosw ; File Unit size, Interleave Gap size
mov [es:cur_desc_end], di
cmp di, 3000h
pop di es ds
jae .done
test byte [es:bx+25], 80h
jz .done
.next:
add bl, [es:bx]
adc bh, 0
jmp .loop
.loopd:
mov ax, bx
pop bx
@@:
add bx, [cs:lb_size]
jz .done2
cmp bx, ax
jb @b
jmp .loope
.notfound:
stc
.done:
pop bx
.done2:
pop bx
ret
 
lb_to_sector:
xor edx, edx
div dword [lb_per_sec]
ret
 
load_phys_sector_for_lb_force:
; in: eax = logical block, ds=0
; in: si=0 - accept 0 logical blocks, otherwise force read at least 1
; out: 0000:1000 = physical sector data; si -> logical block
; out: eax = next physical sector
; out: CF=1 if read error
; destroys cx
; this procedure reads 0-3 or 1-4 logical blocks, up to the end of physical sector
call lb_to_sector
or si, dx
jnz @f
mov si, 1800h
jmp .done
@@:
mov si, 1000h
imul dx, [lb_size]
add si, dx
mov cx, 1
push es bx
push ds
pop es
mov bx, 1000h
call read_sectors
pop bx es
inc eax
.done:
ret
 
normalize:
; in: es:bx = far pointer
; out: es:bx = normalized pointer (i.e. 0 <= bx < 0x10)
push ax bx
mov ax, es
shr bx, 4
add ax, bx
mov es, ax
pop bx ax
and bx, 0x0F
ret
 
read_many_bytes:
and [first_byte], 0
read_many_bytes.with_first:
; read esi bytes from logical block dx:ax to buffer es:bx
; out: CF=1 <=> disk error
push di
; load first physical sector
push bx si
mov si, [first_byte]
call load_phys_sector_for_lb_force
jnc @f
pop si bx
.ret:
pop di
ret
@@:
add si, [first_byte]
mov ecx, 1800h
sub cx, si
mov ebx, esi
pop bx
sub ebx, ecx
jnc @f
add cx, bx
xor ebx, ebx
@@:
pop di
sub [cur_limit], ecx
rep movsb
mov esi, ebx
mov bx, di
call normalize
; load other physical sectors
; read esi bytes from physical sector eax to buffer es:bx
test esi, esi
jz .ret
push esi
add esi, 0x7FF
and si, not 0x7FF
cmp esi, [cur_limit]
jbe .okplace
.noplace:
sub esi, 800h
.okplace:
shr esi, 11 ; si = number of sectors
mov cx, si
jz @f
call read_sectors
@@:
pop esi
jc .ret
movzx ecx, cx
add eax, ecx
shl ecx, 11
sub [cur_limit], ecx
sub esi, ecx
jc .big
jz .nopost
push bx es
push ds
pop es
mov bx, 1000h
mov cx, 1
call read_sectors
pop es di
jc .ret2
mov cx, si
mov si, 1000h
sub word [cur_limit], cx
sbb word [cur_limit+2], 0
rep movsb
mov bx, di
call normalize
.nopost:
clc
.ret2:
pop di
ret
.big:
mov ax, es
sub ax, 80h
mov es, ax
add bx, 800h
add bx, si
call normalize
sub [cur_limit], esi
jmp .nopost
 
; Callback function for secondary loader
callback:
; in: ax = function number; only function 1 is defined for now
dec ax
jz callback_readfile
dec ax
jz callback_continueread
stc ; unsupported function
retf
 
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
clc ; function is supported
retf
 
callback_continueread:
; function 2: continue to 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)
; out: bx=0 - ok, bx=1 - file is too big, only part of file was loaded, bx=3 - read error
; out: dx:ax = file size
les bx, [di]
call normalize
movzx esi, word [di+4] ; si = limit in 4K blocks
shl esi, 12 ; bp:si = limit in bytes
push cs
pop ds
mov [cur_limit], esi
mov di, [cur_chunk]
call loadloop.loadnew
clc ; function is supported
retf
 
secondary_loader_info:
dw 0, 0x1000
dw 0x30000 / 0x1000
db 'kord/loader',0
aKernelNotFound db 'Fatal error: cannot load the secondary loader',0
 
align 2
cachelist:
.head dw cachelist
.tail dw cachelist
free_cache_item dw 0
last_cache_item dw 0x8400
 
use_path_table db 0
bootdrive db ?
align 2
lb_size dw ? ; Logical Block size in bytes
dw 0 ; to allow access dword [lb_size]
lb_per_sec dw ? ; Logical Blocks per physical sector
dw 0 ; to allow access dword [lb_per_sec]
free_ptr dw ? ; first free block in cache (cache block = sector = 0x800 bytes)
size_rest dw ? ; free space in cache (in blocks)
cache_size dw ?
cache_start dw ?
pathtable_size dw ?
pathtable_start dw ?
root_location dd ?
cur_desc_end dw ?
cur_nocache_len dd ?
cur_limit dd ?
cur_unit_limit dd ?
overflow dw ?
cur_chunk dw ?
first_byte dw ?
cur_start dd ?
 
;times 83FEh-$ db 0
db 43h
; just to make file 2048 bytes long :)
db 'd' xor 'i' xor 'a' xor 'm' xor 'o' xor 'n' xor 'd'
 
dw 0xAA55 ; this is not required for CD, but to be consistent...
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/cdfs/bootsect.txt
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. Если же нет, то считываются все сектора, кроме последнего, после чего
последний сектор считывается отдельно во временную область, и уже
оттуда нужная часть данных копируется в буфер.
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/cdfs/build.bat
0,0 → 1,2
@fasm -m 65535 bootsect.asm bootsect.bin
@pause
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/cdfs
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/PrimaryLoader.txt
0,0 → 1,91
; 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.
Загрузчик должен предоставлять следующие сервисы:
1. При загрузке компьютера, получив управление от BIOS'а, загружать
файл loader из папки kord по адресу 1000:0000.
Размер файла loader не превосходит 30000h = 192 Kb.
2. При этом устанавливать следующие регистры:
ax идентифицирует устройство:
al = тип:
'f' - флопик
'h' - HDD
'c' - CD/DVD
'u' - USB флешка
'?' - неизвестное устройство
ah = номер устройства (среди всех устройств фиксированного типа)
bx = тип файловой системы:
'12' = FAT12
'16' = FAT16
'32' = FAT32
'nt' = NTFS
'is' = ISO-9660
ds:si = far-указатель на callback-сервис
3. Предоставлять callback-сервис для вторичного загрузчика - far-процедуру:
на входе: ax = запрашиваемая функция
на выходе: CF=1, если функция не поддерживается; CF=0 иначе
Загрузчик может разрушать все регистры, включая сегментные,
за исключением ss и sp.
4. Всегда должна поддерживаться callback-функция 1:
назначение: прочитать файл, расположенный на загрузочном устройстве
на входе: ax = 1, ds:di = указатель на информационную структуру:
dw:dw far-указатель на буфер,
первое слово - смещение, второе - сегмент
dw максимальное число 4Kb-блоков для чтения (0x1000 байт)
должно быть ненулевым и строго меньше 0x100
ASCIIZ имя файла в формате "<папка1>/<папка2>/<файл>"
Если имя файла содержит символы из старшей половины
ASCIIZ-таблицы или не является 8.3-именем (в смысле, одна из компонент
имени файла имеет имя длиннее 8 символов или расширение длиннее 3),
загрузчик может не найти такой файл, даже если он есть
(а может и найти).
на выходе: bx = статус:
0 = успешно
1 = файл оказался слишком большим, буфер заполнен целиком
и есть ещё данные файла
2 = файл не найден
3 = произошла ошибка чтения
dx:ax = размер файла или FFFF:FFFF, если файл не найден
5. Всегда должна поддерживаться callback-функция 2:
назначение: продолжить чтение файла, частично загруженного функцией 1
на входе: ax = 2, ds:di = указатель на информационную структуру:
dw:dw far-указатель на буфер,
первое слово - смещение, второе - сегмент
dw максимальное число 4Kb-блоков для чтения (0x1000 байт)
должно быть ненулевым и строго меньше 0x100
на выходе: bx = статус:
0 = успешно
1 = файл оказался слишком большим, буфер заполнен целиком
и есть ещё данные файла
3 = произошла ошибка чтения
dx:ax = размер файла
Функцию можно вызывать только в случае, когда последний вызов функции
1 и все последующие вызовы функции 2 вернули bx=1 (иными словами,
только для продолжения загрузки файла, который уже был частично
загружен, но ещё не загружен полностью).
Загрузчик может быть уверен, что данные в областях памяти 0-9000 и
60000-A0000 не будут модифицированы ядром.
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/after_win/kordldr.win.txt
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. Добавляет сектор в конец списка (самый новый вход).
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/after_win/fat.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/after_win/kordldr.win.asm
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 'kord/loader',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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/after_win/ntfs.inc
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/after_win/build.bat
0,0 → 1,2
@fasm -m 65535 kordldr.win.asm kordldr.win
@pause
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/after_win
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat1x/bootsect.txt
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.
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat1x/bootsect.asm
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat1x/kordldr.f1x.asm
0,0 → 1,668
; 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
; calculate starting sector
xchg ax, cx
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 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 'kord/loader',0
aKernelNotFound db 'Fatal error: cannot load the secondary loader',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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat1x/build.bat
0,0 → 1,3
@fasm -m 65535 bootsect.asm bootsect.bin
@fasm -m 65535 kordldr.f1x.asm kordldr.f1x
@pause
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat1x
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat32/bootsect.txt
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.
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat32/bootsect.asm
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 = 0
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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat32/kordldr.f32.asm
0,0 → 1,672
; 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
push ss
pop ds
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
push es
pushad
lea cx, [di + 0x10000 - 0x8400 + (0x6000 shr (9-3))] ; +0x10000 - for FASM
shl cx, 9-3
mov es, cx
xor bx, bx
mov cx, 1
add eax, [bp-6] ; FAT start
sub eax, [bp-10]
call [read_sectors2]
popad
pop es
@@:
; 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-3))]
pop di
and di, 0x7F
shl di, 2
shl ax, 9-3
mov ds, ax
and byte [di+3], 0x0F
mov eax, [di]
pop 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 ; 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-14-2 ; restore stack
mov dx, 3 ; return: read error
@@:
mov bx, dx
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 'kord/loader',0
aKernelNotFound db 'Fatal error: cannot load the secondary loader',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
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat32/build.bat
0,0 → 1,3
@fasm -m 65535 bootsect.asm bootsect.bin
@fasm -m 65535 kordldr.f32.asm kordldr.f32
@pause
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/fat32
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/mkfloppy.inc
0,0 → 1,91
; ---------------------------------------------------------------------------
; mkfloppy.inc
; ---------------------------------------------------------------------------
; Created by Phantom-84
; ---------------------------------------------------------------------------
 
FA_RO equ 01h
FA_HID equ 02h
FA_SYS equ 04h
FA_VOL equ 08h
FA_DIR equ 10h
FA_ARC equ 20h
 
DSTAMP equ 28C1h
TSTAMP equ 6000h
 
root_size=0
 
macro reset id
{
local count, cur, disp, val, var
times 511-($+511) mod 512 db 0
if id#_size>0
count=(id#_size+511)/512
cur=id#_base/512-(33-2)
repeat count
if %=count
val=0FFFh
else
val=cur+1
end if
if cur and 1
val=val shl 4
end if
disp=(cur*3)/2
load var word from 512+disp
var=var or val
store word var at 512+disp
store word var at 10*512+disp
cur=cur+1
end repeat
end if
}
 
macro dent id, name, attr
{
@@ db name
times @b+11-$ db 32
db attr
dw 0, TSTAMP, DSTAMP, DSTAMP, 0, TSTAMP, DSTAMP
if id#_size=0
dw 0
else
dw id#_base/512-(33-2)
end if
if (attr) and FA_DIR
dd 0
else
dd id#_size
end if
}
 
macro orgdir id, parentid
{
id#_base:
dent id, ".", FA_DIR
dent parentid, "..", FA_DIR
}
 
macro findir id
{
id#_size=$-id#_base
reset id
}
 
macro stod id, parentid
{
orgdir id, parentid
id
findir id
}
 
macro stof id, name
{
id#_base:
file name
id#_size=$-id#_base
reset id
}
 
defdir fix macro
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/build.bat
0,0 → 1,20
echo off
cls
echo ** bulding after win loader **
@fasm -m 65535 after_win/kordldr.win.asm after_win/kordldr.win
echo ==============================
echo ** building first loader for cd/dvd **
@fasm -m 65535 cdfs/bootsect.asm cdfs/bootsect.bin
echo ==============================
echo ** building first loader for fat12/fat16 **
@fasm -m 65535 fat1x/bootsect.asm fat1x/bootsect.bin
@fasm -m 65535 fat1x/kordldr.f1x.asm fat1x/kordldr.f1x
echo ==============================
echo ** building firs loader for fat32 **
@fasm -m 65535 fat32/bootsect.asm fat32/bootsect.bin
@fasm -m 65535 fat32/kordldr.f1x.asm fat32/kordldr.f1x
echo ==============================
echo ** make a image of fdd **
@fasm -m 65535 floppy.asc kord.img
 
@pause
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot/floppy.asc
0,0 → 1,49
include "mkfloppy.inc"
;// insert boot sect
file "fat1x/bootsect.bin", 512
 
; fat1
db 0F0h, 0FFh, 0FFh, 9*512-3 dup 0
; fat2
db 0F0h, 0FFh, 0FFh, 9*512-3 dup 0
 
; root
dent kordldr, "KORDLDR F1X", FA_ARC
dent kord, "KORD ",FA_DIR
dent kolibri, "KOLIBRI ",FA_DIR
; ...
 
rb 33*512-$
;///////////////////////////
defdir kord
{
dent loader, "LOADER ", FA_ARC
dent ini,"STARTOS INI", FA_ARC
}
 
defdir kolibri
{
dent kolibri_ldm, "KOLIBRI LDM", FA_ARC
}
 
 
; data
stof kordldr, "fat1x/kordldr.f1x"
stod kord,root
 
stof loader, "../loader"
stof ini,"../startos.ini"
 
store dword ini_base/512+1 at ini_base+1F8h
store word (ini_size+511)/512-1 at ini_base+1FCh
store word 220h at ini_base+1FEh
 
stod kolibri,root
stof kolibri_ldm, "../kolibri_ldm/bin/kolibri.ldm"
store dword kolibri_ldm_base/512+1 at kolibri_ldm_base+1F8h
store word (kolibri_ldm_size+511)/512-1 at kolibri_ldm_base+1FCh
store word 220h at kolibri_ldm_base+1FEh
 
 
; ...
rb 2*80*18*512-$
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/loader.lst
0,0 → 1,2147
flat assembler version 1.68 (65535 kilobytes memory)
0000: E9 E1 0A jmp start
0003: 53 65 63 6F 6E 64 61 72 79 20 4C 6F 61 version db 'Secondary Loader v 0.009', 0
0010: 64 65 72 20 76 20 30 2E 30 30 39 00
001C: 53 65 6C 65 63 74 20 73 65 63 74 69 6F select_section db 'Select section:'
0029: 6E 3A
002B: 53 65 63 74 69 6F 6E 20 64 65 73 63 72 section_description db 'Section description:'
0038: 69 70 74 69 6F 6E 3A
003F: 53 6F 66 74 20 28 63 29 20 32 30 30 38 soft_mes db 'Soft (c) 2008'
004C: 3E 46 61 74 61 6C 20 2D 20 43 50 55 20 badprocessor db '>Fatal - CPU 586+ required.', 0
0059: 35 38 36 2B 20 72 65 71 75 69 72 65 64
0066: 2E 00
0068: 3E 45 72 72 6F 72 3A 20 63 61 6E 6E 6F error_ini_f1 db '>Error: cannot load ini file, buffer is full', 0
0075: 74 20 6C 6F 61 64 20 69 6E 69 20 66 69
0082: 6C 65 2C 20 62 75 66 66 65 72 20 69 73
008F: 20 66 75 6C 6C 00
0095: 3E 45 72 72 6F 72 3A 20 69 6E 69 20 66 error_ini_f2 db '>Error: ini file not found', 0
00A2: 69 6C 65 20 6E 6F 74 20 66 6F 75 6E 64
00AF: 00
00B0: 3E 45 72 72 6F 72 3A 20 63 61 6E 6E 6F error_ini_f3 db '>Error: cannot read ini file', 0
00BD: 74 20 72 65 61 64 20 69 6E 69 20 66 69
00CA: 6C 65 00
00CD: 3E 45 72 72 6F 72 3A 20 75 6E 72 65 63 error_ini_nf db '>Error: unrecognized error when loading ini file', 0
00DA: 6F 67 6E 69 7A 65 64 20 65 72 72 6F 72
00E7: 20 77 68 65 6E 20 6C 6F 61 64 69 6E 67
00F4: 20 69 6E 69 20 66 69 6C 65 00
00FE: 3E 4E 6F 74 20 66 6F 75 6E 64 20 73 65 not_found_sec_loader db '>Not found section [loader]', 0
010B: 63 74 69 6F 6E 20 5B 6C 6F 61 64 65 72
0118: 5D 00
011A: 3E 4E 6F 74 20 66 6F 75 6E 64 20 76 61 not_found_def_sect db '>Not found value default in section [loader]', 0
0127: 6C 75 65 20 64 65 66 61 75 6C 74 20 69
0134: 6E 20 73 65 63 74 69 6F 6E 20 5B 6C 6F
0141: 61 64 65 72 5D 00
0147: 3E 45 72 72 6F 72 20 69 6E 20 73 65 63 default_eq_loader db '>Error in section [loader] parametr default=loader', 0
0154: 74 69 6F 6E 20 5B 6C 6F 61 64 65 72 5D
0161: 20 70 61 72 61 6D 65 74 72 20 64 65 66
016E: 61 75 6C 74 3D 6C 6F 61 64 65 72 00
017A: 3E 46 6F 75 6E 64 20 65 71 75 61 6C 20 found_equal_default db '>Found equal parametr default will be use first value', 0
0187: 70 61 72 61 6D 65 74 72 20 64 65 66 61
0194: 75 6C 74 20 77 69 6C 6C 20 62 65 20 75
01A1: 73 65 20 66 69 72 73 74 20 76 61 6C 75
01AE: 65 00
01B0: 3E 46 6F 75 6E 64 20 65 71 75 61 6C 20 found_equal_timeout db '>Found equal parametr timeout will be use first value', 0
01BD: 70 61 72 61 6D 65 74 72 20 74 69 6D 65
01CA: 6F 75 74 20 77 69 6C 6C 20 62 65 20 75
01D7: 73 65 20 66 69 72 73 74 20 76 61 6C 75
01E4: 65 00
01E6: 3E 53 65 63 74 69 6F 6E 20 74 69 6D 65 set_default_timeout_val db '>Section timeout has incorrect value, will be use default value', 0
01F3: 6F 75 74 20 68 61 73 20 69 6E 63 6F 72
0200: 72 65 63 74 20 76 61 6C 75 65 2C 20 77
020D: 69 6C 6C 20 62 65 20 75 73 65 20 64 65
021A: 66 61 75 6C 74 20 76 61 6C 75 65 00
0226: 3E 49 20 77 69 6C 6C 20 75 73 65 20 70 error_ini_common db '>I will use predefined settings and try to boot. Let's hope for the best...'
0233: 72 65 64 65 66 69 6E 65 64 20 73 65 74
0240: 74 69 6E 67 73 20 61 6E 64 20 74 72 79
024D: 20 74 6F 20 62 6F 6F 74 2E 20 4C 65 74
025A: 27 73 20 68 6F 70 65 20 66 6F 72 20 74
0267: 68 65 20 62 65 73 74 2E 2E 2E
0271: 0D 0A 50 72 65 73 73 20 61 6E 79 20 6B db 13, 10, 'Press any key to continue...', 0
027E: 65 79 20 74 6F 20 63 6F 6E 74 69 6E 75
028B: 65 2E 2E 2E 00
0290: 3E 49 6E 69 20 66 69 6C 65 20 6C 6F 61 load_ini db '>Ini file loaded successfully', 0
029D: 64 65 64 20 73 75 63 63 65 73 73 66 75
02AA: 6C 6C 79 00
02AE: 3E 45 6E 64 20 70 61 72 73 69 6E 67 20 parse_ini_end db '>End parsing ini file', 0
02BB: 69 6E 69 20 66 69 6C 65 00
02C4: 3E 50 6F 69 6E 74 20 74 6F 20 64 65 66 point_to_default_sec_not_found db '>Point to default section is not found in ini file', 0
02D1: 61 75 6C 74 20 73 65 63 74 69 6F 6E 20
02DE: 69 73 20 6E 6F 74 20 66 6F 75 6E 64 20
02EB: 69 6E 20 69 6E 69 20 66 69 6C 65 00
02F7: 3E 49 6E 63 6F 72 65 63 74 20 73 65 63 incorect_section_define db '>Incorect section define not found ']'', 0
0304: 74 69 6F 6E 20 64 65 66 69 6E 65 20 6E
0311: 6F 74 20 66 6F 75 6E 64 20 27 5D 27 00
031E: 22 53 65 63 74 69 6F 6E 20 75 6E 6E 61 default_section_name db '"Section unname"'
032B: 6D 65 22
032E: 50 72 65 73 73 20 61 6E 79 20 6B 65 79 start_msg db 'Press any key to change default section, press [Enter] to continue booting'
033B: 20 74 6F 20 63 68 61 6E 67 65 20 64 65
0348: 66 61 75 6C 74 20 73 65 63 74 69 6F 6E
0355: 2C 20 70 72 65 73 73 20 5B 45 6E 74 65
0362: 72 5D 20 74 6F 20 63 6F 6E 74 69 6E 75
036F: 65 20 62 6F 6F 74 69 6E 67
0378: 6F 72 20 77 61 69 74 20 34 20 73 65 63 time_msg db 'or wait 4 seconds before default continuation'
0385: 6F 6E 64 73 20 62 65 66 6F 72 65 20 64
0392: 65 66 61 75 6C 74 20 63 6F 6E 74 69 6E
039F: 75 61 74 69 6F 6E
03A5: 73 65 63 6F 6E 64 73 20 62 65 66 6F 72 time_str db 'seconds before default continuation'
03B2: 65 20 64 65 66 61 75 6C 74 20 63 6F 6E
03BF: 74 69 6E 75 61 74 69 6F 6E
03C8: 53 65 74 20 73 74 61 63 6B 20 26 20 73 stack_msg db 'Set stack & segments is have completed', 0
03D5: 65 67 6D 65 6E 74 73 20 69 73 20 68 61
03E2: 76 65 20 63 6F 6D 70 6C 65 74 65 64 00
03EF: 48 61 76 65 20 6C 6F 61 64 65 64 20 73 show_string db 'Have loaded size:'
03FC: 69 7A 65 3A
0400: 20 20 20 20 20 20 00 show_decode db ' ', 0
0407: 20 20 20 20 20 20 20 2D 4D 65 73 73 61 show_db1 db ' -Message debug1', 0
0414: 67 65 20 64 65 62 75 67 31 00
041E: 20 20 20 20 20 20 20 2D 4D 65 73 73 61 show_db2 db ' -Message debug2', 0
042B: 67 65 20 64 65 62 75 67 32 00
0435: 5B 6C 6F 61 64 65 72 5D 20 69 73 20 66 lm_l_found db '[loader] is found', 0
0442: 6F 75 6E 64 00
0447: 74 69 6D 65 6F 75 74 20 69 73 20 66 6F lm_lf_timeout db 'timeout is found', 0
0454: 75 6E 64 00
0458: 6E 61 6D 65 20 64 65 66 61 75 6C 74 20 lm_lf_default db 'name default is found and end parsing section', 0
0465: 69 73 20 66 6F 75 6E 64 20 61 6E 64 20
0472: 65 6E 64 20 70 61 72 73 69 6E 67 20 73
047F: 65 63 74 69 6F 6E 00
0486: 66 6F 75 6E 64 20 73 65 63 74 69 6F 6E lm_lf_section db 'found section [', 0
0493: 20 5B 00
0496: 66 6F 75 6E 64 20 64 65 66 61 75 6C 74 lm_lf_default_f db 'found default parametr', 0
04A3: 20 70 61 72 61 6D 65 74 72 00
04AD: 73 65 63 74 69 6F 6E 20 5B 6C 6F 61 64 lm_l_end db 'section [loader] is end', 0
04BA: 65 72 5D 20 69 73 20 65 6E 64 00
04C5: 53 48 4F 57 20 41 4C 4C 20 53 65 63 74 show_all_sect db 'SHOW ALL Sections', 0
04D2: 69 6F 6E 73 00
04D7: 4E 6F 74 20 73 68 6F 77 20 73 65 63 74 no_show_only_w db 'Not show sections - only work on default sect', 0
04E4: 69 6F 6E 73 20 2D 20 6F 6E 6C 79 20 77
04F1: 6F 72 6B 20 6F 6E 20 64 65 66 61 75 6C
04FE: 74 20 73 65 63 74 00
0505: 5B 20 6E 6F 74 20 66 6F 75 6E 64 00 _not_found db '[ not found', 0
0511: 5B 5D 20 66 6F 75 6E 64 00 _found_1 db '[] found', 0
051A: 5B 20 66 6F 75 6E 64 00 _found_2 db '[ found', 0
0522: 48 65 6C 6C 6F 20 24 29 00 say_hello db 'Hello $)', 0
052B: 53 74 61 72 74 20 75 73 65 5F 52 61 6D ramdiskFS_st db 'Start use_RamdiskFS macros', 0
0538: 64 69 73 6B 46 53 20 6D 61 63 72 6F 73
0545: 00
0546: 20 20 20 20 20 20 20 2D 4B 62 20 61 76 free_memory_msg db ' -Kb availability system free memory', 0
0553: 61 69 6C 61 62 69 6C 69 74 79 20 73 79
0560: 73 74 65 6D 20 66 72 65 65 20 6D 65 6D
056D: 6F 72 79 00
0571: 20 20 20 20 20 20 20 2D 4B 62 20 65 71 RamdiskSize_msg db ' -Kb equal RamdiskSize', 0
057E: 75 61 6C 20 52 61 6D 64 69 73 6B 53 69
058B: 7A 65 00
058E: 20 20 20 20 20 20 20 20 2D 62 79 74 73 RamdiskSector_msg db ' -byts RamdiskSector', 0
059B: 20 52 61 6D 64 69 73 6B 53 65 63 74 6F
05A8: 72 00
05AA: 20 20 20 20 20 20 20 2D 52 61 6D 64 69 RamdiskCluster_msg db ' -RamdiskCluster', 0
05B7: 73 6B 43 6C 75 73 74 65 72 00
05C1: 20 20 20 20 20 20 20 2D 73 69 7A 65 20 RamdiskFile_msg db ' -size RamdiskFile', 0
05CE: 52 61 6D 64 69 73 6B 46 69 6C 65 00
05DA: 20 20 20 20 20 20 20 2D 66 69 72 73 74 fat_create_msg db ' -first create fat table, point to next block', 0
05E7: 20 63 72 65 61 74 65 20 66 61 74 20 74
05F4: 61 62 6C 65 2C 20 70 6F 69 6E 74 20 74
0601: 6F 20 6E 65 78 74 20 62 6C 6F 63 6B 00
060E: 20 20 20 20 20 20 20 2D 69 6E 20 62 79 BPB_msg db ' -in byte, why we get data from move BPB struct', 0
061B: 74 65 2C 20 77 68 79 20 77 65 20 67 65
0628: 74 20 64 61 74 61 20 66 72 6F 6D 20 6D
0635: 6F 76 65 20 42 50 42 20 73 74 72 75 63
0642: 74 00
0644: 20 20 20 20 20 20 20 2D 66 69 72 73 74 firstDataSect_msg db ' -first data sector, offset to data in sectors', 0
0651: 20 64 61 74 61 20 73 65 63 74 6F 72 2C
065E: 20 6F 66 66 73 65 74 20 74 6F 20 64 61
066B: 74 61 20 69 6E 20 73 65 63 74 6F 72 73
0678: 00
0679: 20 20 20 20 20 20 20 2D 73 69 7A 65 20 size_root_dir_msg db ' -size root dir in sectrors', 0
0686: 72 6F 6F 74 20 64 69 72 20 69 6E 20 73
0693: 65 63 74 72 6F 72 73 00
069B: 20 20 20 20 20 20 20 2D 73 69 7A 65 20 DataClasters_msg db ' -size data in Clasters', 0
06A8: 64 61 74 61 20 69 6E 20 43 6C 61 73 74
06B5: 65 72 73 00
06B9: 20 20 20 20 20 20 20 2D 69 66 20 2D 31 check_name_fat_msg db ' -if -1 name is present, else 0 then not present name', 0
06C6: 20 6E 61 6D 65 20 69 73 20 70 72 65 73
06D3: 65 6E 74 2C 20 65 6C 73 65 20 30 20 74
06E0: 68 65 6E 20 6E 6F 74 20 70 72 65 73 65
06ED: 6E 74 20 6E 61 6D 65 00
06F5: 20 20 20 20 20 20 20 2D 69 66 20 2D 31 convertion_file_name_msg db ' -if -1, then destination name is bad', 0
0702: 2C 20 74 68 65 6E 20 64 65 73 74 69 6E
070F: 61 74 69 6F 6E 20 6E 61 6D 65 20 69 73
071C: 20 62 61 64 00
0721: 2D 4D 61 6B 65 20 46 41 54 31 32 20 52 make_fat12_RFS_msg db '-Make FAT12 Ram FS', 0
072E: 61 6D 20 46 53 00
0734: 2D 45 6E 64 20 6D 61 6B 65 20 52 61 6D get_type_FS_msg db '-End make RamDisk', 0
0741: 44 69 73 6B 00
0746: 20 20 20 20 2D 72 65 74 75 72 6E 20 63 return_code_af_move db ' -return code after 0x87 int 0x15, move block', 0
0753: 6F 64 65 20 61 66 74 65 72 20 30 78 38
0760: 37 20 69 6E 74 20 30 78 31 35 2C 20 6D
076D: 6F 76 65 20 62 6C 6F 63 6B 00
0777: 20 20 20 20 2D 72 65 74 75 72 6E 20 63 return_code_af_fat_m db ' -return code after 0x87 int 0x15, move fat struc', 0
0784: 6F 64 65 20 61 66 74 65 72 20 30 78 38
0791: 37 20 69 6E 74 20 30 78 31 35 2C 20 6D
079E: 6F 76 65 20 66 61 74 20 73 74 72 75 63
07AB: 00
07AC: 5B 6C 6F 61 64 65 72 5D parse_loader db '[loader]'
07B4: 74 69 6D 65 6F 75 74 parse_l_timeout db 'timeout'
07BB: 64 65 66 61 75 6C 74 parse_l_default db 'default'
07C2: 61 6D 65 parse_name db 'ame'
07C5: 64 65 73 63 72 69 70 74 parse_descript db 'descript'
07CD: 4C 6F 61 64 65 72 4D 6F 64 75 6C 65 parse_LoaderModule db 'LoaderModule'
07D9: 52 61 6D 64 69 73 6B 53 69 7A 65 parse_RamdiskSize db 'RamdiskSize'
07E4: 52 61 6D 64 69 73 6B 46 53 parse_RamdiskFS db 'RamdiskFS'
07ED: 52 61 6D 64 69 73 6B 53 65 63 74 6F 72 parse_RamdiskSector db 'RamdiskSector'
07FA: 52 61 6D 64 69 73 6B 43 6C 75 73 74 65 parse_RamdiskCluster db 'RamdiskCluster'
0807: 72
0808: 46 41 54 parse_RFS_FAT db 'FAT'
080B: 4B 52 46 53 parse_RFS_KRFS db 'KRFS'
080F: 4C 6F 61 64 65 72 49 6D 61 67 65 parse_Loader_Image db 'LoaderImage'
081A: 52 61 6D 64 69 73 6B 46 69 6C 65 parse_RamdiskFile db 'RamdiskFile'
0825: 66 39 C8 cmp eax, ecx
0828: 72 0D jb @f
082A: 66 31 D2 xor edx, edx
082D: 66 F7 F1 div ecx
0830: 66 52 push edx
0832: E8 F0 FF call decode
0835: 66 58 pop eax
0837: 0C 30 or al, 0x30
0839: 88 05 mov [ ds : di ], al
083B: 47 inc di
083C: C3 ret
083D: B4 0E mov ah, 0Eh
083F: B7 00 mov bh, 0
0841: CD 10 int 10h
0843: C3 ret
0844: 60 pusha
0845: AC lodsb
0846: E8 F4 FF call putchar
0849: AC lodsb
084A: 3C 00 cmp al, 0
084C: 75 F8 jnz @b
084E: B0 0D mov al, 13
0850: E8 EA FF call putchar
0853: B0 0A mov al, 10
0855: E8 E5 FF call putchar
0858: 61 popa
0859: C3 ret
085A: B4 00 mov ah, 0
085C: CD 16 int 16h
085E: 38 D8 cmp al, bl
0860: 72 F8 jb getkey
0862: 38 F8 cmp al, bh
0864: 77 F4 ja getkey
0866: 50 push ax
0867: E8 D3 FF call putchar
086A: 58 pop ax
086B: 83 E0 0F and ax, 0Fh
086E: 75 02 jnz @f
0870: B0 0A mov al, 10
0872: C3 ret
0873: 26 8A 05 mov al, byte [ es : di ]
0876: 47 inc di
0877: 49 dec cx
0878: E3 20 jcxz .exit
087A: 3C 0A cmp al, 0xa
087C: 74 0A jz ._entry
087E: 3C 3B cmp al, ';'
0880: 75 F1 jnz .start
0882: B0 0A mov al, 0xa
0884: F2 repnz
0885: AE scasb
0886: E3 12 jcxz .exit
0888: 26 8A 05 mov al, byte [ es : di ]
088B: 3C 20 cmp al, ' '
088D: 75 07 jnz .not_space
088F: F3 repe
0890: AE scasb
0891: 4F dec di
0892: 41 inc cx
0893: 26 8A 05 mov al, byte [ es : di ]
0896: 3C 3B cmp al, ';'
0898: 74 E8 jz .first_com
089A: C3 ret
089B: 56 push si
089C: 68 00 20 push ini_data_
089F: 07 pop es
08A0: B0 5D mov al, ']'
08A2: F2 repnz
08A3: AE scasb
08A4: 85 C9 test cx, cx
08A6: 0F 84 0F 02 jz error.incorect_section_def
08AA: B0 6E mov al, 'n'
08AC: F2 repnz
08AD: AE scasb
08AE: E3 69 jcxz .not_name_sec_fb
08B0: BE C2 07 mov si, parse_name
08B3: 51 push cx
08B4: 57 push di
08B5: B9 03 00 mov cx, parse_name_e - parse_name
08B8: F3 repe
08B9: A6 cmpsb
08BA: 5F pop di
08BB: 59 pop cx
08BC: 74 02 jz .yaaa_find_value
08BE: EB EC jmp .find_val_name_fb
08C0: 83 E9 03 sub cx, parse_name_e - parse_name
08C3: 83 C7 03 add di, parse_name_e - parse_name
08C6: B8 20 3D mov ax, 0x3d20
08C9: F3 repe
08CA: AE scasb
08CB: 85 C9 test cx, cx
08CD: 74 4A jz .not_name_sec_fb
08CF: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
08D3: 75 D5 jnz .find_val_name_fb1
08D5: F3 repe
08D6: AE scasb
08D7: 41 inc cx
08D8: 4F dec di
08D9: 06 push es
08DA: 1F pop ds
08DB: 68 00 B8 push 0xb800
08DE: 07 pop es
08DF: 31 C0 xor ax, ax
08E1: B8 20 07 mov ax, 0x0720
08E4: B9 27 00 mov cx, 39
08E7: 89 FE mov si, di
08E9: 89 D7 mov di, dx
08EB: 83 EF 02 sub di, 2
08EE: F3 rep
08EF: AB stosw
08F0: 89 D7 mov di, dx
08F2: B4 0F mov ah, color_sym_white
08F4: B9 24 00 mov cx, 36
08F7: AC lodsb
08F8: 83 EF 02 sub di, 2
08FB: 3C 22 cmp al, '"'
08FD: 74 04 jz @f
08FF: 3C 27 cmp al, '''
0901: 75 12 jnz .end_sh_name_sec
0903: AC lodsb
0904: AB stosw
0905: AC lodsb
0906: 3C 22 cmp al, '"'
0908: 74 0B jz .end_sh_name_sec
090A: 3C 27 cmp al, '''
090C: 74 07 jz .end_sh_name_sec
090E: E2 F4 loop @b
0910: B0 7D mov al, '}'
0912: B4 0E mov ah, color_sym_yellow
0914: AB stosw
0915: 0E push cs
0916: 1F pop ds
0917: 5E pop si
0918: C3 ret
0919: 0E push cs
091A: 1F pop ds
091B: BF 1E 03 mov di, default_section_name
091E: EB BB jmp .def_sect_name
0920: 8B 7E F4 mov di, point_default
0923: 68 00 20 push ini_data_
0926: 07 pop es
0927: 89 F9 mov cx, di
0929: 89 CB mov bx, cx
092B: FD std
092C: B0 0A mov al, 0xa
092E: F2 repnz
092F: AE scasb
0930: E3 25 jcxz .go_
0932: 89 7E C6 mov find_sec_di, di
0935: 89 F9 mov cx, di
0937: 29 CB sub bx, cx
0939: 89 D9 mov cx, bx
093B: FC cld
093C: E8 34 FF call get_firs_sym
093F: E3 0D jcxz ._not_section
0941: 3B 7E F6 cmp di, point_loader
0944: 74 08 jz ._not_section
0946: 3C 5B cmp al, '['
0948: 75 04 jnz ._not_section
094A: 89 7E F4 mov point_default, di
094D: C3 ret
094E: 8B 7E C6 mov di, find_sec_di
0951: 89 F9 mov cx, di
0953: 89 CB mov bx, cx
0955: EB D4 jmp .find_start_section
0957: FC cld
0958: 89 D9 mov cx, bx
095A: 26 8A 05 mov al, byte [ es : di ]
095D: 68 6A 09 push word .f_go
0960: 3C 20 cmp al, ' '
0962: 74 03 jz @f
0964: E9 2F FF jmp get_firs_sym.not_space
0967: E9 21 FF jmp get_firs_sym.first_sp
096A: E3 E1 jcxz .exit_scan_sect
096C: 3B 7E F6 cmp di, point_loader
096F: 74 DC jz .exit_scan_sect
0971: 3C 5B cmp al, '['
0973: 75 D8 jnz .exit_scan_sect
0975: 89 7E F4 mov point_default, di
0978: C3 ret
0979: 8B 7E F4 mov di, point_default
097C: 68 00 20 push ini_data_
097F: 07 pop es
0980: 8B 4E FE mov cx, save_cx
0983: 29 F9 sub cx, di
0985: EB 17 jmp .let_s_go
0987: 68 00 20 push ini_data_
098A: 07 pop es
098B: 8B 4E FE mov cx, save_cx
098E: 26 8A 05 mov al, byte [ es : di ]
0991: 68 A1 09 push word .let_s_go_ret
0994: 3C 20 cmp al, ' '
0996: 74 03 jz @f
0998: E9 FB FE jmp get_firs_sym.not_space
099B: E9 ED FE jmp get_firs_sym.first_sp
099E: E8 D2 FE call get_firs_sym
09A1: E3 0C jcxz .exit_scan_sect
09A3: 3C 5B cmp al, '['
09A5: 75 F7 jnz .let_s_go
09A7: 3B 7E F6 cmp di, point_loader
09AA: 74 F2 jz .let_s_go
09AC: 89 7E F4 mov point_default, di
09AF: C3 ret
09B0: 8D 76 F2 lea si, point_to_hframe
09B3: BF 22 03 mov di, 962 - 160
09B6: 8B 56 F4 mov dx, point_default
09B9: B9 12 00 mov cx, 18
09BC: 8B 1C mov bx, [ si ]
09BE: 81 C7 A0 00 add di, 160
09C2: 39 D3 cmp bx, dx
09C4: 74 05 jz .clean_cursor_
09C6: 83 EE 02 sub si, 2
09C9: E2 F1 loop .clean_show_cur
09CB: 68 00 B8 push 0xb800
09CE: 07 pop es
09CF: 50 push ax
09D0: 89 76 CA mov point_to_point_def, si
09D3: 31 C0 xor ax, ax
09D5: B8 20 07 mov ax, 0x0720
09D8: AB stosw
09D9: 83 C7 44 add di, 68
09DC: AB stosw
09DD: 58 pop ax
09DE: C3 ret
09DF: B4 00 mov ah, 0
09E1: CD 1A int 1Ah
09E3: 91 xchg ax, cx
09E4: 66 C1 E0 10 shl eax, 10h
09E8: 92 xchg ax, dx
09E9: C3 ret
09EA: 1E push ds
09EB: 0E push cs
09EC: 1F pop ds
09ED: 9C pushf
09EE: FF 1E D4 1A call far dword [ old_timer ]
09F2: 66 60 pushad
09F4: E8 E8 FF call gettime
09F7: 66 2B 06 D8 1A sub eax, dword [ start_timer ]
09FC: 8B 1E D2 1A mov bx, word [ value_timeout ]
0A00: 6B DB 12 imul bx, 18
0A03: 29 C3 sub bx, ax
0A05: 76 1F jbe .timergo
0A07: 06 push es
0A08: 68 00 B8 push 0xb800
0A0B: 07 pop es
0A0C: 89 D8 mov ax, bx
0A0E: BB 12 00 mov bx, 18
0A11: 31 D2 xor dx, dx
0A13: F7 F3 div bx
0A15: BB 0A 00 mov bx, 10
0A18: BF 96 0E mov di, 3734
0A1B: E8 24 00 call .decode
0A1E: 31 C0 xor ax, ax
0A20: AB stosw
0A21: 07 pop es
0A22: 66 61 popad
0A24: 1F pop ds
0A25: CF iret
0A26: 6A 00 push 0
0A28: 07 pop es
0A29: 66 A1 D4 1A mov eax, dword [ old_timer ]
0A2D: 26 66 A3 20 00 mov [ es : 8 * 4 ], eax
0A32: 66 A3 DC 1A mov dword [ timer_ ], eax
0A36: 8B 26 E0 1A mov sp, word [ start_stack ]
0A3A: 8B 2E E2 1A mov bp, word [ save_bp_from_timer ]
0A3E: FB sti
0A3F: E9 D8 06 jmp parse_start.parse_run_only
0A42: 39 D8 cmp ax, bx
0A44: 72 09 jb @f
0A46: 31 D2 xor dx, dx
0A48: F7 F3 div bx
0A4A: 52 push dx
0A4B: E8 F4 FF call .decode
0A4E: 58 pop ax
0A4F: 0C 30 or al, 0x30
0A51: 50 push ax
0A52: B4 09 mov ah, 9
0A54: AB stosw
0A55: 58 pop ax
0A56: C3 ret
0A57: 8B 5E C8 mov bx, point_to_eframe
0A5A: 8D 76 F2 lea si, point_to_hframe
0A5D: BA C6 03 mov dx, 966
0A60: 39 DE cmp si, bx
0A62: 72 12 jb ._show_space_fb
0A64: 8B 3C mov di, [ si ]
0A66: 83 EE 02 sub si, 2
0A69: 8B 0C mov cx, [ si ]
0A6B: 29 F9 sub cx, di
0A6D: E8 2B FE call show_name_section
0A70: 81 C2 A0 00 add dx, 160
0A74: EB EA jmp .home_show_fb
0A76: 83 EA 04 sub dx, 4
0A79: 68 00 B8 push 0xb800
0A7C: 07 pop es
0A7D: 81 FA 64 0E cmp dx, 0xE64
0A81: 77 12 ja .exit_show_fb
0A83: 89 D7 mov di, dx
0A85: 31 C0 xor ax, ax
0A87: B8 20 07 mov ax, 0x0720
0A8A: B9 27 00 mov cx, 39
0A8D: F3 rep
0A8E: AB stosw
0A8F: 81 C2 A0 00 add dx, 160
0A93: EB E8 jmp @b
0A95: C3 ret
0A96: 89 C7 mov di, ax
0A98: 89 D9 mov cx, bx
0A9A: FF 66 FC jmp ret_on_ch
0A9D: C9 leave
0A9E: BE 1A 01 mov si, not_found_def_sect
0AA1: E9 F4 00 jmp err_show_ini
0AA4: C9 leave
0AA5: BE FE 00 mov si, not_found_sec_loader
0AA8: E9 ED 00 jmp err_show_ini
0AAB: C9 leave
0AAC: BE 47 01 mov si, default_eq_loader
0AAF: E9 E6 00 jmp err_show_ini
0AB2: C9 leave
0AB3: BE C4 02 mov si, point_to_default_sec_not_found
0AB6: E9 DF 00 jmp err_show_ini
0AB9: C9 leave
0ABA: BE F7 02 mov si, incorect_section_define
0ABD: E9 D8 00 jmp err_show_ini
0AC0: 68 00 B8 push word 0xb800
0AC3: 07 pop es
0AC4: C3 ret
0AC5: 00 00 00 20 file_data dw 0x0, ini_data_
0AC9: 10 00 size_data dw 16
0ACB: 6B 6F 72 64 2F 73 74 61 72 74 6F 73 2E name_ini_f db 'kord/startos.ini', 0
0AD8: 69 6E 69 00
0ADC: 00 00 00 00 loader_callback dd ?
0AE0: 00 00 load_drive dw ?
0AE2: 00 00 load_ft dw ?
0AE4: 2E 89 36 DC 0A mov word [ cs : loader_callback ], si
0AE9: 2E 8C 1E DE 0A mov word [ cs : loader_callback + 2 ], ds
0AEE: 2E A3 E0 0A mov word [ cs : load_drive ], ax
0AF2: 2E 89 1E E2 0A mov word [ cs : load_ft ], bx
0AF7: 8C C8 mov ax, cs
0AF9: 8E D0 mov ss, ax
0AFB: 31 E4 xor sp, sp
0AFD: 8E D8 mov ds, ax
0AFF: 8E C0 mov es, ax
0B01: FC cld
0B02: FB sti
0B03: B8 03 00 mov ax, 3
0B06: CD 10 int 0x10
0B08: BE 03 00 mov si, version
0B0B: E8 36 FD call printplain
0B0E: B0 23 mov al, '#'
0B10: B9 50 00 mov cx, 80
0B13: E8 27 FD call putchar
0B16: E2 FB loop @b
0B18: BE C8 03 mov si, stack_msg
0B1B: E8 26 FD call printplain
0B1E: 31 DB xor bx, bx
0B20: 8E DB mov ds, bx
0B22: FF 77 1A push word [ bx + 6 * 4 + 2 ]
0B25: FF 77 18 push word [ bx + 6 * 4 ]
0B28: C7 47 18 4A 0B mov word [ bx + 6 * 4 ], ud16
0B2D: 8C 4F 1A mov word [ bx + 6 * 4 + 2 ], cs
0B30: 66 31 C0 xor eax, eax
0B33: 0F A2 cpuid
0B35: 66 85 C0 test eax, eax
0B38: 74 10 jz cpubad
0B3A: 66 31 C0 xor eax, eax
0B3D: 40 inc ax
0B3E: 0F A2 cpuid
0B40: F6 C2 10 test dl, 10h
0B43: 74 05 jz cpubad
0B45: F6 C2 20 test dl, 20h
0B48: 75 12 jnz cpugood
0B4A: 8F 06 18 00 pop word [ 6 * 4 ]
0B4E: 8F 06 1A 00 pop word [ 6 * 4 + 2 ]
0B52: 0E push cs
0B53: 1F pop ds
0B54: BE 4C 00 mov si, badprocessor
0B57: E8 EA FC call printplain
0B5A: EB FE jmp $
0B5C: 66 8F 06 18 00 pop dword [ 6 * 4 ]
0B61: 0E push cs
0B62: 1F pop ds
0B63: 66 0F B7 E4 movzx esp, sp
0B67: B9 03 00 mov cx, loop_read_startos_file
0B6C: 31 C0 xor ax, ax
0B6E: BF C5 0A mov di, file_data
0B71: 40 inc ax
0B72: 51 push cx
0B73: FF 1E DC 0A call far dword [ loader_callback ]
0B77: 59 pop cx
0B78: 0E push cs
0B79: 0E push cs
0B7A: 1F pop ds
0B7B: 07 pop es
0B7C: 85 DB test bx, bx
0B7E: 74 28 jz check_conf_file
0B80: 49 dec cx
0B81: 75 E9 jnz load_startos_file
0B83: BE 68 00 mov si, error_ini_f1
0B86: 4B dec bx
0B87: 74 0F jz err_show_ini
0B89: BE 95 00 mov si, error_ini_f2
0B8C: 4B dec bx
0B8D: 74 09 jz err_show_ini
0B8F: BE B0 00 mov si, error_ini_f3
0B92: 4B dec bx
0B93: 74 03 jz err_show_ini
0B95: BE CD 00 mov si, error_ini_nf
0B98: E8 A9 FC call printplain
0B9B: BE 26 02 mov si, error_ini_common
0B9E: E8 A3 FC call printplain
0BA1: 31 C0 xor ax, ax
0BA3: CD 16 int 16h
0BA5: EB FE jmp $
0BA8: 50 push ax
0BA9: B9 0A 00 mov cx, 0x0a
0BAC: BF 00 04 mov di, show_decode
0BAF: E8 73 FC call decode
0BB2: BE EF 03 mov si, show_string
0BB5: E8 8C FC call printplain
0BB8: BE 90 02 mov si, load_ini
0BBB: E8 86 FC call printplain
0BBE: 59 pop cx
0BBF: C8 00 01 00 enter 256, 0
0BC3: 89 2E E2 1A mov word [ save_bp_from_timer ], bp
0BC7: 89 4E FE mov save_cx, cx
0BCA: C4 3E C5 0A les di, dword [ file_data ]
0BCE: 31 C0 xor ax, ax
0BD0: 89 46 F8 mov status_flag, ax
0BD3: C7 46 C4 00 30 mov info_real_mode_size, ini_data_ + 0x1000
0BD8: FC cld
0BD9: C7 46 FC EE 0B mov ret_on_ch, .start
0BDE: 26 8A 05 mov al, byte [ es : di ]
0BE1: 68 F1 0B push word .first_ret
0BE4: 3C 20 cmp al, ' '
0BE6: 74 03 jz .first_sp_1
0BE8: E9 AB FC jmp get_firs_sym.not_space
0BEB: E9 9D FC jmp get_firs_sym.first_sp
0BEE: E8 82 FC call get_firs_sym
0BF1: 85 C9 test cx, cx
0BF3: 0F 84 AD FE jz error.not_loader
0BF7: 3C 5B cmp al, '['
0BF9: 74 02 jz .parse_loader
0BFB: EB F1 jmp .start
0BFD: 89 CB mov bx, cx
0BFF: 89 F8 mov ax, di
0C01: BE AC 07 mov si, parse_loader
0C04: B9 08 00 mov cx, parse_loader_e - parse_loader
0C07: F3 repe
0C08: A6 cmpsb
0C09: 0F 85 89 FE jnz error.rest_value
0C0D: 89 46 F6 mov point_loader, ax
0C10: 83 EB 08 sub bx, parse_loader_e - parse_loader
0C13: 01 CB add bx, cx
0C15: 89 D9 mov cx, bx
0C17: 60 pusha
0C18: BE 35 04 mov si, lm_l_found
0C1B: E8 26 FC call printplain
0C1E: 61 popa
0C1F: 89 FA mov dx, di
0C21: E8 4F FC call get_firs_sym
0C24: E3 04 jcxz .loader_f_end
0C26: 3C 5B cmp al, '['
0C28: 75 F7 jnz @b
0C2A: 29 CB sub bx, cx
0C2C: 89 D7 mov di, dx
0C2E: 89 D9 mov cx, bx
0C30: C7 46 FC 35 0C mov ret_on_ch, .get_next_str
0C35: E8 3B FC call get_firs_sym
0C38: 85 C9 test cx, cx
0C3A: 0F 84 57 01 jz .end_loader
0C3E: 3C 74 cmp al, 't'
0C40: 0F 84 DE 00 jz .loader_timeout
0C44: 3C 64 cmp al, 'd'
0C46: 75 ED jnz .get_next_str
0C48: 89 CB mov bx, cx
0C4A: 89 F8 mov ax, di
0C4C: BE BB 07 mov si, parse_l_default
0C4F: B9 07 00 mov cx, parse_l_default_e - parse_l_default
0C52: F3 repe
0C53: A6 cmpsb
0C54: 0F 85 3E FE jnz error.rest_value
0C58: 83 EB 07 sub bx, parse_l_default_e - parse_l_default
0C5B: 01 CB add bx, cx
0C5D: 89 D9 mov cx, bx
0C5F: F7 46 F8 01 00 test status_flag, flag_found_default
0C64: 74 08 jz .correct_is_not_set
0C66: BE 7A 01 mov si, found_equal_default
0C69: E8 D8 FB call printplain
0C6C: EB C7 jmp .get_next_str
0C6E: B8 20 3D mov ax, 0x3d20
0C71: F3 repe
0C72: AE scasb
0C73: 85 C9 test cx, cx
0C75: 0F 84 1C 01 jz .end_loader
0C79: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
0C7D: 75 B6 jnz .get_next_str
0C7F: F3 repe
0C80: AE scasb
0C81: 41 inc cx
0C82: 4F dec di
0C83: 89 CB mov bx, cx
0C85: 89 FA mov dx, di
0C87: 26 8A 05 mov al, byte [ es : di ]
0C8A: 47 inc di
0C8B: 49 dec cx
0C8C: 85 C9 test cx, cx
0C8E: 0F 84 0B FE jz error.error_get_size_d_sect
0C92: 3C 20 cmp al, ' '
0C94: 74 F1 jz @b
0C96: 3C 0D cmp al, 0xd
0C98: 74 04 jz .found_size_d_sect
0C9A: 3C 0A cmp al, 0xa
0C9C: 75 E9 jnz @b
0C9E: 41 inc cx
0C9F: 89 D8 mov ax, bx
0CA1: 29 CB sub bx, cx
0CA3: 89 5E FA mov save_cx_d, bx
0CA6: 89 D7 mov di, dx
0CA8: 89 D9 mov cx, bx
0CAA: 89 C3 mov bx, ax
0CAC: 89 D0 mov ax, dx
0CAE: BE AC 07 mov si, parse_loader
0CB1: 46 inc si
0CB2: F3 repe
0CB3: A6 cmpsb
0CB4: 75 03 jnz .check_section
0CB6: E9 F2 FD jmp error.default_eq_loader
0CB9: 89 D9 mov cx, bx
0CBB: 89 C7 mov di, ax
0CBD: 89 FE mov si, di
0CBF: 57 push di
0CC0: 51 push cx
0CC1: 8B 4E FE mov cx, save_cx
0CC4: C4 3E C5 0A les di, dword [ file_data ]
0CC8: 26 8A 05 mov al, byte [ es : di ]
0CCB: 68 DB 0C push word .first_ret_d
0CCE: 3C 20 cmp al, ' '
0CD0: 74 03 jz .first_sp_1_d
0CD2: E9 C1 FB jmp get_firs_sym.not_space
0CD5: E9 B3 FB jmp get_firs_sym.first_sp
0CD8: E8 98 FB call get_firs_sym
0CDB: E3 38 jcxz .correct_exit
0CDD: 3C 5B cmp al, '['
0CDF: 74 02 jz .found_sect_d
0CE1: EB F5 jmp .start_d
0CE3: 89 CB mov bx, cx
0CE5: 89 F8 mov ax, di
0CE7: 56 push si
0CE8: 8B 4E FA mov cx, save_cx_d
0CEB: 06 push es
0CEC: 1F pop ds
0CED: 47 inc di
0CEE: F3 repe
0CEF: A6 cmpsb
0CF0: 0E push cs
0CF1: 1F pop ds
0CF2: 5E pop si
0CF3: 75 1A jnz .not_compare_d_s
0CF5: 26 80 3D 5D cmp byte [ es : di ], ']'
0CF9: 75 14 jnz .not_compare_d_s
0CFB: 83 4E F8 01 or status_flag, flag_found_default
0CFF: 59 pop cx
0D00: 5F pop di
0D01: 89 46 F4 mov point_default, ax
0D04: 60 pusha
0D05: BE 96 04 mov si, lm_lf_default_f
0D08: E8 39 FB call printplain
0D0B: 61 popa
0D0C: E9 26 FF jmp .get_next_str
0D0F: 89 D9 mov cx, bx
0D11: 89 C7 mov di, ax
0D13: EB C3 jmp .start_d
0D15: 59 pop cx
0D16: 5F pop di
0D17: 60 pusha
0D18: BE 58 04 mov si, lm_lf_default
0D1B: E8 26 FB call printplain
0D1E: 61 popa
0D1F: E9 13 FF jmp .get_next_str
0D22: 89 CB mov bx, cx
0D24: 89 F8 mov ax, di
0D26: BE B4 07 mov si, parse_l_timeout
0D29: B9 07 00 mov cx, parse_l_timeout_e - parse_l_timeout
0D2C: F3 repe
0D2D: A6 cmpsb
0D2E: 0F 85 64 FD jnz error.rest_value
0D32: 83 EB 07 sub bx, parse_l_timeout_e - parse_l_timeout
0D35: 01 CB add bx, cx
0D37: 89 D9 mov cx, bx
0D39: F7 46 F8 02 00 test status_flag, flag_found_timeout
0D3E: 74 09 jz .correct_is_not_set_t
0D40: BE B0 01 mov si, found_equal_timeout
0D43: E8 FE FA call printplain
0D46: E9 EC FE jmp .get_next_str
0D49: B8 20 3D mov ax, 0x3d20
0D4C: F3 repe
0D4D: AE scasb
0D4E: E3 35 jcxz .timeout_sec_end_d
0D50: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
0D54: 0F 85 DD FE jnz .get_next_str
0D58: F3 repe
0D59: AE scasb
0D5A: 41 inc cx
0D5B: 4F dec di
0D5C: 51 push cx
0D5D: 31 DB xor bx, bx
0D5F: B9 02 00 mov cx, 2
0D62: 26 8A 05 mov al, byte [ es : di ]
0D65: 3C 30 cmp al, '0'
0D67: 72 0B jb .end_get_val_t
0D69: 3C 39 cmp al, '9'
0D6B: 77 07 ja .end_get_val_t
0D6D: 6B DB 0A imul bx, 10
0D70: 34 30 xor al, 0x30
0D72: 00 C3 add bl, al
0D74: 47 inc di
0D75: E2 EB loop @b
0D77: 89 1E D2 1A mov word [ value_timeout ], bx
0D7B: 60 pusha
0D7C: BE 47 04 mov si, lm_lf_timeout
0D7F: E8 C2 FA call printplain
0D82: 61 popa
0D83: EB 0C jmp @f
0D85: C7 06 D2 1A 05 00 mov word [ value_timeout ], default_timeout_value
0D8B: BE E6 01 mov si, set_default_timeout_val
0D8E: E8 B3 FA call printplain
0D91: 59 pop cx
0D92: E9 A0 FE jmp .get_next_str
0D95: 60 pusha
0D96: BE AD 04 mov si, lm_l_end
0D99: E8 A8 FA call printplain
0D9C: 61 popa
0D9D: 31 C0 xor ax, ax
0D9F: CD 16 int 16h
0DA1: 60 pusha
0DA2: A1 D2 1A mov ax, word [ value_timeout ]
0DA5: B9 0A 00 mov cx, 0x0a
0DA8: BF 07 04 mov di, show_db1
0DAB: 66 C7 05 20 20 20 20 mov dword [ ds : di ], ' '
0DB2: C7 45 04 20 20 mov word [ ds : di + 4 ], ' '
0DB7: E8 6B FA call decode
0DBA: BE 07 04 mov si, show_db1
0DBD: E8 84 FA call printplain
0DC0: 61 popa
0DC1: 85 C0 test ax, ax
0DC3: 0F 84 53 03 jz .parse_run_only
0DC7: 60 pusha
0DC8: BE C5 04 mov si, show_all_sect
0DCB: E8 76 FA call printplain
0DCE: 61 popa
0DCF: B0 F6 mov al, 0xf6
0DD1: E6 60 out 0x60, al
0DD3: 31 C9 xor cx, cx
0DD5: E4 64 in al, 64h
0DD7: 24 02 and al, 00000010b
0DD9: E0 FA loopnz .wait_loop
0DDB: B0 F3 mov al, 0xf3
0DDD: E6 60 out 0x60, al
0DDF: 31 C9 xor cx, cx
0DE1: E4 64 in al, 64h
0DE3: A8 02 test al, 2
0DE5: E0 FA loopnz @b
0DE7: B0 00 mov al, 0
0DE9: E6 60 out 0x60, al
0DEB: 31 C9 xor cx, cx
0DED: E4 64 in al, 64h
0DEF: A8 02 test al, 2
0DF1: E0 FA loopnz @b
0DF3: E8 E9 FB call gettime
0DF6: 66 A3 D8 1A mov dword [ start_timer ], eax
0DFA: C7 06 DC 1A EA 09 mov word [ timer_ ], newtimer
0E00: 8C 0E DE 1A mov word [ timer_ + 2 ], cs
0E04: FA cli
0E05: 6A 00 push 0
0E07: 07 pop es
0E08: 26 66 FF 36 20 00 push dword [ es : 8 * 4 ]
0E0E: 66 8F 06 D4 1A pop dword [ old_timer ]
0E13: 66 FF 36 DC 1A push dword [ timer_ ]
0E18: 26 66 8F 06 20 00 pop dword [ es : 8 * 4 ]
0E1E: FB sti
0E1F: C7 46 BE 12 00 mov save_descript_size, 18
0E24: 31 C0 xor ax, ax
0E26: B8 20 07 mov ax, 0x0720
0E29: 68 00 B8 push 0xb800
0E2C: 07 pop es
0E2D: 31 FF xor di, di
0E2F: B9 D0 07 mov cx, 25 * 80
0E32: F3 rep
0E33: AB stosw
0E34: BF A4 00 mov di, 164
0E37: BE 03 00 mov si, version
0E3A: B9 19 00 mov cx, version_end - version
0E3D: B4 0E mov ah, color_sym_yellow
0E3F: AC lodsb
0E40: AB stosw
0E41: E2 FC loop @b
0E43: BF 1E 01 mov di, 286
0E46: B4 0C mov ah, color_sym_pink
0E48: B0 4B mov al, 'K'
0E4A: AB stosw
0E4B: B0 20 mov al, ' '
0E4D: AB stosw
0E4E: B4 07 mov ah, color_sym_lightgray
0E50: BE 3F 00 mov si, soft_mes
0E53: B9 0D 00 mov cx, soft_mes_end - soft_mes
0E56: AC lodsb
0E57: AB stosw
0E58: E2 FC loop @b
0E5A: BF E0 01 mov di, 480
0E5D: B4 0E mov ah, color_sym_yellow
0E5F: B0 C4 mov al, 0xC4
0E61: B9 3D 00 mov cx, 61
0E64: F3 rep
0E65: AB stosw
0E66: BF 24 03 mov di, 804
0E69: BE 1C 00 mov si, select_section
0E6C: B9 0F 00 mov cx, select_section_end - select_section
0E6F: B4 07 mov ah, color_sym_lightgray
0E71: AC lodsb
0E72: AB stosw
0E73: E2 FC loop @b
0E75: BF 70 03 mov di, 880
0E78: BE 2B 00 mov si, section_description
0E7B: B9 14 00 mov cx, section_description_end - section_description
0E7E: AC lodsb
0E7F: AB stosw
0E80: E2 FC loop @b
0E82: 8B 4E FE mov cx, save_cx
0E85: C4 3E C5 0A les di, dword [ file_data ]
0E89: 89 FE mov si, di
0E8B: 89 CB mov bx, cx
0E8D: BA 12 00 mov dx, size_show_section
0E90: 26 8A 05 mov al, byte [ es : di ]
0E93: 68 B9 0E push word .first_ret_bl_sc
0E96: 3C 20 cmp al, ' '
0E98: 74 03 jz .first_bl_sc
0E9A: E9 F9 F9 jmp get_firs_sym.not_space
0E9D: E9 EB F9 jmp get_firs_sym.first_sp
0EA0: E8 D0 F9 call get_firs_sym
0EA3: 85 C9 test cx, cx
0EA5: 0F 84 09 FC jz error.correct_exit_bl
0EA9: 3C 5B cmp al, '['
0EAB: 75 F3 jnz .start_hbl
0EAD: 89 FE mov si, di
0EAF: 89 CB mov bx, cx
0EB1: BA 12 00 mov dx, size_show_section
0EB4: EB 09 jmp .analisist_al
0EB6: E8 BA F9 call get_firs_sym
0EB9: 85 C9 test cx, cx
0EBB: 0F 84 F3 FB jz error.correct_exit_bl
0EBF: 3C 5B cmp al, '['
0EC1: 75 F3 jnz .start_bl
0EC3: 3B 7E F6 cmp di, point_loader
0EC6: 74 EE jz .start_bl
0EC8: 3B 7E F4 cmp di, point_default
0ECB: 74 05 jz .save_point_def
0ECD: 4A dec dx
0ECE: 75 E6 jnz .start_bl
0ED0: EB CE jmp .start_hbl
0ED2: 89 F7 mov di, si
0ED4: 89 D9 mov cx, bx
0ED6: 8D 76 F2 lea si, point_to_hframe
0ED9: BA 13 00 mov dx, size_show_section + 1
0EDC: 26 8A 05 mov al, byte [ es : di ]
0EDF: 68 EF 0E push word .first_ret_mfb
0EE2: 3C 20 cmp al, ' '
0EE4: 74 03 jz .first_bl_mbf
0EE6: E9 AD F9 jmp get_firs_sym.not_space
0EE9: E9 9F F9 jmp get_firs_sym.first_sp
0EEC: E8 84 F9 call get_firs_sym
0EEF: E3 13 jcxz .val_buff_comp
0EF1: 3C 5B cmp al, '['
0EF3: 75 F7 jnz .start_mfb
0EF5: 3B 7E F6 cmp di, point_loader
0EF8: 74 F2 jz .start_mfb
0EFA: 89 3C mov [ si ], di
0EFC: 83 EE 02 sub si, 2
0EFF: 4A dec dx
0F00: 75 EA jnz .start_mfb
0F02: EB 08 jmp @f
0F04: FF 76 FE push save_cx
0F07: 8F 04 pop word [ si ]
0F09: 83 EE 02 sub si, 2
0F0C: 83 C6 04 add si, 4
0F0F: 89 76 C8 mov point_to_eframe, si
0F12: E8 42 FB call show_bl_sc_sect
0F15: 8D 76 F2 lea si, point_to_hframe
0F18: BF 22 03 mov di, 962 - 160
0F1B: 8B 46 F4 mov ax, point_default
0F1E: B9 12 00 mov cx, size_show_section
0F21: 8B 1C mov bx, [ si ]
0F23: 81 C7 A0 00 add di, 160
0F27: 39 C3 cmp bx, ax
0F29: 74 05 jz .show_cursor_activ
0F2B: 83 EE 02 sub si, 2
0F2E: E2 F1 loop .home_show_cur
0F30: 89 76 CA mov point_to_point_def, si
0F33: B8 10 04 mov ax, ( color_sym_red * 0x100 + 0x10 )
0F36: AB stosw
0F37: 83 C7 44 add di, 68
0F3A: 40 inc ax
0F3B: AB stosw
0F3C: 8B 7E F4 mov di, point_default
0F3F: 68 00 20 push ini_data_
0F42: 8B 76 CA mov si, point_to_point_def
0F45: 07 pop es
0F46: 83 EE 02 sub si, 2
0F49: 8B 0C mov cx, [ si ]
0F4B: 29 F9 sub cx, di
0F4D: E8 23 F9 call get_firs_sym
0F50: 85 C9 test cx, cx
0F52: 0F 84 91 00 jz .exit?0Pz
0F56: 3C 64 cmp al, 'd'
0F58: 75 F3 jnz .start_p_sh_d?0Py
0F5A: 89 CB mov bx, cx
0F5C: 89 F8 mov ax, di
0F5E: BE C5 07 mov si, parse_descript
0F61: B9 08 00 mov cx, parse_descript_e - parse_descript
0F64: F3 repe
0F65: A6 cmpsb
0F66: 75 78 jnz .rest_value_loop_sh_d?0Q0
0F68: 83 EB 08 sub bx, parse_descript_e - parse_descript
0F6B: 01 CB add bx, cx
0F6D: 89 D9 mov cx, bx
0F6F: B8 20 3D mov ax, 0x3d20
0F72: F3 repe
0F73: AE scasb
0F74: E3 6A jcxz .rest_value_loop_sh_d?0Q0
0F76: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
0F7A: 75 64 jnz .rest_value_loop_sh_d?0Q0
0F7C: F3 repe
0F7D: AE scasb
0F7E: 41 inc cx
0F7F: 4F dec di
0F80: 57 push di
0F81: 5E pop si
0F82: 06 push es
0F83: 1F pop ds
0F84: 68 00 B8 push 0xb800
0F87: 07 pop es
0F88: BF 10 04 mov di, 1040
0F8B: BB 12 00 mov bx, 18
0F8E: 89 7E C6 mov find_sec_di, di
0F91: 89 5E FA mov save_cx_d, bx
0F94: 57 push di
0F95: 31 C0 xor ax, ax
0F97: B9 26 00 mov cx, 38
0F9A: 57 push di
0F9B: F3 rep
0F9C: AB stosw
0F9D: 5F pop di
0F9E: 39 5E BE cmp save_descript_size, bx
0FA1: 74 07 jz @f
0FA3: 81 C7 A0 00 add di, 160
0FA7: 4B dec bx
0FA8: 75 ED jnz @b
0FAA: 5F pop di
0FAB: AC lodsb
0FAC: B4 0A mov ah, color_sym_lettuce
0FAE: 3C 22 cmp al, '"'
0FB0: 74 04 jz .loop_message?0Q2
0FB2: 3C 27 cmp al, '''
0FB4: 75 20 jnz .end_sh_desc_sec?0Q1
0FB6: B9 26 00 mov cx, 38
0FB9: AC lodsb
0FBA: 3C 22 cmp al, '"'
0FBC: 74 18 jz .end_sh_desc_sec?0Q1
0FBE: 3C 27 cmp al, '''
0FC0: 74 14 jz .end_sh_desc_sec?0Q1
0FC2: AB stosw
0FC3: E2 F4 loop @b
0FC5: 81 46 C6 A0 00 add find_sec_di, 160
0FCA: 8B 7E C6 mov di, find_sec_di
0FCD: FF 4E FA dec save_cx_d
0FD0: 83 7E FA 00 cmp save_cx_d, 0
0FD4: 75 E0 jnz .loop_message?0Q2
0FD6: FF 76 FA push save_cx_d
0FD9: 8F 46 BE pop save_descript_size
0FDC: 0E push cs
0FDD: 1F pop ds
0FDE: EB 07 jmp .exit?0Pz
0FE0: 89 C7 mov di, ax
0FE2: 89 D9 mov cx, bx
0FE4: E9 66 FF jmp .start_p_sh_d?0Py
0FE7: 66 A1 D4 1A mov eax, dword [ old_timer ]
0FEB: 66 3B 06 DC 1A cmp eax, dword [ timer_ ]
0FF0: 74 5E jz .interrupt_16
0FF2: 31 C0 xor ax, ax
0FF4: BF 20 0D mov di, 3360
0FF7: B9 40 01 mov cx, 80 * 4
0FFA: F3 rep
0FFB: AB stosw
0FFC: BF 22 0D mov di, 3362
0FFF: B4 0C mov ah, color_sym_pink
1001: B0 DA mov al, 0xDA
1003: AB stosw
1004: B0 C4 mov al, 0xc4
1006: B9 4C 00 mov cx, 76
1009: F3 rep
100A: AB stosw
100B: B0 BF mov al, 0xBF
100D: AB stosw
100E: 83 C7 04 add di, 4
1011: B0 B3 mov al, 0xb3
1013: AB stosw
1014: 81 C7 98 00 add di, 152
1018: AB stosw
1019: 83 C7 04 add di, 4
101C: AB stosw
101D: 81 C7 98 00 add di, 152
1021: AB stosw
1022: 83 C7 04 add di, 4
1025: B0 C0 mov al, 0xc0
1027: AB stosw
1028: B0 C4 mov al, 0xc4
102A: B9 4C 00 mov cx, 76
102D: F3 rep
102E: AB stosw
102F: B0 D9 mov al, 0xd9
1031: AB stosw
1032: BE 2E 03 mov si, start_msg
1035: B9 4A 00 mov cx, start_msg_e - start_msg
1038: BF C6 0D mov di, 3526
103B: AC lodsb
103C: AB stosw
103D: E2 FC loop @b
103F: 83 C7 2C add di, 44
1042: BE 78 03 mov si, time_msg
1045: B9 2D 00 mov cx, time_msg_e - time_msg
1048: AC lodsb
1049: AB stosw
104A: E2 FC loop @b
104C: 89 26 E0 1A mov word [ start_stack ], sp
1050: 31 C0 xor ax, ax
1052: CD 16 int 0x16
1054: 66 8B 1E D4 1A mov ebx, dword [ old_timer ]
1059: 66 3B 1E DC 1A cmp ebx, dword [ timer_ ]
105E: 74 2A jz @f
1060: FA cli
1061: 6A 00 push 0
1063: 07 pop es
1064: 26 66 89 1E 20 00 mov [ es : 8 * 4 ], ebx
106A: 66 89 1E DC 1A mov dword [ timer_ ], ebx
106F: FB sti
1070: 50 push ax
1071: 68 00 B8 push 0xb800
1074: 07 pop es
1075: 31 C0 xor ax, ax
1077: B8 20 07 mov ax, 0x0720
107A: BF 20 0D mov di, 3360
107D: B9 40 01 mov cx, 80 * 4
1080: F3 rep
1081: AB stosw
1082: 68 00 20 push ini_data_
1085: 07 pop es
1086: E8 CE F9 call show_bl_sc_sect
1089: 58 pop ax
108A: E8 23 F9 call clean_active_cursor
108D: 80 FC 48 cmp ah, 0x48
1090: 74 21 jz .up
1092: 80 FC 50 cmp ah, 0x50
1095: 74 3A jz .down
1097: 80 FC 49 cmp ah, 0x49
109A: 74 53 jz .pgup
109C: 80 FC 51 cmp ah, 0x51
109F: 74 5B jz .pgdown
10A1: 80 FC 47 cmp ah, 0x47
10A4: 74 63 jz .home
10A6: 80 FC 4F cmp ah, 0x4f
10A9: 74 66 jz .end
10AB: 3C 0D cmp al, 0xD
10AD: 0F 85 64 FE jnz .show_active_cursor
10B1: EB 6F jmp .end_show_all
10B3: 8B 76 CA mov si, point_to_point_def
10B6: 83 C6 02 add si, 2
10B9: 8D 46 F2 lea ax, point_to_hframe
10BC: 39 C6 cmp si, ax
10BE: 77 0B ja @f
10C0: 89 76 CA mov point_to_point_def, si
10C3: 8B 04 mov ax, [ si ]
10C5: 89 46 F4 mov point_default, ax
10C8: E9 4A FE jmp .show_active_cursor
10CB: E8 52 F8 call find_before_sect
10CE: E9 B1 FD jmp .show_all_scr
10D1: 8B 76 CA mov si, point_to_point_def
10D4: 8B 46 C8 mov ax, point_to_eframe
10D7: 83 EE 02 sub si, 2
10DA: 39 C6 cmp si, ax
10DC: 72 0B jb @f
10DE: 89 76 CA mov point_to_point_def, si
10E1: 8B 04 mov ax, [ si ]
10E3: 89 46 F4 mov point_default, ax
10E6: E9 2C FE jmp .show_active_cursor
10E9: E8 8D F8 call find_next_sect
10EC: E9 93 FD jmp .show_all_scr
10EF: B9 12 00 mov cx, size_show_section
10F2: 51 push cx
10F3: E8 2A F8 call find_before_sect
10F6: 59 pop cx
10F7: E2 F9 loop @b
10F9: E9 86 FD jmp .show_all_scr
10FC: B9 12 00 mov cx, size_show_section
10FF: 51 push cx
1100: E8 76 F8 call find_next_sect
1103: 59 pop cx
1104: E2 F9 loop @b
1106: E9 79 FD jmp .show_all_scr
1109: 31 FF xor di, di
110B: E8 79 F8 call find_next_sect.h
110E: E9 71 FD jmp .show_all_scr
1111: 8B 7E FE mov di, save_cx
1114: E8 0C F8 call find_before_sect.e
1117: E9 68 FD jmp .show_all_scr
111A: 60 pusha
111B: BE D7 04 mov si, no_show_only_w
111E: E8 23 F7 call printplain
1121: 61 popa
1122: 8B 7E F4 mov di, point_default
1125: 68 00 20 push ini_data_
1128: 07 pop es
1129: 8B 76 CA mov si, point_to_point_def
112C: 83 EE 02 sub si, 2
112F: 8B 0C mov cx, [ si ]
1131: 31 C0 xor ax, ax
1133: 29 F9 sub cx, di
1135: 89 4E FA mov save_cx_d, cx
1138: 89 46 F8 mov status_flag, ax
113B: BE 2B 05 mov si, ramdiskFS_st
113E: E8 03 F7 call printplain
1141: 31 C0 xor ax, ax
1143: 89 46 C0 mov show_errors_sect, ax
1146: B4 88 mov ah, 0x88
1148: CD 15 int 0x15
114A: 73 02 jnc ._support_function_use_free_memory
114C: 31 C0 xor ax, ax
114E: 89 46 C2 mov free_ad_memory, ax
1151: 60 pusha
1152: 66 0F B7 C0 movzx eax, ax
1156: B9 0A 00 mov cx, 0x0a
1159: BF 46 05 mov di, free_memory_msg
115C: 66 C7 05 20 20 20 20 mov dword [ ds : di ], ' '
1163: C7 45 04 20 20 mov word [ ds : di + 4 ], ' '
1168: E8 BA F6 call decode
116B: BE 46 05 mov si, free_memory_msg
116E: E8 D3 F6 call printplain
1171: 61 popa
1172: 8B 7E F4 mov di, point_default
1175: 8B 4E FA mov cx, save_cx_d
1178: E8 F8 F6 call get_firs_sym
117B: 85 C9 test cx, cx
117D: 74 6E jz ._end_parse_RS?0k2
117F: 3C 52 cmp al, 'R'
1181: 75 F5 jnz .start_p_RS?0ju
1183: 89 CB mov bx, cx
1185: 89 F8 mov ax, di
1187: BE D9 07 mov si, parse_RamdiskSize
118A: B9 0B 00 mov cx, parse_RamdiskSize_e - parse_RamdiskSize
118D: F3 repe
118E: A6 cmpsb
118F: 75 4C jnz .rest_value_loop_RS?0jz
1191: 83 EB 0B sub bx, parse_RamdiskSize_e - parse_RamdiskSize
1194: 01 CB add bx, cx
1196: 89 D9 mov cx, bx
1198: F7 46 F8 02 00 test status_flag, flag_found_RS
119D: 74 00 jz .correct_is_not_set_RS?0jv
119F: B8 20 3D mov ax, 0x3d20
11A2: F3 repe
11A3: AE scasb
11A4: E3 3D jcxz .end_get_RS_ERROR_1?0k0
11A6: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
11AA: 75 CC jnz .start_p_RS?0ju
11AC: F3 repe
11AD: AE scasb
11AE: 41 inc cx
11AF: 4F dec di
11B0: 31 DB xor bx, bx
11B2: B9 05 00 mov cx, 5
11B5: 26 8A 05 mov al, byte [ es : di ]
11B8: 3C 30 cmp al, '0'
11BA: 72 04 jb .CS?0jw
11BC: 3C 39 cmp al, '9'
11BE: 76 06 jbe .correct_val_RS?0jx
11C0: 3C 4B cmp al, 'K'
11C2: 74 0C jz .correct_size_RS?0jy
11C4: EB 23 jmp .end_get_RS_ERROR_2?0k1
11C6: 6B DB 0A imul bx, 10
11C9: 34 30 xor al, 0x30
11CB: 00 C3 add bl, al
11CD: 47 inc di
11CE: E2 E5 loop @b
11D0: 85 DB test bx, bx
11D2: 75 07 jnz @f
11D4: 83 4E C0 04 or show_errors_sect, show_error_3
11D8: BB 40 00 mov bx, 64
11DB: EB 10 jmp ._end_parse_RS?0k2
11DD: 89 C7 mov di, ax
11DF: 89 D9 mov cx, bx
11E1: EB 95 jmp .start_p_RS?0ju
11E3: 83 4E C0 01 or show_errors_sect, show_error_1
11E7: EB 04 jmp ._end_parse_RS?0k2
11E9: 83 4E C0 02 or show_errors_sect, show_error_2
11ED: 60 pusha
11EE: 66 0F B7 C3 movzx eax, bx
11F2: B9 0A 00 mov cx, 0x0a
11F5: BF 71 05 mov di, RamdiskSize_msg
11F8: 66 C7 05 20 20 20 20 mov dword [ ds : di ], ' '
11FF: C7 45 04 20 20 mov word [ ds : di + 4 ], ' '
1204: E8 1E F6 call decode
1207: BE 71 05 mov si, RamdiskSize_msg
120A: E8 37 F6 call printplain
120D: 61 popa
120E: 39 5E C2 cmp free_ad_memory, bx
1211: 0F 86 80 07 jbe ._not_memory_in_sys?0iL
1215: 66 0F B7 C3 movzx eax, bx
1219: 66 C1 E0 0A shl eax, 10
121D: 66 89 46 BA mov save_ramdisksize, eax
1221: 8B 7E F4 mov di, point_default
1224: 8B 4E FA mov cx, save_cx_d
1227: E8 49 F6 call get_firs_sym
122A: 85 C9 test cx, cx
122C: 0F 84 5D 07 jz ._end_parse_FRS
1230: 3C 52 cmp al, 'R'
1232: 75 F3 jnz .start_g_tpe_RFS
1234: 89 CB mov bx, cx
1236: 89 F8 mov ax, di
1238: BE E4 07 mov si, parse_RamdiskFS
123B: B9 09 00 mov cx, parse_RamdiskFS_e - parse_RamdiskFS
123E: F3 repe
123F: A6 cmpsb
1240: 0F 85 38 07 jnz .start_g_tpe_RFS_rest_v
1244: 83 EB 09 sub bx, parse_RamdiskFS_e - parse_RamdiskFS
1247: 01 CB add bx, cx
1249: 89 D9 mov cx, bx
124B: F7 46 F8 04 00 test status_flag, flag_found_GTRFMS
1250: 74 00 jz .correct_is_not_set_FRS
1252: B8 20 3D mov ax, 0x3d20
1255: F3 repe
1256: AE scasb
1257: 85 C9 test cx, cx
1259: 0F 84 26 07 jz .end_get_FRS_ERROR_1
125D: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
1261: 75 C4 jnz .start_g_tpe_RFS
1263: F3 repe
1264: AE scasb
1265: 41 inc cx
1266: 4F dec di
1267: 89 CB mov bx, cx
1269: 89 F8 mov ax, di
126B: BE 08 08 mov si, parse_RFS_FAT
126E: B9 03 00 mov cx, parse_RFS_FAT_e - parse_RFS_FAT
1271: F3 repe
1272: A6 cmpsb
1273: 0F 85 F7 06 jnz .krfs_cmp
1277: 8B 7E F4 mov di, point_default
127A: 8B 4E FA mov cx, save_cx_d
127D: E8 F3 F5 call get_firs_sym
1280: 85 C9 test cx, cx
1282: 74 54 jz .end_RamdiskSector
1284: 3C 52 cmp al, 'R'
1286: 75 F5 jnz .start_RamdiskSector
1288: 89 CB mov bx, cx
128A: 89 F8 mov ax, di
128C: BE ED 07 mov si, parse_RamdiskSector
128F: B9 0D 00 mov cx, parse_RamdiskSector_e - parse_RamdiskSector
1292: F3 repe
1293: A6 cmpsb
1294: 75 3C jnz .RamdiskSector_rest_val
1296: 83 EB 0D sub bx, parse_RamdiskSector_e - parse_RamdiskSector
1299: 01 CB add bx, cx
129B: 89 D9 mov cx, bx
129D: F7 46 F8 08 00 test status_flag, flag_found_RamdiskSector
12A2: 74 00 jz .correct_is_not_set_RamdiskSector
12A4: B8 20 3D mov ax, 0x3d20
12A7: F3 repe
12A8: AE scasb
12A9: E3 2D jcxz .end_get_RamS_ERROR_1
12AB: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
12AF: 75 CC jnz .start_RamdiskSector
12B1: F3 repe
12B2: AE scasb
12B3: 41 inc cx
12B4: 4F dec di
12B5: 31 DB xor bx, bx
12B7: B9 04 00 mov cx, 4
12BA: 26 0F B6 05 movzx ax, byte [ es : di ]
12BE: 3C 30 cmp al, '0'
12C0: 72 16 jb .end_RamdiskSector
12C2: 3C 39 cmp al, '9'
12C4: 77 12 ja .end_RamdiskSector
12C6: 6B DB 0A imul bx, 10
12C9: 34 30 xor al, 0x30
12CB: 01 C3 add bx, ax
12CD: 47 inc di
12CE: E2 EA loop @b
12D0: EB 06 jmp .end_RamdiskSector
12D2: 89 D9 mov cx, bx
12D4: 89 C7 mov di, ax
12D6: EB A5 jmp .start_RamdiskSector
12D8: 89 D8 mov ax, bx
12DA: 60 pusha
12DB: 66 0F B7 C3 movzx eax, bx
12DF: B9 0A 00 mov cx, 0x0a
12E2: BF 8E 05 mov di, RamdiskSector_msg
12E5: 66 C7 05 20 20 20 20 mov dword [ ds : di ], ' '
12EC: 66 C7 45 04 20 20 20 20 mov dword [ ds : di + 4 ], ' '
12F4: E8 2E F5 call decode
12F7: BE 8E 05 mov si, RamdiskSector_msg
12FA: E8 47 F5 call printplain
12FD: 61 popa
12FE: 3D 00 10 cmp ax, 4096
1301: 77 04 ja .RS1?0sn
1303: 85 C0 test ax, ax
1305: 75 06 jnz @f
1307: C7 06 87 1A 00 02 mov word [ fat12_buffer.BPB_BytsPerSec ], 512
130D: A3 87 1A mov word [ fat12_buffer.BPB_BytsPerSec ], ax
1310: 8B 7E F4 mov di, point_default
1313: 8B 4E FA mov cx, save_cx_d
1316: E8 5A F5 call get_firs_sym
1319: 85 C9 test cx, cx
131B: 74 47 jz .end_RamdiskCluster
131D: 3C 52 cmp al, 'R'
131F: 75 F5 jnz .start_RamdiskCluster
1321: 89 CB mov bx, cx
1323: 89 F8 mov ax, di
1325: BE FA 07 mov si, parse_RamdiskCluster
1328: B9 0E 00 mov cx, parse_RamdiskCluster_e - parse_RamdiskCluster
132B: F3 repe
132C: A6 cmpsb
132D: 75 2F jnz .RamdiskCluster_rest_val
132F: 83 EB 0E sub bx, parse_RamdiskCluster_e - parse_RamdiskCluster
1332: 01 CB add bx, cx
1334: 89 D9 mov cx, bx
1336: F7 46 F8 16 00 test status_flag, flag_found_RamdiskCluster
133B: 74 00 jz .correct_is_not_set_RamdiskCluster
133D: B8 20 3D mov ax, 0x3d20
1340: F3 repe
1341: AE scasb
1342: E3 20 jcxz .end_get_RamSC_ERROR_1
1344: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
1348: 75 CC jnz .start_RamdiskCluster
134A: F3 repe
134B: AE scasb
134C: 41 inc cx
134D: 4F dec di
134E: 26 0F B6 05 movzx ax, byte [ es : di ]
1352: 3C 30 cmp al, '0'
1354: 72 0E jb .end_RamdiskCluster
1356: 3C 39 cmp al, '9'
1358: 77 0A ja .end_RamdiskCluster
135A: 34 30 xor al, 0x30
135C: EB 06 jmp .end_RamdiskCluster
135E: 89 D9 mov cx, bx
1360: 89 C7 mov di, ax
1362: EB B2 jmp .start_RamdiskCluster
1364: 60 pusha
1365: B9 0A 00 mov cx, 0x0a
1368: BF AA 05 mov di, RamdiskCluster_msg
136B: E8 B7 F4 call decode
136E: BE AA 05 mov si, RamdiskCluster_msg
1371: E8 D0 F4 call printplain
1374: 61 popa
1375: 3C 80 cmp al, 128
1377: 77 6B ja @f
1379: A2 89 1A mov byte [ fat12_buffer.BPB_SecPerClus ], al
137C: 66 0F B7 06 87 1A movzx eax, word [ fat12_buffer.BPB_BytsPerSec ]
1382: 66 0F B6 1E 89 1A movzx ebx, byte [ fat12_buffer.BPB_SecPerClus ]
1388: 66 0F AF D8 imul ebx, eax
138C: 66 8B 46 BA mov eax, save_ramdisksize
1390: 66 99 cdq
1392: 66 F7 FB idiv ebx
1395: 66 3D F5 0F 00 00 cmp eax, 4085
139B: 0F 82 8E 00 jb .fat12?0so
139F: 66 3D F5 FF 00 00 cmp eax, 65525
13A5: 72 18 jb .fat16?0sp
13A7: C7 46 B4 20 00 mov set_ramfs, 32
13AC: C7 06 8A 1A 20 00 mov word [ fat12_buffer.BPB_RsvdSecCnt ], 32
13B2: 66 31 C0 xor eax, eax
13B5: A3 8D 1A mov word [ fat12_buffer.BPB_RootEntCnt ], ax
13B8: A3 8F 1A mov word [ fat12_buffer.BPB_TotSec16 ], ax
13BB: 66 A3 9C 1A mov dword [ fat12_buffer.BPB_TotSec32 ], eax
13BF: EB FE jmp $
13C1: C7 46 B4 10 00 mov set_ramfs, 16
13C6: 66 0F B6 1E 89 1A movzx ebx, byte [ fat12_buffer.BPB_SecPerClus ]
13CC: 66 0F AF C3 imul eax, ebx
13D0: 66 3D 00 00 01 00 cmp eax, 0x10000
13D6: 73 0C jae @f
13D8: A3 8F 1A mov word [ fat12_buffer.BPB_TotSec16 ], ax
13DB: 66 C7 06 9C 1A 00 00 00 00 mov dword [ fat12_buffer.BPB_TotSec32 ], 0
13E4: 66 B8 E0 00 00 00 mov eax, root_dir_entry_count
13EA: A3 8D 1A mov word [ fat12_buffer.BPB_RootEntCnt ], ax
13ED: 66 0F B7 1E 87 1A movzx ebx, word [ fat12_buffer.BPB_BytsPerSec ]
13F3: 66 6B C0 20 imul eax, 32
13F7: 66 01 D8 add eax, ebx
13FA: 66 48 dec eax
13FC: 66 99 cdq
13FE: 66 F7 FB idiv ebx
1401: 66 0F B7 1E 8A 1A movzx ebx, word [ fat12_buffer.BPB_RsvdSecCnt ]
1407: 66 01 C3 add ebx, eax
140A: 66 0F B7 06 8F 1A movzx eax, word [ fat12_buffer.BPB_TotSec16 ]
1410: 66 29 D8 sub eax, ebx
1413: 66 C1 E7 08 shl edi, 8
1417: 66 0F B6 0E 8C 1A movzx ecx, byte [ fat12_buffer.BPB_NumFATs ]
141D: 66 01 CF add edi, ecx
1420: 66 01 F8 add eax, edi
1423: 66 48 dec eax
1425: 66 99 cdq
1427: 66 F7 FF idiv edi
142A: A3 92 1A mov word [ fat12_buffer.BPB_FATSz16 ], ax
142D: C7 46 B4 0C 00 mov set_ramfs, 12
1432: 66 0F B6 1E 89 1A movzx ebx, byte [ fat12_buffer.BPB_SecPerClus ]
1438: 66 0F AF C3 imul eax, ebx
143C: 66 3D 00 00 01 00 cmp eax, 0x10000
1442: 73 0C jae @f
1444: A3 8F 1A mov word [ fat12_buffer.BPB_TotSec16 ], ax
1447: 66 C7 06 9C 1A 00 00 00 00 mov dword [ fat12_buffer.BPB_TotSec32 ], 0
1450: 66 B8 E0 00 00 00 mov eax, root_dir_entry_count
1456: A3 8D 1A mov word [ fat12_buffer.BPB_RootEntCnt ], ax
1459: 66 0F B7 06 8F 1A movzx eax, word [ fat12_buffer.BPB_TotSec16 ]
145F: 66 6B C0 0C imul eax, 12
1463: 66 C1 E8 03 shr eax, 3
1467: 66 0F B7 1E 87 1A movzx ebx, word [ fat12_buffer.BPB_BytsPerSec ]
146D: 66 99 cdq
146F: 66 F7 FB idiv ebx
1472: 40 inc ax
1473: A3 92 1A mov word [ fat12_buffer.BPB_FATSz16 ], ax
1476: A1 92 1A mov ax, word [ fat12_buffer.BPB_FATSz16 ]
1479: 0F B6 1E 8C 1A movzx bx, byte [ fat12_buffer.BPB_NumFATs ]
147E: 0F AF C3 imul ax, bx
1481: 8B 1E 8D 1A mov bx, word [ fat12_buffer.BPB_RootEntCnt ]
1485: C1 EB 04 shr bx, 4
1488: 01 D8 add ax, bx
148A: 89 5E B0 mov size_root_dir, bx
148D: 0F B6 1E 8A 1A movzx bx, byte [ fat12_buffer.BPB_RsvdSecCnt ]
1492: 01 D8 add ax, bx
1494: 89 46 AE mov firstDataSect, ax
1497: 8B 1E 8F 1A mov bx, word [ fat12_buffer.BPB_TotSec16 ]
149B: 29 C3 sub bx, ax
149D: 89 D8 mov ax, bx
149F: 0F B6 1E 89 1A movzx bx, byte [ fat12_buffer.BPB_SecPerClus ]
14A4: 99 cwd
14A5: F7 FB idiv bx
14A7: 89 46 AC mov DataClasters, ax
14AA: 60 pusha
14AB: 8B 46 AE mov ax, firstDataSect
14AE: B9 0A 00 mov cx, 0x0a
14B1: BF 44 06 mov di, firstDataSect_msg
14B4: E8 6E F3 call decode
14B7: BE 44 06 mov si, firstDataSect_msg
14BA: E8 87 F3 call printplain
14BD: 8B 46 B0 mov ax, size_root_dir
14C0: B9 0A 00 mov cx, 0x0a
14C3: BF 79 06 mov di, size_root_dir_msg
14C6: E8 5C F3 call decode
14C9: BE 79 06 mov si, size_root_dir_msg
14CC: E8 75 F3 call printplain
14CF: 8B 46 AC mov ax, DataClasters
14D2: B9 0A 00 mov cx, 0x0a
14D5: BF 9B 06 mov di, DataClasters_msg
14D8: E8 4A F3 call decode
14DB: BE 9B 06 mov si, DataClasters_msg
14DE: E8 63 F3 call printplain
14E1: 61 popa
14E2: A0 91 1A mov al, byte [ fat12_buffer.BPB_Media ]
14E5: 1E push ds
14E6: 8B 7E C4 mov di, info_real_mode_size
14E9: 81 C7 00 10 add di, 0x1000
14ED: 57 push di
14EE: 31 FF xor di, di
14F0: 89 7E AA mov point_to_free_root, di
14F3: 1F pop ds
14F4: 88 05 mov byte [ di ], al
14F6: 83 C8 FF or ax, - 1
14F9: 47 inc di
14FA: 89 05 mov word [ di ], ax
14FC: 1F pop ds
14FD: C7 46 B2 03 00 mov point_next_fat_str, 3
1502: 60 pusha
1503: 8B 46 B2 mov ax, point_next_fat_str
1506: B9 0A 00 mov cx, 0x0a
1509: BF DA 05 mov di, fat_create_msg
150C: E8 16 F3 call decode
150F: BE DA 05 mov si, fat_create_msg
1512: E8 2F F3 call printplain
1515: 61 popa
1516: B8 7C 1A mov ax, fat12_buffer
1519: BE 3C 1A mov si, table_15_87
151C: 01 44 12 add word [ si + 8 * 2 + 2 ], ax
151F: 06 push es
1520: 1E push ds
1521: 07 pop es
1522: B9 1F 00 mov cx, 31
1525: B4 87 mov ah, 0x87
1527: CD 15 int 0x15
1529: 07 pop es
152A: 60 pusha
152B: 8B 44 12 mov ax, word [ si + 8 * 2 + 2 ]
152E: B9 0A 00 mov cx, 0x0a
1531: BF 0E 06 mov di, BPB_msg
1534: E8 EE F2 call decode
1537: BE 0E 06 mov si, BPB_msg
153A: E8 07 F3 call printplain
153D: 61 popa
153E: 8B 7E F4 mov di, point_default
1541: 8B 4E FA mov cx, save_cx_d
1544: C7 46 A6 00 00 mov data_offset, 0
1549: E8 27 F3 call get_firs_sym
154C: 85 C9 test cx, cx
154E: 0F 84 B3 03 jz ._end?1D2
1552: 3C 52 cmp al, 'R'
1554: 75 F3 jnz .start_loop?1D1
1556: 89 CB mov bx, cx
1558: 89 F8 mov ax, di
155A: BE 1A 08 mov si, parse_RamdiskFile
155D: B9 0B 00 mov cx, parse_RamdiskFile_e - parse_RamdiskFile
1560: F3 repe
1561: A6 cmpsb
1562: 0F 85 98 03 jnz .rest_value_loop?1D3
1566: 83 EB 0B sub bx, parse_RamdiskFile_e - parse_RamdiskFile
1569: 01 CB add bx, cx
156B: 89 D9 mov cx, bx
156D: B8 20 3D mov ax, 0x3d20
1570: F3 repe
1571: AE scasb
1572: 66 85 C9 test ecx, ecx
1575: 0F 84 85 03 jz .rest_value_loop?1D3
1579: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
157D: 0F 85 7D 03 jnz .rest_value_loop?1D3
1581: F3 repe
1582: AE scasb
1583: 41 inc cx
1584: 4F dec di
1585: 89 7E A2 mov save_di_RAMDISK, di
1588: 89 4E A0 mov save_cx_RAMDISK, cx
158B: 26 8A 05 mov al, byte [ es : di ]
158E: 3C 2C cmp al, ','
1590: 74 04 jz .found_end_str
1592: 47 inc di
1593: 49 dec cx
1594: 75 F5 jnz @b
1596: 89 7E A8 mov point_to_dest_file_name, di
1599: 47 inc di
159A: BE BA 1A mov si, shot_name_fat
159D: 83 4E A4 FF or first_input, - 1
15A1: B9 0B 00 mov cx, 11
15A4: 26 8A 05 mov al, byte [ es : di ]
15A7: 3C 0A cmp al, 0xa
15A9: 74 7D jz .st4_s?1GP
15AB: 3C 0D cmp al, 0xd
15AD: 74 79 jz .st4_s?1GP
15AF: 3C 20 cmp al, 0x20
15B1: 74 75 jz .st4_s?1GP
15B3: 3C 20 cmp al, 0x20
15B5: 72 7A jb .error?1GK
15B7: 3C 22 cmp al, 0x22
15B9: 74 76 jz .error?1GK
15BB: 3C 2A cmp al, 0x2a
15BD: 74 72 jz .error?1GK
15BF: 3C 2B cmp al, 0x2b
15C1: 74 6E jz .error?1GK
15C3: 3C 2C cmp al, 0x2c
15C5: 74 6A jz .error?1GK
15C7: 3C 2F cmp al, 0x2F
15C9: 74 66 jz .error?1GK
15CB: 3C 3A cmp al, 0x3a
15CD: 74 62 jz .error?1GK
15CF: 3C 3B cmp al, 0x3b
15D1: 74 5E jz .error?1GK
15D3: 3C 3C cmp al, 0x3c
15D5: 74 5A jz .error?1GK
15D7: 3C 3D cmp al, 0x3d
15D9: 74 56 jz .error?1GK
15DB: 3C 3E cmp al, 0x3E
15DD: 74 52 jz .error?1GK
15DF: 3C 3F cmp al, 0x3F
15E1: 74 4E jz .error?1GK
15E3: 3C 5B cmp al, 0x5b
15E5: 74 4A jz .error?1GK
15E7: 3C 5C cmp al, 0x5c
15E9: 74 46 jz .error?1GK
15EB: 3C 5D cmp al, 0x5d
15ED: 74 42 jz .error?1GK
15EF: 3C 7C cmp al, 0x7c
15F1: 74 3E jz .error?1GK
15F3: 83 7E A4 FF cmp first_input, - 1
15F7: 75 08 jnz .next_step?1GJ
15F9: 83 66 A4 00 and first_input, 0
15FD: 3C 2E cmp al, '.'
15FF: 74 30 jz .error?1GK
1601: 3C 2E cmp al, 0x2e
1603: 75 13 jnz .st2?1GM
1605: B0 20 mov al, ' '
1607: 80 F9 03 cmp cl, 3
160A: 76 0C jbe .st2?1GM
160C: 88 04 mov byte [ si ], al
160E: 46 inc si
160F: 49 dec cx
1610: 83 F9 03 cmp cx, 3
1613: 77 F7 ja .st3?1GO
1615: 47 inc di
1616: EB 8C jmp @b
1618: 3C 60 cmp al, 0x60
161A: 76 02 jbe .st2_l?1GN
161C: 34 20 xor al, 0x20
161E: 88 04 mov byte [ si ], al
1620: 47 inc di
1621: 46 inc si
1622: E2 80 loop @b
1624: 31 C0 xor ax, ax
1626: EB 0C jmp @f
1628: B0 20 mov al, ' '
162A: 88 04 mov byte [ si ], al
162C: 46 inc si
162D: E2 FB loop .st4?1GQ
162F: EB F3 jmp .st5?1GR
1631: 83 C8 FF or ax, - 1
1634: 60 pusha
1635: B9 0A 00 mov cx, 0x0a
1638: BF F5 06 mov di, convertion_file_name_msg
163B: E8 E7 F1 call decode
163E: BE F5 06 mov si, convertion_file_name_msg
1641: E8 00 F2 call printplain
1644: BE BA 1A mov si, shot_name_fat
1647: C6 44 0C 00 mov byte [ si + 12 ], 0
164B: E8 F6 F1 call printplain
164E: 61 popa
164F: 85 C0 test ax, ax
1651: 75 39 jnz .exit?1GI
1653: BE BA 1A mov si, shot_name_fat
1656: 8B 7E AE mov di, firstDataSect
1659: 2B 7E B0 sub di, size_root_dir
165C: C1 E7 09 shl di, 9
165F: BA E0 00 mov dx, root_dir_entry_count
1662: 8B 46 C4 mov ax, info_real_mode_size
1665: 05 00 10 add ax, 0x1000
1668: 8E E8 mov gs, ax
166A: B9 0B 00 mov cx, 11
166D: 8A 00 mov al, byte [ ds : si + bx ]
166F: 65 8A 21 mov ah, byte [ gs : di + bx ]
1672: 43 inc bx
1673: 38 C4 cmp ah, al
1675: 75 07 jnz .no_equal?1GH
1677: E2 F4 loop @b
1679: 83 C8 FF or ax, - 1
167C: EB 0E jmp .exit?1GI
167E: B9 0B 00 mov cx, 11
1681: 31 DB xor bx, bx
1683: 83 C7 20 add di, 32
1686: 4A dec dx
1687: 75 E4 jnz @b
1689: 83 E0 00 and ax, 0
168C: 60 pusha
168D: B9 0A 00 mov cx, 0x0a
1690: BF B9 06 mov di, check_name_fat_msg
1693: 66 C7 05 20 20 20 20 mov dword [ di ], ' '
169A: C7 45 04 20 20 mov word [ di + 4 ], ' '
169F: E8 83 F1 call decode
16A2: BE B9 06 mov si, check_name_fat_msg
16A5: E8 9C F1 call printplain
16A8: 61 popa
16A9: 8B 7E A2 mov di, save_di_RAMDISK
16AC: 8B 4E A0 mov cx, save_cx_RAMDISK
16AF: 84 C0 test al, al
16B1: 0F 85 94 FE jnz .start_loop?1D1
16B5: 26 66 FF 75 FA push dword [ es : di - 6 ]
16BA: 8D 75 FA lea si, [ di - 6 ]
16BD: 26 FF 75 FE push word [ es : di - 2 ]
16C1: 57 push di
16C2: 31 C0 xor ax, ax
16C4: 26 89 45 FA mov word [ es : di - 6 ], ax
16C8: 8B 46 C4 mov ax, info_real_mode_size
16CB: 26 89 45 FC mov word [ es : di - 4 ], ax
16CF: 26 C7 45 FE 10 00 mov word [ es : di - 2 ], 16
16D5: 8B 7E A8 mov di, point_to_dest_file_name
16D8: 26 FF 35 push word [ es : di ]
16DB: 51 push cx
16DC: 31 C0 xor ax, ax
16DE: 26 89 05 mov word [ es : di ], ax
16E1: 57 push di
16E2: 89 F7 mov di, si
16E4: 40 inc ax
16E5: 56 push si
16E6: 06 push es
16E7: 55 push bp
16E8: 06 push es
16E9: 1F pop ds
16EA: 0E push cs
16EB: 07 pop es
16EC: 26 FF 1E DC 0A call far dword [ es : loader_callback ]
16F1: 0E push cs
16F2: 1F pop ds
16F3: 5D pop bp
16F4: 07 pop es
16F5: 5E pop si
16F6: 83 FB 02 cmp bx, 2
16F9: 0F 87 01 02 ja .error?1D4
16FD: 89 5E 9E mov status_flag_loader_f, bx
1700: 66 C1 E2 10 shl edx, 16
1704: 89 C2 mov dx, ax
1706: 66 89 56 B6 mov save_file_size, edx
170A: 66 89 D0 mov eax, edx
170D: 5F pop di
170E: 59 pop cx
170F: 26 8F 05 pop word [ es : di ]
1712: 5F pop di
1713: 26 8F 45 FE pop word [ es : di - 2 ]
1717: 26 66 8F 45 FA pop dword [ es : di - 6 ]
171C: 60 pusha
171D: B9 0A 00 mov cx, 0x0a
1720: BF C1 05 mov di, RamdiskFile_msg
1723: 66 C7 05 20 20 20 20 mov dword [ ds : di ], ' '
172A: E8 F8 F0 call decode
172D: BE C1 05 mov si, RamdiskFile_msg
1730: E8 11 F1 call printplain
1733: 61 popa
1734: 06 push es
1735: 8B 46 C4 mov ax, info_real_mode_size
1738: 05 00 10 add ax, 0x1000
173B: 8E C0 mov es, ax
173D: 8B 7E AE mov di, firstDataSect
1740: 2B 7E B0 sub di, size_root_dir
1743: C1 E7 09 shl di, 9
1746: 03 7E AA add di, point_to_free_root
1749: BE BA 1A mov si, shot_name_fat
174C: B9 0B 00 mov cx, 11
174F: AC lodsb
1750: AA stosb
1751: E2 FC loop @b
1753: 31 C0 xor ax, ax
1755: B4 08 mov ah, ATTR_VOLUME_ID
1757: 26 89 05 mov word [ es : di ], ax
175A: 83 C7 02 add di, 2
175D: 26 C6 05 64 mov byte [ es : di ], 100
1761: 47 inc di
1762: 26 C7 05 2B 03 mov word [ es : di ], 0x032b
1767: 83 C7 02 add di, 2
176A: 26 C7 05 00 00 mov word [ es : di ], 0x0
176F: 83 C7 02 add di, 2
1772: 26 C7 05 2B 03 mov word [ es : di ], 0x032b
1777: 83 C7 02 add di, 2
177A: 26 C7 05 00 00 mov word [ es : di ], 0x0
177F: 83 C7 02 add di, 2
1782: 26 C7 05 00 00 mov word [ es : di ], 0x0
1787: 83 C7 02 add di, 2
178A: 26 C7 05 2B 03 mov word [ es : di ], 0x032b
178F: 83 C7 02 add di, 2
1792: 8B 46 B2 mov ax, point_next_fat_str
1795: 26 89 05 mov word [ es : di ], ax
1798: 83 C7 02 add di, 2
179B: 57 push di
179C: 89 C3 mov bx, ax
179E: D1 EB shr bx, 1
17A0: 01 D8 add ax, bx
17A2: 8B 1E 87 1A mov bx, word [ fat12_buffer.BPB_BytsPerSec ]
17A6: 99 cwd
17A7: F7 FB idiv bx
17A9: 89 C6 mov si, ax
17AB: 66 0F B7 06 87 1A movzx eax, word [ fat12_buffer.BPB_BytsPerSec ]
17B1: 66 0F B6 1E 89 1A movzx ebx, byte [ fat12_buffer.BPB_SecPerClus ]
17B7: 66 0F AF C3 imul eax, ebx
17BB: 66 8B 5E B6 mov ebx, save_file_size
17BF: 66 29 C3 sub ebx, eax
17C2: 66 39 C3 cmp ebx, eax
17C5: 76 29 jbe .eof_file?1US
17C7: FF 46 B2 inc point_next_fat_str
17CA: 8B 4E B2 mov cx, point_next_fat_str
17CD: 89 C2 mov dx, ax
17CF: D1 EA shr dx, 1
17D1: 01 D1 add cx, dx
17D3: F7 C6 01 00 test si, 0x1
17D7: 74 0B jz .step2?1UP
17D9: C1 E1 04 shl cx, 4
17DC: 26 89 0C mov word [ es : si ], cx
17DF: 46 inc si
17E0: 01 C1 add cx, ax
17E2: EB DB jmp @b
17E4: 81 E1 FF 0F and cx, 0x0FFF
17E8: 26 89 0C mov word [ es : si ], cx
17EB: 46 inc si
17EC: 01 C1 add cx, ax
17EE: EB CF jmp @b
17F0: B9 FF 0F mov cx, 0x0fff
17F3: F7 C6 01 00 test si, 0x1
17F7: 74 08 jz .step3?1UQ
17F9: C1 E1 04 shl cx, 4
17FC: 26 89 0C mov word [ es : si ], cx
17FF: EB 07 jmp .end?1UR
1801: 81 E1 FF 0F and cx, 0x0FFF
1805: 26 89 0C mov word [ es : si ], cx
1808: FF 46 B2 inc point_next_fat_str
180B: 5F pop di
180C: 66 8B 46 B6 mov eax, save_file_size
1810: 26 66 89 05 mov dword [ es : di ], eax
1814: 66 60 pushad
1816: 8B 7E AE mov di, firstDataSect
1819: 2B 7E B0 sub di, size_root_dir
181C: C1 E7 09 shl di, 9
181F: 03 7E AA add di, point_to_free_root
1822: BE C6 1A mov si, dest_name_fat
1825: B9 0B 00 mov cx, 11
1828: 26 8A 05 mov al, byte [ es : di ]
182B: 47 inc di
182C: 88 04 mov byte [ ds : si ], al
182E: 46 inc si
182F: E2 F7 loop @b
1831: 31 C0 xor ax, ax
1833: 88 04 mov byte [ si ], al
1835: BE C6 1A mov si, dest_name_fat
1838: E8 09 F0 call printplain
183B: 66 61 popad
183D: 83 46 AA 20 add point_to_free_root, 32
1841: 07 pop es
1842: 8B 46 C4 mov ax, info_real_mode_size
1845: BE 3C 1A mov si, table_15_87
1848: 89 44 12 mov word [ si + 8 * 2 + 2 ], ax
184B: 66 0F B7 46 AE movzx eax, firstDataSect
1850: 66 0F B7 56 A6 movzx edx, data_offset
1855: 66 01 D0 add eax, edx
1858: 66 0F B7 1E 87 1A movzx ebx, word [ fat12_buffer.BPB_BytsPerSec ]
185E: 66 0F B6 16 89 1A movzx edx, byte [ fat12_buffer.BPB_SecPerClus ]
1864: 0F AF DA imul bx, dx
1867: 66 53 push ebx
1869: 66 0F AF C3 imul eax, ebx
186D: 60 pusha
186E: B9 0A 00 mov cx, 0x0a
1871: BF 07 04 mov di, show_db1
1874: E8 AE EF call decode
1877: BE 07 04 mov si, show_db1
187A: E8 C7 EF call printplain
187D: 61 popa
187E: B2 10 mov dl, 0x10
1880: 66 3D 00 00 01 00 cmp eax, 0x00010000
1886: 72 0A jb @f
1888: 66 2D 00 00 01 00 sub eax, 0x00010000
188E: FE C2 inc dl
1890: EB EE jmp @b
1892: 88 54 1B mov byte [ si + 8 * 3 + 3 ], dl
1895: 89 44 1A mov word [ si + 8 * 3 + 2 ], ax
1898: 66 8B 4E B6 mov ecx, save_file_size
189C: 66 81 F9 FF FF 00 00 cmp ecx, 0x0000ffff
18A3: 76 0A jbe .correct_on_byte?1cJ
18A5: 66 B9 00 00 01 00 mov ecx, 0x00010000
18AB: 66 29 4E B6 sub save_file_size, ecx
18AF: 66 58 pop eax
18B1: 66 51 push ecx
18B3: FF 46 A6 inc data_offset
18B6: 66 39 C8 cmp eax, ecx
18B9: 73 05 jae @f
18BB: 66 29 C1 sub ecx, eax
18BE: EB F3 jmp @b
18C0: 66 59 pop ecx
18C2: 66 F7 C1 01 00 00 00 test ecx, 0x1
18C9: 74 02 jz .st1?1cI
18CB: 66 41 inc ecx
18CD: 66 D1 E9 shr ecx, 1
18D0: 06 push es
18D1: 1E push ds
18D2: 07 pop es
18D3: B4 87 mov ah, 0x87
18D5: CD 15 int 0x15
18D7: 07 pop es
18D8: 60 pusha
18D9: B9 0A 00 mov cx, 0x0a
18DC: BF 46 07 mov di, return_code_af_move
18DF: E8 43 EF call decode
18E2: BE 46 07 mov si, return_code_af_move
18E5: E8 5C EF call printplain
18E8: 61 popa
18E9: 83 7E 9E 01 cmp status_flag_loader_f, 0x1
18ED: 75 00 jnz @f
18EF: 8B 7E A2 mov di, save_di_RAMDISK
18F2: 8B 4E A0 mov cx, save_cx_RAMDISK
18F5: 60 pusha
18F6: 31 C0 xor ax, ax
18F8: CD 16 int 0x16
18FA: 61 popa
18FB: E9 4B FC jmp .start_loop?1D1
18FE: 89 C7 mov di, ax
1900: 89 D9 mov cx, bx
1902: E9 44 FC jmp .start_loop?1D1
1905: 8B 46 C4 mov ax, info_real_mode_size
1908: 05 00 10 add ax, 0x1000
190B: BE 3C 1A mov si, table_15_87
190E: 89 44 12 mov word [ si + 8 * 2 + 2 ], ax
1911: B8 00 02 mov ax, 512
1914: 89 44 1A mov word [ si + 8 * 3 + 2 ], ax
1917: 66 0F B7 0E 92 1A movzx ecx, word [ fat12_buffer.BPB_FATSz16 ]
191D: 0F B6 1E 8C 1A movzx bx, byte [ fat12_buffer.BPB_NumFATs ]
1922: 0F AF CB imul cx, bx
1925: 03 4E B0 add cx, size_root_dir
1928: 66 C1 E1 09 shl ecx, 9
192C: 66 F7 C1 01 00 00 00 test ecx, 0x1
1933: 74 02 jz .st1?1ho
1935: 66 41 inc ecx
1937: 66 D1 E9 shr ecx, 1
193A: 06 push es
193B: 1E push ds
193C: 07 pop es
193D: B4 87 mov ah, 0x87
193F: CD 15 int 0x15
1941: 07 pop es
1942: 60 pusha
1943: B9 0A 00 mov cx, 0x0a
1946: BF 77 07 mov di, return_code_af_fat_m
1949: E8 D9 EE call decode
194C: BE 77 07 mov si, return_code_af_fat_m
194F: E8 F2 EE call printplain
1952: 61 popa
1953: 60 pusha
1954: B9 0A 00 mov cx, 0x0a
1957: BF 07 04 mov di, show_db1
195A: E8 C8 EE call decode
195D: BE 07 04 mov si, show_db1
1960: E8 E1 EE call printplain
1963: 61 popa
1964: 60 pusha
1965: BE 21 07 mov si, make_fat12_RFS_msg
1968: E8 D9 EE call printplain
196B: 61 popa
196C: EB 1F jmp ._end_parse_FRS
196E: 89 D9 mov cx, bx
1970: 89 C7 mov di, ax
1972: BE 0B 08 mov si, parse_RFS_KRFS
1975: B9 04 00 mov cx, parse_RFS_KRFS_e - parse_RFS_KRFS
1978: F3 repe
1979: A6 cmpsb
197A: EB 11 jmp ._end_parse_FRS
197C: 89 D9 mov cx, bx
197E: 89 C7 mov di, ax
1980: E9 A4 F8 jmp .start_g_tpe_RFS
1983: 83 4E C0 01 or show_errors_sect, show_error_1
1987: EB 04 jmp ._end_parse_FRS
1989: 83 4E C0 02 or show_errors_sect, show_error_2
198D: 60 pusha
198E: BE 34 07 mov si, get_type_FS_msg
1991: E8 B0 EE call printplain
1994: 61 popa
1995: 31 C0 xor ax, ax
1997: CD 16 int 0x16
1999: 8B 7E F4 mov di, point_default
199C: 8B 4E FA mov cx, save_cx_d
199F: E8 D1 EE call get_firs_sym
19A2: 85 C9 test cx, cx
19A4: 0F 84 8E 00 jz ._afterLoaderModule
19A8: 3C 4C cmp al, 'L'
19AA: 75 F3 jnz .start_p_LM
19AC: 89 CB mov bx, cx
19AE: 89 F8 mov ax, di
19B0: BE CD 07 mov si, parse_LoaderModule
19B3: B9 0C 00 mov cx, parse_LoaderModule_e - parse_LoaderModule
19B6: F3 repe
19B7: A6 cmpsb
19B8: 75 75 jnz .rest_value_loop_LM
19BA: 83 EB 0C sub bx, parse_LoaderModule_e - parse_LoaderModule
19BD: 01 CB add bx, cx
19BF: 89 D9 mov cx, bx
19C1: F7 46 F8 01 00 test status_flag, flag_found_LM
19C6: 74 00 jz .correct_is_not_set_LM
19C8: B8 20 3D mov ax, 0x3d20
19CB: F3 repe
19CC: AE scasb
19CD: E3 60 jcxz .rest_value_loop_LM
19CF: 26 3A 65 FF cmp ah, byte [ es : di - 1 ]
19D3: 75 5A jnz .rest_value_loop_LM
19D5: F3 repe
19D6: AE scasb
19D7: 41 inc cx
19D8: 4F dec di
19D9: 26 66 FF 75 FA push dword [ es : di - 6 ]
19DE: 8D 75 FA lea si, [ di - 6 ]
19E1: 26 FF 75 FE push word [ es : di - 2 ]
19E5: 31 C0 xor ax, ax
19E7: 26 89 45 FA mov word [ es : di - 6 ], ax
19EB: 8B 46 C4 mov ax, info_real_mode_size
19EE: 26 89 45 FC mov word [ es : di - 4 ], ax
19F2: 26 C7 45 FE 10 00 mov word [ es : di - 2 ], 16
19F8: 26 8A 05 mov al, byte [ es : di ]
19FB: 3C 20 cmp al, ' '
19FD: 74 0C jz .found_end_str?1mb
19FF: 3C 0A cmp al, 0xa
1A01: 74 08 jz .found_end_str?1mb
1A03: 3C 0D cmp al, 0xd
1A05: 74 04 jz .found_end_str?1mb
1A07: 47 inc di
1A08: 49 dec cx
1A09: 75 ED jnz @b
1A0B: 26 FF 35 push word [ es : di ]
1A0E: 31 C0 xor ax, ax
1A10: 26 89 05 mov word [ es : di ], ax
1A13: 89 F7 mov di, si
1A15: 40 inc ax
1A16: 56 push si
1A17: 06 push es
1A18: 06 push es
1A19: 1F pop ds
1A1A: 0E push cs
1A1B: 07 pop es
1A1C: 26 FF 1E DC 0A call far dword [ es : loader_callback ]
1A21: 0E push cs
1A22: 1F pop ds
1A23: 07 pop es
1A24: 5E pop si
1A25: 85 DB test bx, bx
1A27: 75 03 jnz .error_LM
1A29: 26 FF 2C jmp far dword [ es : si ]
1A2C: E8 91 F0 call error.LoaderModule
1A2F: 89 C7 mov di, ax
1A31: 89 D9 mov cx, bx
1A33: E9 69 FF jmp .start_p_LM
1A36: EB FE jmp $
1A38: E9 6A F1 jmp ini_loaded
1A3C: 00 00 00 00 00 00 00 00 db 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0
1A44: 00 00 00 00 00 00 00 00 db 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0
1A4C: FF FF db 0xff, 0xff
1A4E: 00 10 db 0x0, 0x10
1A50: 00 93 00 00 db 0x00, 0x93, 0x0, 0x0
1A54: FF FF 00 00 10 93 00 00 db 0xff, 0xff, 0x0, 0x00, 0x10, 0x93, 0x0, 0x0
1A5C: 00 00 00 00 00 00 00 00 db 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0
1A64: 00 00 00 00 00 00 00 00 db 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0
1A6C: 00 00 00 00 00 00 00 00 db 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0
1A74: 00 00 00 00 00 00 00 00 db 0x00, 0x00, 0x0, 0x00, 0x00, 0x00, 0x0, 0x0
1A7C: 90 90 90 .BS_jmpBoot db 0x90, 0x90, 0x90
1A7F: 4B 20 53 79 53 20 36 34 .BS_OEMName db 'K SyS 64'
1A87: 00 02 .BPB_BytsPerSec dw 512
1A89: 01 .BPB_SecPerClus db 0x1
1A8A: 01 00 .BPB_RsvdSecCnt dw 0x1
1A8C: 01 .BPB_NumFATs db 0x1
1A8D: 00 02 .BPB_RootEntCnt dw 512
1A8F: 00 00 .BPB_TotSec16 dw 0x0
1A91: F0 .BPB_Media db 0xF0
1A92: 00 00 .BPB_FATSz16 dw 0x0
1A94: 00 00 .BPB_SecPerTrk dw 0x0
1A96: 00 00 .BPB_NumHeads dw 0x0
1A98: 00 00 00 00 .BPB_HiddSec dd 0x0
1A9C: 00 00 00 00 .BPB_TotSec32 dd 0x0
1AA0: 52 .BS_DrvNum db 'R'
1AA1: 00 .BS_Reserved1 db 0x0
1AA2: 29 .BS_BootSig db 0x29
1AA3: 52 46 4B 53 .BS_VolID db 'RFKS'
1AA7: 52 41 4D 20 44 49 53 4B 20 46 53 .BS_VolLab db 'RAM DISK FS'
1AB2: 46 41 54 31 32 20 20 20 .BS_FilSysType db 'FAT12 '
1ABA: shot_name_fat rb 11
1AC5: rb 1
1AC6: dest_name_fat rb 12
1AD2: value_timeout rw 1
1AD4: old_timer rd 1
1AD8: start_timer rd 1
1ADC: timer_ rd 1
1AE0: start_stack rw 1
1AE2: save_bp_from_timer rw 1
3 passes, 0.8 seconds, 6842 bytes.
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/parse_any.inc
0,0 → 1,686
; Copyright (c) 2009, <Lrz>
; 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.
;*****************************************************************************
 
;тут распологается модуль с помощью которого будут парситься все остальные секции
color_sym_black equ 0
color_sym_blue equ 1
color_sym_green equ 2
color_sym_turquoise equ 3
color_sym_red equ 4
 
color_sym_lightgray equ 7
 
color_sym_lightblue equ 9
color_sym_lettuce equ 10
color_sym_pink equ 12
color_sym_yellow equ 14
 
macro use_any_sec
{
;узнаем работу предыдущего шага т.е. чему = timeout, если он 0, то визуальная часть не будет отображена на дисплее с выбором загрузочных секций.
;иначе мы ее должны отобразить и ждать заявленое время для выбора и конигурирования пукнктов секции от пользователя.
 
if DEBUG
pusha
mov ax, word [value_timeout];идет проверка на наличее значения timeout, для более быстрой работы, этот параметр должен быть уже обработан,т.е. в этом случае при его =0 будет сформирован указатель только на дефолтную секцию, иначе информация будет собрана по всем секциям и составлены указатели в блоке памяти
; mov ax,cx
mov cx, 0x0a
mov di, show_db1
mov dword[ds:di], ' '
mov word [ds:di+4], ' '
call decode
;Show size
mov si, show_db1
call printplain
;
popa
end if
 
test ax, ax
jz .parse_run_only
 
;отобразим полный список всех найденых секций.
if DEBUG
pusha
mov si, show_all_sect
call printplain
popa
end if
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov al, 0xf6 ; Сброс клавиатуры, разрешить сканирование
out 0x60, al
xor cx, cx
.wait_loop: ; variant 2
; reading state of port of 8042 controller
in al, 64h
and al, 00000010b ; ready flag
; wait until 8042 controller is ready
loopnz .wait_loop
 
 
; set keyboard typematic rate & delay
mov al, 0xf3
out 0x60, al
xor cx, cx
@@:
in al, 64h
test al, 2
loopnz @b
mov al, 0
out 0x60, al
xor cx, cx
@@:
in al, 64h
test al, 2
loopnz @b
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; get start time
call gettime
mov dword [start_timer], eax
mov word [timer_], newtimer
mov word [timer_+2], cs
;установить свое прерывание на таймер т.е. код будет перрываться ~18 раз в сек и переходить на обработчик
cli
push 0
pop es
push dword [es:8*4]
pop dword [old_timer]
push dword [timer_]
pop dword [es:8*4]
sti
 
;процедура формирования буфера для скролинга секций
;if DEBUG
; pusha
; mov ax,point_default
; mov ax,cx
; mov cx,0x0a
; mov di,show_db1
; mov dword[ds:di],' '
; mov word [ds:di+4],' '
; call decode
;Show size
; mov si,show_db1
; call printplain
;
; xor ax,ax
; int 0x16
; popa
;end if
;;;;;;;;;;;;;размер предыдущей сеции установим =0
mov save_descript_size, 18
;отобразить black screen
show_bl_sc ;es=0xb800
.show_all_scr:
get_frame_buffer ;es=0x2000
;отображение секций
call show_bl_sc_sect ;es=0xb800
;отобразить активный курсор
.show_active_cursor:
show_act_cursor
show_descript ;макрос по отображению описания секции
 
;отобразить Press any key ....
mov eax, dword [old_timer]
cmp eax, dword [timer_]
jz .interrupt_16
 
show_timer_message
mov word [start_stack], sp
.interrupt_16:
xor ax, ax ;получим информацию о том что нажато
int 0x16
;check on change
mov ebx, dword [old_timer]
cmp ebx, dword [timer_]
jz @f
;restore timer interrupt
cli
push 0
pop es
; mov eax,dword [old_timer] ; восстановим прежднее прерывание
mov [es:8*4], ebx
mov dword [timer_], ebx
sti
push ax
clear_timer_msg
pop ax
@@:
call clean_active_cursor ;clean old cursor ;es=0xb800
 
cmp ah, 0x48 ;реакция системы на события
jz .up
cmp ah, 0x50
jz .down
cmp ah, 0x49
jz .pgup
cmp ah, 0x51
jz .pgdown
cmp ah, 0x47
jz .home
cmp ah, 0x4f
jz .end
 
cmp al, 0xD
jnz .show_active_cursor
 
jmp .end_show_all ;парсинг секции которая указана в point_default
.up:
mov si, point_to_point_def ;значение указателя
add si, 2
lea ax, point_to_hframe
 
cmp si, ax
ja @f
 
mov point_to_point_def, si
mov ax, [si]
mov point_default, ax
jmp .show_active_cursor
@@:
call find_before_sect
jmp .show_all_scr
 
 
 
.down:
mov si, point_to_point_def ;значение указателя
mov ax, point_to_eframe ;указатель на последний элемент
sub si, 2
cmp si, ax
jb @f
 
mov point_to_point_def, si
mov ax, [si]
mov point_default, ax
jmp .show_active_cursor
 
@@:
call find_next_sect
jmp .show_all_scr
 
.pgup:
mov cx, size_show_section
@@:
push cx
call find_before_sect
pop cx
loop @b
jmp .show_all_scr
 
 
.pgdown:
mov cx, size_show_section
@@:
push cx
call find_next_sect
pop cx
loop @b
jmp .show_all_scr
 
.home:
xor di, di
call find_next_sect.h
jmp .show_all_scr
 
.end:
mov di, save_cx
call find_before_sect.e
jmp .show_all_scr
 
 
 
 
; тут мы будем парсить только дефолтную секцию и выполнять ее ничего не предлагая пользователю из диалогов.
.parse_run_only:
if DEBUG
pusha
mov si, no_show_only_w
call printplain
popa
end if
 
 
.end_show_all:
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
;show black screen SL
macro show_bl_sc
{
;;;;;;;;;;;;;;;
;очистим экран и выведем меню
; draw frames
xor ax, ax
if DEBUG
mov ax, 0x0720
end if
push 0xb800
pop es
xor di, di
; draw top
mov cx, 25 * 80
rep stosw
;;;;;;;;;;;;;;;;;;;;;;; show 'Secondary Loader v0.xxx'
mov di, 164
mov si, version
mov cx, version_end-version
mov ah, color_sym_yellow
@@:
lodsb
stosw
loop @b
;;;;;;;;;;;;;;;;;;;;;;; show firm ))
mov di, (2*160-(2*(soft_mes_end-soft_mes+4))) ;286
mov ah, color_sym_pink;color_sym_red
mov al, 'K'
stosw
mov al, ' '
stosw
mov ah, color_sym_lightgray;color_sym_lightblue;color_sym_pink
mov si, soft_mes
mov cx, soft_mes_end- soft_mes
@@:
lodsb
stosw
loop @b
;;;;;;;;;;;;;;;;;;;;;;; show '__________________________'
mov di, 480
mov ah, color_sym_yellow
mov al, 0xC4 ; '─'
mov cx, 61
rep stosw
;;;;;;;;;;;;;;;;;;;;;;; show 'Select section'
mov di, 804
mov si, select_section
mov cx, select_section_end - select_section
mov ah, color_sym_lightgray
@@:
lodsb
stosw
loop @b
;;;;;;;;;;;;;;;;;;;;;;; show 'Section description'
mov di, 880
mov si, section_description
mov cx, section_description_end - section_description
; mov ah,color_sym_lightgray
@@:
lodsb
stosw
loop @b
 
}
 
macro show_timer_message
{
;;;;;;;;;;;;;;;;;;;;; show Press any key
;;;;;;;;;;;;;;;;;;;;; show ramk
 
xor ax, ax
mov di, 3360
mov cx, 80*4
rep stosw
 
mov di, 3362
mov ah, color_sym_pink
mov al, 0xDA
stosw
mov al, 0xc4
mov cx, 76
rep stosw
mov al, 0xBF
stosw
add di, 4
mov al, 0xb3
stosw
add di, 152
stosw
add di, 4
stosw
add di, 152
stosw
add di, 4
mov al, 0xc0
stosw
mov al, 0xc4
mov cx, 76
rep stosw
mov al, 0xd9
stosw
;;;;;;;;;;;;;;;;;;;;;;;;ramk is complete show
;show first message
mov si, start_msg
mov cx, start_msg_e-start_msg
mov di, 3526
@@:
lodsb
stosw
loop @b
;;;;;;;;;;;;;;;;;;;; show press Enter to....
add di, 44
mov si, time_msg
mov cx, time_msg_e-time_msg
@@:
lodsb
stosw
loop @b
}
 
 
 
 
 
 
 
 
macro get_frame_buffer
{
mov cx, save_cx ;it's placed size of ini file
les di, dword [file_data]
 
mov si, di ;point frame
mov bx, cx
mov dx, size_show_section
; mov point_to_hframe,di ; внесем значение, так подстраховка не более
 
mov al, byte [es:di]
push word .first_ret_bl_sc
cmp al, ' '
jz .first_bl_sc
jmp get_firs_sym.not_space
.first_bl_sc:
jmp get_firs_sym.first_sp
 
.start_hbl:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz error.correct_exit_bl ;critical error not found default point it's not possible because it's param chacking before
cmp al, '['
jnz .start_hbl
 
mov si, di ;point frame
mov bx, cx
mov dx, size_show_section
jmp .analisist_al
 
 
.start_bl:
call get_firs_sym ;get first symbol on new line
.first_ret_bl_sc: ;первый возврат
test cx, cx
jz error.correct_exit_bl ;critical error not found default point it's not possible because it's param chacking before
.analisist_al:
cmp al, '['
jnz .start_bl
;просматриваем ini файл с начала в поисках секции указаной как default
;поиск фрейма в котором содержиться значение default
.found_sect_bl:
cmp di, point_loader
jz .start_bl
cmp di, point_default
jz .save_point_def
 
dec dx
jnz .start_bl
 
jmp .start_hbl
 
 
.save_point_def:
;итак далее мы должны заполнить frame буфер адресов секций, что бы потом по нему быстро перемещаться не вычисляя снова адреса
mov di, si ;указатель на начало
mov cx, bx
lea si, point_to_hframe
mov dx, size_show_section+1 ;т.к. у нас структура содержит размер между первым и вторым указателем, то нам нужно на 1 адрес больше обсчитать секций.
;переходим на обработку значения указателя
mov al, byte [es:di]
push word .first_ret_mfb
cmp al, ' '
jz .first_bl_mbf
jmp get_firs_sym.not_space
.first_bl_mbf:
jmp get_firs_sym.first_sp
 
.start_mfb:
call get_firs_sym ;get first symbol on new line
.first_ret_mfb: ;первый возврат
jcxz .val_buff_comp ;.end_loader ;found or not found parametrs in section exit in section
cmp al, '['
jnz .start_mfb
 
.found_sect_mfb:
cmp di, point_loader ;if we have section loader
jz .start_mfb
 
mov [si], di
 
sub si, 2
dec dx
jnz .start_mfb
;bufer is full
jmp @f
.val_buff_comp:
push save_cx
pop word [si]
sub si, 2
@@:
 
add si, 4
mov point_to_eframe, si
 
}
 
macro show_act_cursor
{
;отображение курсора по умолчанию
lea si, point_to_hframe
mov di, 962-160
mov ax, point_default
mov cx, size_show_section
.home_show_cur:
mov bx, [si]
add di, 160
cmp bx, ax
jz .show_cursor_activ
sub si, 2
loop .home_show_cur
 
.show_cursor_activ:
; push 0xb800
; pop es
mov point_to_point_def, si
mov ax, (color_sym_red*0x100+0x10)
stosw
add di, 68
inc ax
stosw
}
 
macro clear_timer_msg
{
push 0xb800
pop es
xor ax, ax
if DEBUG
mov ax, 0x0720
end if
;;;;;;;;;;;;;;;;;;;;; show Press any key
mov di, 3360
mov cx, 80*4
rep stosw
 
;show sect
push ini_data_
pop es
call show_bl_sc_sect ;es=0xb800
 
}
 
macro show_descript
;Этот макрос показывает краткое описание, если оно есть у секции в пункте
;Section description
{
local .start_p_sh_d
local .exit
local .rest_value_loop_sh_d
local .end_sh_desc_sec
local .loop_message
local .show_mess_prev_eq
mov di, point_default
push ini_data_
mov si, point_to_point_def
pop es
sub si, 2
mov cx, [si] ;загрузим указатель наследующию секцию
sub cx, di ;вот теперь имеем истиный размер
;di - указатель на дефолтную секцию т.е. выбранную cx - размер области. для просмотра
 
.start_p_sh_d:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz .exit ;нету? ну ладно - следующее значение тогда )
cmp al, 'd'
jnz .start_p_sh_d
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
mov bx, cx
mov ax, di
 
mov si, parse_descript
mov cx, parse_descript_e - parse_descript
repe cmpsb
jnz .rest_value_loop_sh_d ;is not compare
 
sub bx, parse_descript_e - parse_descript;correct cx
add bx, cx
mov cx, bx
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; разбор аля ' = '
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
jcxz .rest_value_loop_sh_d ;not found param timeout
cmp ah, byte [es:di-1] ;find '='
jnz .rest_value_loop_sh_d
repe scasb ;cut ' '
inc cx
dec di
;;;;;;;;;;;;;;;;;;;;di указывает на строчку, которую нам нужно выводить.
;строчка будет выводиться блоками по 37 символов.
;настроим куда будем выводить т.е. начало
;es:di - указывают на строчку из которой мы берем символ, ds:si куда будем выводить
push di
pop si
 
push es
pop ds
 
push 0xb800
pop es
mov di, 1040
mov bx, 18
mov find_sec_di, di
mov save_cx_d, bx
;;;;;;;;;;;;;;;;;;;;;;;;;;
;clean string
 
push di
xor ax, ax
 
@@:
mov cx, 38
push di
rep stosw
pop di
 
cmp save_descript_size, bx
jz @f
 
 
add di, 160
dec bx
jnz @b
 
@@:
pop di
;enter in mess
.show_mess_prev_eq:
lodsb
mov ah, color_sym_lettuce;color_sym_turquoise
; sub di,2
cmp al, '"'
jz .loop_message
cmp al, "'"
jnz .end_sh_desc_sec
 
.loop_message:
mov cx, 38
@@:
lodsb
cmp al, '"'
jz .end_sh_desc_sec
cmp al, "'"
jz .end_sh_desc_sec
stosw
loop @b
add find_sec_di, 160
mov di, find_sec_di
dec save_cx_d
cmp save_cx_d, 0
jnz .loop_message
 
.end_sh_desc_sec:
push save_cx_d
pop save_descript_size
 
push cs
pop ds
jmp .exit
 
 
.rest_value_loop_sh_d:
mov di, ax
mov cx, bx
jmp .start_p_sh_d
 
.exit:
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/debug_msg.inc
0,0 → 1,77
; Copyright (c) 2009, <Lrz>
; 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.
;*****************************************************************************
 
;Тут определены все сообщения, которые нужны в процессе отладки, и совсем не нужны в рабочей копии программы.
If DEBUG
cseg_msg db ' - Adress of code segment',0
stack_msg db 'Set stack & segments is have completed',0
show_string db 'Have loaded size:'
show_decode db ' ',0
show_db1 db ' -Message debug1',0
show_db2 db ' -Message debug2',0
 
 
lm_l_found db '[loader] is found',0
lm_lf_timeout db 'timeout is found',0
lm_lf_default db 'name default is found and end parsing section',0
lm_lf_section db 'found section [',0
lm_lf_default_f db 'found default parametr',0
lm_l_end db 'section [loader] is end',0
show_all_sect db 'SHOW ALL Sections',0
no_show_only_w db 'Not show sections - only work on default sect',0
_not_found db '[ not found',0
_found_1 db '[] found',0
_found_2 db '[ found',0
say_hello db 'Hello $)',0
ramdiskFS_st db 'Start use_RamdiskFS macros',0
free_memory_msg db ' -Kb availability system free memory',0
RamdiskSize_msg db ' -Kb equal RamdiskSize',0
RamdiskSector_msg db ' -byts RamdiskSector',0
RamdiskCluster_msg db ' -RamdiskCluster',0
RamdiskFile_msg db ' -size RamdiskFile',0
fat_create_msg db ' -first create fat table, point to next block',0
BPB_msg db ' -in byte, why we get data from move BPB struct',0
firstDataSect_msg db ' -first data sector, offset to data in sectors',0
size_root_dir_msg db ' -size root dir in sectrors',0
DataClasters_msg db ' -size data in Clasters',0
first_entry_in_fat db ' -data segment in FIRST entry FAT',0
check_root_fat_ db ' : --------------',0
check_name_fat_msg_y db 'Name is present that is BAD',0
check_name_fat_msg_n db 'Name is not present that is GOOD',0
name_of_seg_get_64 db ' -name of seg where we get 64 Kb of data',0
convertion_file_name_msg_y db '->Destination name of file is GOOD',0
convertion_file_name_msg_n db '->Destination name of file is BAD',0
alarm_msg db '%%%%%%%% WARNING: MISS THE FILE %%%%%%%%%%%',0
start_making_FAT12_msg db '>>>>>> Begin make a RAMDISK and FS after 1 Mb <<<<<<<',0
make_fat12_RFS_msg db '-Make FAT12 Ram FS',0
get_type_FS_msg db '-End make RamDisk',0
seg_where_get_data db ' - Segment where we get data for move up file',0
return_code_af_move db ' -return code after 0x87 int 0x15, move block',0
return_code_af_fat_m db ' -return code after 0x87 int 0x15, move fat struc',0
 
 
 
end if
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/loader.asm
0,0 → 1,317
; Copyright (c) 2008-2009, <Lrz>
; 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 nickname <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.
;*****************************************************************************
 
;start of the project 13.02.2008 year.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Secondary Loader copyright Alexey Teplov nickname <Lrz>
;if you need log preproc
;/////////////
;include 'listing.inc'
;enable listing
;////////////
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;start of code: ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
use16
org 0x0
jmp start
include 'sl_equ.inc' ; в файле размещены все equ предопределения
include 'boot_st.inc'
include 'debug_msg.inc' ;here is message from debug
include 'parse_dat.inc'
include 'sl_proc.inc'
include 'parse.inc'
include 'parse_loader.inc'
include 'parse_any.inc'
include 'parse_def_sect.inc'
include 'parse_err.inc'
 
file_data dw 0x0,ini_data_ ;формат: смещение: сегмент т.к. используется les
size_data dw 16 ;16 блоков по 4 кб т.е предел до 64 кб
name_ini_f db 'kord/startos.ini',0
 
;////////////
loader_callback dd ?
load_drive dw ?
load_ft dw ?
;Start code
 
start:
; Save far pointer to callback procedure, ds:si is point
mov word [cs:loader_callback], si
mov word [cs:loader_callback+2], ds
; Save type of drive
mov word [cs:load_drive], ax
; Save type of FT
mov word [cs:load_ft], bx
; set up stack
mov ax, cs
mov ss, ax
xor sp, sp
; set up segment registers
mov ds, ax
mov es, ax
; just to be sure: force DF=0, IF=1
cld
sti
 
; set videomode
mov ax, 3
int 0x10
 
mov si, version
call printplain
mov al, '#'
mov cx, 80
;input cx=size al=char будет вывден символ сколько раз указано в cx
@@:
call putchar
loop @b
 
if DEBUG
pushad
mov ax, cs
shl eax, 4 ; в десятичной системе адрес сегмента
mov cx, 0xa
mov di, cseg_msg
call decode
;***************
mov si, cseg_msg
call printplain
popad
end if
 
 
if DEBUG
mov si, stack_msg
call printplain
end if
 
; Require 586 or higher processor (cpuid and rdtsc,rdmsr/wrmsr commands)
; install int 6 (#UD) handler
xor bx, bx
mov ds, bx
push word [bx+6*4+2]
push word [bx+6*4]
mov word [bx+6*4], ud16
mov word [bx+6*4+2], cs
; issue CPUID command
xor eax, eax ; N.B.: will cause #UD before 386
cpuid ; N.B.: will cause #UD before later 486s
test eax, eax
jz cpubad
; get processor features
xor eax, eax
inc ax
cpuid
test dl, 10h ; CPUID[1].edx[4] - TSC support
jz cpubad
test dl, 20h ; CPUID[1].edx[5] - MSR support
jnz cpugood
 
ud16: ; #UD handler, called if processor did not recognize some commands
cpubad:
; restore int 6 (#UD) handler
pop word [6*4]
pop word [6*4+2]
; say error
push cs
pop ds
mov si, badprocessor
sayerr:
call printplain
jmp $
 
cpugood:
; restore int 6 (#UD) handler
pop dword [6*4]
push cs
pop ds
 
; set up esp
movzx esp, sp
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; init memory
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 
 
 
; Load startos.ini
mov cx, loop_read_startos_file ;кол-во попыток чтения файла конфигурации startos.ini
align 4
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Load startos.ini ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
load_startos_file:
 
xor ax, ax
mov di, file_data
inc ax ;function 1 - read file
push cx
call far dword [loader_callback]
pop cx
push cs
push cs
pop ds
pop es
 
test bx, bx
jz check_conf_file
dec cx
jnz load_startos_file
 
;SET DEFAULT Not use ini file
error_ini:
mov si, error_ini_f1 ;Error: cannot load ini file, buffer is full
dec bx
jz err_show_ini
mov si, error_ini_f2 ;Error: ini file not found
dec bx
jz err_show_ini
mov si, error_ini_f3 ;Error: cannot read ini file
dec bx
jz err_show_ini
 
mov si, error_ini_nf ;Error: unrecognized error when loading ini file
err_show_ini:
call printplain
mov si, error_ini_common
call printplain
; wait for keypress
xor ax, ax
int 16h
 
ini_loaded:
 
jmp $
 
align 4
check_conf_file:
;Check config file in current dir
push ax ;save size file
if DEBUG
mov cx, 0x0a
mov di, show_decode
call decode
;Show size
mov si, show_string
call printplain
end if
 
 
;Show message
mov si, load_ini
call printplain
 
pop cx ;restore size file
use_parse ;parsing startos.ini
;
jmp ini_loaded
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;DATA
;;;;;;;;;;;;;;;;;;;;;;;;;;;
; table for move to extended memory (int 15h, ah=87h)
align 4
table_15_87:
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
 
db 0xff,0xff
db 0x0,0x10
db 0x00,0x93,0x0,0x0
 
db 0xff,0xff,0x0,0x00,0x10,0x93,0x0,0x0
 
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
db 0x00,0x00,0x0,0x00,0x00,0x00,0x0,0x0
 
fat12_buffer:
.BS_jmpBoot db 0x90,0x90,0x90 ;3 байта NOP инструкция - ничего не делать
.BS_OEMName db 'K SyS 64' ;8 байт
.BPB_BytsPerSec dw 512 ;кол-во байтов в секторе может быть любое 512 1024 2048 4096 2 байта
.BPB_SecPerClus db 0x1 ;кол-во секторов в кластере
.BPB_RsvdSecCnt dw 0x1 ;для FAt12/16 только 1, для FAT32 обычно 32
.BPB_NumFATs db 0x1 ;кол-во фат таблиц, на тот случай если будет сброс на дискету образа рам диска
.BPB_RootEntCnt dw 512 ;для мак совместимости с fat16
.BPB_TotSec16 dw 0x0 ;кл-во секторов
.BPB_Media db 0xF0
.BPB_FATSz16 dw 0x0
.BPB_SecPerTrk dw 0x0 ;содержит геометрию диска для RAMFS на как бы без разницы, пока пустое поле, позже внести реальные значения.
.BPB_NumHeads dw 0x0
.BPB_HiddSec dd 0x0 ;кол-во скрытых секторов
.BPB_TotSec32 dd 0x0
.BS_DrvNum db 'R' ;от слова RAM
.BS_Reserved1 db 0x0
.BS_BootSig db 0x29
.BS_VolID db 'RFKS'
.BS_VolLab db 'RAM DISK FS' ;11 символов
.BS_FilSysType db 'FAT12 ' ;8 символов
;62 байта структура fat12.
db (512-($-fat12_buffer))dup(0x90)
 
 
 
;структура для дирректории fat
struc FAT_32_entry ;Byte Directory Entry Structure
{
.DIR_Name rb 11
.DIR_Attr db ?
.DIR_NTRes db ?
.DIR_CrtTimeTenth db ?
.DIR_CrtTime dw ?
.DIR_CrtDate dw ?
.DIR_LstAccDate dw ?
.DIR_FstClusHI dw ?
.DIR_WrtTime dw ?
.DIR_WrtDate dw ?
.DIR_FstClusLO dw ?
.DIR_FileSize dd ?
 
 
}
;Тут будут распологатсья данные, которые затруднительно распологать в стековой области....
;;;
;timer
shot_name_fat rb 11 ;временный буфер для fat12, в нем храняться имена файлов приведенные к правилам FAT /* вдальнейшем перенести в стэк
 
if DEBUG
rb 1 ;нужен для отладки и вывода имени файла после преобразования
dest_name_fat db 24 dup('_');12
db 0x0
end if
 
value_timeout rw 1 ;value to timeout
old_timer rd 1 ;старое значение вектора таймера
start_timer rd 1 ;значение таймера
timer_ rd 1 ;новое значение вектора таймера т.е. SL
start_stack rw 1 ;save stack
save_bp_from_timer rw 1 ;save bp from timer
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/parse.inc
0,0 → 1,118
; Copyright (c) 2009, <Lrz>
; 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 nickname <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.
;*****************************************************************************
 
; Модуль парсинга - это стандартный компонент, встраиваемый во вторичный загрузчик.
; Данный модуль позволяет стандартно произвести разбор ini файла
; (и с использованием полученных данных ОС будет загружаться дальше).
; В начале найдем открывающий "[" - это будет указывать на начало
; секции. Поддерживается 1 секция это [loader], остальные секции могут иметь
; любые имена, но они должны быть заключены в в скобки []
macro use_parse
{
;input cx=size of ini file
parse_start:
;es:di as 2000:0000 new segment
;установим указатель на загруженный блок
enter 256, 0 ;set 16 byte for current task in stack
;we are is not use bp because bp is pointer on array 16 byte
mov word [save_bp_from_timer], bp ;save point to own data array
mov save_cx, cx ;it's placed size of ini file
les di, dword [file_data]
;обнулим все переменные выделенные из стека
;init flag
xor ax, ax
mov status_flag, ax
;set data size
mov info_real_mode_size, ini_data_ +0x1000 ;изменим значение занятости памяти
 
;поиск начала блока.
;///////////check [loader]
cld
 
mov ret_on_ch, .start ;set return
mov al, byte [es:di]
push word .first_ret
cmp al, ' '
jz .first_sp_1
jmp get_firs_sym.not_space
.first_sp_1:
jmp get_firs_sym.first_sp
 
.start:
call get_firs_sym ;get first symbol on new line
.first_ret: ;первый возврат
; jcxz .end_file ;.end_loader ;found or not found parametrs in section exit in section
test cx, cx
jz error.not_loader
cmp al, '['
jz .parse_loader
jmp .start
;////// проверка на наличее секции loader
use_parse_loader
;pause
if DEBUG
xor ax, ax
int 16h
end if
;////// вывод графического экрана, выбор, секции под дефолту
use_any_sec
;парсинг выбраной или дефолтной секции т.е. разбор параметров выполнение сценария
use_parse_def_sect
 
;//////////////////
;/end parse block
;//////////////////
;.end_bl:
; mov cx,bx
;
; jmp .start
 
.exit:
 
; mov si,parse_ini_end
; call printplain
;
;if DEBUG
; pusha
; mov ax,cx
; mov cx,0x0a
; mov di,show_db1_dec
; mov dword[ds:di],' '
; call decode
;Show size
; mov si,show_db1
; call printplain
;
; popa
;end if
jmp $
 
;///////////////////procedure //////////
;input es:di - is pointer to date
;cx - counter
;return: cx - status if =0 - end of date else es:di point to first symbol on new line
 
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/parse_dat.inc
0,0 → 1,56
; Copyright (c) 2009, <Lrz>
; 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 nickname <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.
;*****************************************************************************
 
;Тут представленны теги, для сравнения
parse_loader db '[loader]'
parse_loader_e:
parse_l_timeout db 'timeout'
parse_l_timeout_e:
parse_l_default db 'default'
parse_l_default_e:
parse_name db 'ame'
parse_name_e:
parse_descript db 'descript'
parse_descript_e:
 
parse_LoaderModule db 'LoaderModule'
parse_LoaderModule_e:
parse_RamdiskSize db 'RamdiskSize'
parse_RamdiskSize_e:
parse_RamdiskFS db 'RamdiskFS'
parse_RamdiskFS_e:
parse_RamdiskSector db 'RamdiskSector'
parse_RamdiskSector_e:
parse_RamdiskCluster db 'RamdiskCluster'
parse_RamdiskCluster_e:
parse_RFS_FAT db 'FAT'
parse_RFS_FAT_e:
parse_RFS_KRFS db 'KRFS'
parse_RFS_KRFS_e:
parse_Loader_Image db 'LoaderImage'
parse_Loader_Image_e:
parse_RamdiskFile db 'RamdiskFile'
parse_RamdiskFile_e:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/parse_def_sect.inc
0,0 → 1,2121
; Copyright (c) 2009, <Lrz>
; 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 nickname <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.
;*****************************************************************************
 
; в этой секции идет разбор параметров указатель на секцию храниться в point_default
;типы ошибок при обработке макроса
;Макрос RamdiskFS
;/определение флагов в записи корневой директории
ATTR_READ_ONLY equ 0x01
ATTR_HIDDEN equ 0x02
ATTR_SYSTEM equ 0x04
ATTR_VOLUME_ID equ 0x08
ATTR_DIRECTORY equ 0x10
ATTR_ARCHIVE equ 0x20
 
 
 
show_error_1 equ 0x1 ;кончились данные - не запланированный конец секции
show_error_2 equ 0x2 ;нет завершающего символа в размере рам диска.
show_error_3 equ 0x4 ; рам диск будет иметь размер =64 кб.
show_error_4 equ 0x8 ;
 
macro use_parse_def_sect
{
mov di, point_default
push ini_data_
pop es
mov si, point_to_point_def
sub si, 2
mov cx, [si] ;загрузим указатель наследующию секцию
 
xor ax, ax ;обнулим аx для очистки флагов
 
sub cx, di ;вот теперь имеем истиный размер
mov save_cx_d, cx ;сохраним значение cx своей переменной
;обнулим переменную флагов, это необходимо, для того, что бы избежать обработку повторяющихся значений
 
mov status_flag, ax
;;;;
;ВХод в обработку парсинга значений секций. es:di - указатель на начало секции cx размер секции доступной для парсинга
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;соглашение не разрушаем bp, es, cs, sp
;use_Loader_Image ;загрузить образ выше 1 мб
use_RamdiskFS
;проверяется самый последний.
use_LoaderModule ;особенность - передает управление на загруженный модуль.
}
 
macro use_LoaderModule
;как вариант сейчас используется модель, при загрузке модуля на него передается управление, решение временое
;управление будет передаваться только после обработки всей секции
{
local .found_end_str
 
mov di, point_default ;restore value
mov cx, save_cx_d
;обработка конструкции типа LoaderModule=kord/kolibri.ldm
.start_p_LM:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz ._afterLoaderModule ;нету? ну ладно - следующее значение тогда )
cmp al, 'L'
jnz .start_p_LM
;проверка на значение LoaderModule
; parse_LoaderModule
mov bx, cx
mov ax, di
 
mov si, parse_LoaderModule
mov cx, parse_LoaderModule_e - parse_LoaderModule
repe cmpsb
jnz .rest_value_loop_LM ;is not compare
 
sub bx, parse_LoaderModule_e - parse_LoaderModule;correct cx
add bx, cx
mov cx, bx
 
test status_flag, flag_found_LM ;оценка флагов
jz .correct_is_not_set_LM
 
; mov si,found_equal_timeout ;мы нашли что флаг уже установлен, информируем
; call printplain
; jmp .get_next_str
 
.correct_is_not_set_LM:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
jcxz .rest_value_loop_LM ;not found param timeout
cmp ah, byte [es:di-1] ;find '='
jnz .rest_value_loop_LM
repe scasb ;cut ' '
inc cx
dec di
;di указывает на начало блока информации, в cx длинна до конца секции.
;после загрузки заноситься значение занятой памяти.
;для того что бы загрузить модуль, воспользуемся callback сервисом
;оригинальное решение - разместим dd перед строчкой и после строчки разместим byte =0
;это выглядит так: в ini файле существует строчка LoaderModule = kord/kernel.loader
;мы ее модифицируем до такого состояния dw,dw,db'kord/kernel.loader',0 конечно сохранив те значения которые мы заменяем
;сохранили певые 2 word
push dword [es:di-6]
lea si, [di-6]
 
push word [es:di-2]
xor ax, ax
mov word [es:di-6], ax ;вносим нужные значения
;info_real_mode_size размер и указатель на область в которую можно загрузиться
mov ax, info_real_mode_size ;0x3000 ;следующий сегмент за данными
 
 
mov word [es:di-4], ax
mov word [es:di-2], 16 ;кол-во блоков по 4 кб =64 кб т.е. больше не считаем
;;;;;; поиск конца строчки
@@:
mov al, byte [es:di]
cmp al, ' '
jz .found_end_str
cmp al, 0xa
jz .found_end_str
cmp al, 0xd
jz .found_end_str
inc di
dec cx
jnz @b
;;;not found допустим,что это конец файла и он не имеет привычного заверешния строки
.found_end_str:
 
push word [es:di]
xor ax, ax
mov word [es:di], ax
; xor ax,ax ; function 1 - read file
mov di, si ;file_data
inc ax
push si
push es
 
push es
pop ds
push cs
pop es
 
call far dword [es:loader_callback]
 
push cs
pop ds
 
pop es
pop si
 
test bx, bx
jnz .error_LM
 
 
jmp far dword [es:si]
 
 
.error_LM:
call error.LoaderModule
.rest_value_loop_LM:
mov di, ax
mov cx, bx
jmp .start_p_LM
 
._afterLoaderModule:
}
 
macro use_RamdiskFS
; формирование рам диска, + обработка всего связанного.
{
if DEBUG
local ._not_memory_in_sys
;//////// clear window
mov ax, 3
int 0x10
;\\\\\\\\\ clear window is end
mov si, ramdiskFS_st
call printplain
end if
; обнулим регистр состояния ошибок
xor ax, ax
mov show_errors_sect, ax
use_free_memory ; узнаем какого объема у нас доступна память. значение возаращается в ax
;узнаем сколько у нас есть памяти и сможем ли мы сформировать нужного размера рам диск.
use_RamdiskSize ;значение возвращается в bx
cmp free_ad_memory, bx ; размерность в кб.
jbe ._not_memory_in_sys
movzx eax, bx
shl eax, 10 ;*1024 = get size in byte
mov save_ramdisksize, eax ; сорханим размер в byte
 
get_type_FS ;получим тип файловой системы + создадим ее
 
._not_memory_in_sys:
if DEBUG
;pause
xor ax, ax
int 0x16
end if
}
macro use_RamdiskSize
{
local .start_p_RS
local .correct_is_not_set_RS
local .CS
local .correct_val_RS
local .correct_size_RS
local .rest_value_loop_RS
local .end_get_RS_ERROR_1
local .end_get_RS_ERROR_2
local ._end_parse_RS
;обрабатывается размер формируемого рам диска
;загрузим начало секции, т.к. будем просматривать с начала и всю секцию
mov di, point_default ;restore value
mov cx, save_cx_d
.start_p_RS:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz ._end_parse_RS ;нету? ну ладно - следующее значение тогда )
cmp al, 'R'
jnz .start_p_RS
;проверка на значения RamdiskSize
; parse_RamdiskSize
mov bx, cx
mov ax, di
 
mov si, parse_RamdiskSize
mov cx, parse_RamdiskSize_e - parse_RamdiskSize
repe cmpsb
jnz .rest_value_loop_RS ;is not compare
 
sub bx, parse_RamdiskSize_e - parse_RamdiskSize;correct cx
add bx, cx
mov cx, bx
 
test status_flag, flag_found_RS ;оценка флагов
jz .correct_is_not_set_RS
 
; mov si,found_equal_timeout ;мы нашли что флаг уже установлен, информируем
; call printplain
; jmp .get_next_str
 
.correct_is_not_set_RS:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
jcxz .end_get_RS_ERROR_1 ;not found param
cmp ah, byte [es:di-1] ;find '='
jnz .start_p_RS ; перейдем на начало и попробуем найти еще секцию
repe scasb ;cut ' '
inc cx
dec di
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Тут нужно преобразовывать строчку в цифровое значение.
;;;;;;;;;;;;;;;;;;;;;;;;;;
xor bx, bx
mov cx, 5
@@:
mov al, byte [es:di]
cmp al, '0'
jb .CS
cmp al, '9'
jbe .correct_val_RS
.CS:
cmp al, 'K'
jz .correct_size_RS
jmp .end_get_RS_ERROR_2
.correct_val_RS:
imul bx, 10
xor al, 0x30
add bl, al
inc di
loop @b
 
.correct_size_RS:
;возможен 1 вариант, когда размер задан в K киллобайтах
;внутренный формат данных это кол-во запрощеной памяти в кб.
test bx, bx
jnz @f ;если значение отлично от 0
;;;;;сообщение об ошибке, размер "найденого" блока =0 минимально мы должны
;установить 64 кб размер рам диска.
or show_errors_sect, show_error_3
mov bx, 64
@@:
jmp ._end_parse_RS
 
 
.rest_value_loop_RS:
mov di, ax
mov cx, bx
jmp .start_p_RS
.end_get_RS_ERROR_1:
;сообщение об ошибке - данный участок кода не был корректно обработан :(
or show_errors_sect, show_error_1
jmp ._end_parse_RS
.end_get_RS_ERROR_2:
or show_errors_sect, show_error_2
 
._end_parse_RS:
if DEBUG
pusha
movzx eax, bx
mov cx, 0x0a
mov di, RamdiskSize_msg
mov dword[ds:di], ' '
mov word [ds:di+4], ' '
call decode
;Show size
mov si, RamdiskSize_msg
call printplain
 
popa
end if
 
}
 
macro use_free_memory
{
local _support_function_use_free_memory
;макрос для получения общего числа доступной памяти в кб, для формирования рам диска за пределами 1 мб.
;используется 0х88 функция 0х15 прерывания
; если поддерживается функция, то в ax значение в кб, если нет, то в ax=0
mov ah, 0x88 ;ah,0x88
int 0x15
jnc ._support_function_use_free_memory
xor ax, ax
;возвращает в ax число в кб
._support_function_use_free_memory:
mov free_ad_memory, ax ; если не поддерживается биосом, то в ax=0
if DEBUG
pushad
movzx eax, ax
mov cx, 0x0a
mov di, free_memory_msg
mov dword[ds:di], ' '
mov word [ds:di+4], ' '
call decode
;Show size
mov si, free_memory_msg
call printplain
 
popad
end if
 
 
 
 
}
macro show_ERRORS
{
 
}
 
macro get_type_FS ;получить и создать образ для заданной RFS.
{
mov di, point_default ;restore value
mov cx, save_cx_d
.start_g_tpe_RFS:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz ._end_parse_FRS ;._end_get_type_RFS ;нету? ну ладно - следующее значение тогда )
cmp al, 'R'
jnz .start_g_tpe_RFS
;проверка на значения RamdiskSize
; parse_RamdiskSize
mov bx, cx
mov ax, di
 
mov si, parse_RamdiskFS
mov cx, parse_RamdiskFS_e - parse_RamdiskFS
repe cmpsb
jnz .start_g_tpe_RFS_rest_v ;is not compare
 
sub bx, parse_RamdiskFS_e - parse_RamdiskFS;correct cx
add bx, cx
mov cx, bx
 
test status_flag, flag_found_GTRFMS ;оценка флагов
jz .correct_is_not_set_FRS
 
; mov si,found_equal_timeout ;мы нашли что флаг уже установлен, информируем
; call printplain
; jmp .get_next_str
 
.correct_is_not_set_FRS:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
test cx, cx
jz .end_get_FRS_ERROR_1 ;not found param
cmp ah, byte [es:di-1] ;find '='
jnz .start_g_tpe_RFS ; перейдем на начало и попробуем найти еще секцию
repe scasb ;cut ' '
inc cx
dec di
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Тут нужно преобразовывать строчку в цифровое значение.
;;;;;;;;;;;;;;;;;;;;;;;;;;
mov bx, cx
mov ax, di
 
mov si, parse_RFS_FAT
mov cx, parse_RFS_FAT_e - parse_RFS_FAT
repe cmpsb
jnz .krfs_cmp ;is not compare
 
make_FAT_RamFS ;сделать
 
if DEBUG
pusha
mov si, make_fat12_RFS_msg
call printplain
popa
end if
jmp ._end_parse_FRS
 
.krfs_cmp:
mov cx, bx
mov di, ax
 
mov si, parse_RFS_KRFS
mov cx, parse_RFS_KRFS_e - parse_RFS_KRFS
repe cmpsb
; jnz @f ;is not compare
 
jmp ._end_parse_FRS
 
 
.start_g_tpe_RFS_rest_v:
mov cx, bx
mov di, ax
jmp .start_g_tpe_RFS
.end_get_FRS_ERROR_1:
;сообщение об ошибке - данный участок кода не был корректно обработан :(
or show_errors_sect, show_error_1
jmp ._end_parse_FRS
.end_get_FRS_ERROR_2:
or show_errors_sect, show_error_2
 
._end_parse_FRS:
if DEBUG
pusha
mov si, get_type_FS_msg
call printplain
popa
end if
 
 
 
}
macro make_FAT_RamFS
{
local .RS1
local .fat12
local .fat16
; мы должны сформировать в начальный образ Ram FS, а потом записать его за область выше 1 мб..
;для случая с FAT12
; mov di,fat12_buffer ;ds должен быть = cs
;es:di - указывают на начало блока для формирования рам фс.
use_RamdiskSector ;возращаемое значение в ax размер сектора в байтах
cmp ax, 4096;по спецификации значение должно быть в пределах от 1 до 4096
ja .RS1
test ax, ax
jnz @f ;ошибка если сюда прыгнули все таки ...
 
.RS1:
mov word [fat12_buffer.BPB_BytsPerSec], 512
;;;;;;;;;;скажем что по дефолту будем юзать значение...
@@:
mov word [fat12_buffer.BPB_BytsPerSec], ax;тут все ок
 
;BPB_SecPerClus кол-во секторов в кластере
use_RamdiskCluster ;возращаемое значение в al
cmp al, 128
ja @f
; test al,0x1 ;проверка на кратность )
; jnz @f
 
mov byte [fat12_buffer.BPB_SecPerClus], al
 
;incorrect value will be set dafault
 
;ниже некорректное значение в т.к. размер кратен 2 и в диапазоне от 1 до 128 включительно
; мы должны ругнуться на это
;@@: ;mov byte [fat12_buffer.BPB_SecPerClus],1
 
;;;;; определеим какая у нас будет использоваться FAT
;по условию, fat12<4085<=fat16<65525<=fat32
; fat12_buffer.BPB_BytsPerSec*fat12_buffer.BPB_SecPerClus = кол-во секторов
movzx eax, word [fat12_buffer.BPB_BytsPerSec]
movzx ebx, byte [fat12_buffer.BPB_SecPerClus]
 
imul ebx, eax;тут размерность сектора
mov eax, save_ramdisksize ;размер запрошенного рам диска в байтах
cdq
idiv ebx
;;;;;;;; сейчас частное в eax, а остаток в edx
;получим кол-во секторов, и можем уже определить тип FAT которую нужно делать.
cmp eax, 4085
jb .fat12
cmp eax, 65525
jb .fat16
;;;;;;;;;;;;;;;;;;;;;;;; тут fat32
mov set_ramfs, 32 ;установим тип файловой системы
mov word [fat12_buffer.BPB_RsvdSecCnt], 32
xor eax, eax
mov word [fat12_buffer.BPB_RootEntCnt], ax
mov word [fat12_buffer.BPB_TotSec16], ax
mov dword [fat12_buffer.BPB_TotSec32], eax
 
 
.fat16: ;fat16
;Для FAT12 и FAT16 дисков это поле содержит количество секторов, а BPB_TotSec32 равно 0, если значение <умещается> (меньше 0x10000).
jmp $
mov set_ramfs, 16 ;установим тип файловой системы
movzx ebx, byte [fat12_buffer.BPB_SecPerClus]
imul eax, ebx
 
cmp eax, 0x10000
jae @f
mov word [fat12_buffer.BPB_TotSec16], ax
mov dword [fat12_buffer.BPB_TotSec32], 0
@@:
;количество секторов занимаемое одной копией фат
; mov word [fat12_buffer.BPB_FATSz16],0x9 ;Для FAT12/FAT16 это количество секторов одной FAT. ??
;;;; заполним BPB_RootEntCnt Для FAT12 и FAT16 дисков, это поле содержит число
;32-байтных элементов корневой директории. Для FAT32 дисков, это поле должно
;быть 0. Пока константа, нужно будет позже доделать.
mov eax, root_dir_entry_count
mov word [fat12_buffer.BPB_RootEntCnt], ax ; count of 32-byte dir. entries (224*32 = 14 sectors= 7 kb)
;по документации рекомендуют отрезать 16 кб для рут дир но это оч много, даже для коос. имхо для начала хватит и 7 кб
;;;;;;;
;Для FAT16 это количество секторов одной FAT. Для FAT32 это значение
;равно 0, а количество секторов одной FAT содержится в BPB_FATSz32.
;RootDirSectors = ((BPB_RootEntCnt * 32) + (BPB_BytsPerSec - 1)) / BPB_BytsPerSec;
 
;TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors);
;TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
;If(FATType == FAT32)
; TmpVal2 = TmpVal2 / 2;
;FATSz = (TMPVal1 + (TmpVal2 - 1)) / TmpVal2;
;If(FATType == FAT32) {
; BPB_FATSz16 = 0;
; BPB_FATSz32 = FATSz;
;} else {
; BPB_FATSz16 = LOWORD(FATSz);
; /* there is no BPB_FATSz32 in a FAT16 BPB */
;}
;=====================================
;RootDirSectors
movzx ebx, word [fat12_buffer.BPB_BytsPerSec]
imul eax, 32
add eax, ebx
dec eax
 
cdq
idiv ebx
;;;;;;;; сейчас частное в eax, а остаток в edx для дискеты 1.44 у нас должно быть значение =14
;BPB_ResvdSecCnt + RootDirSectors
movzx ebx, word [fat12_buffer.BPB_RsvdSecCnt]
add ebx, eax
;DskSize у нас это значение уже получено и доступно
movzx eax, word [fat12_buffer.BPB_TotSec16] ;должен быть в секторах
sub eax, ebx
 
 
;TmpVal1=eax
shl edi, 8 ;=edi*256
movzx ecx, byte [fat12_buffer.BPB_NumFATs]
add edi, ecx
;TmpVal2=edi
add eax, edi
dec eax
cdq
idiv edi
;FATSz = сейчас частное в eax, а остаток в edx
mov word [fat12_buffer.BPB_FATSz16], ax
 
 
 
 
 
 
 
 
.fat12: ;fat12
if DEBUG
; выведем в отладке, что собираемся делать образ диска c FS=fat12
pushad
mov si, start_making_FAT12_msg
call printplain
popad
end if
 
 
 
;Для FAT12 и FAT16 дисков это поле содержит количество секторов, а BPB_TotSec32 равно 0, если значение <умещается> (меньше 0x10000).
mov set_ramfs, 12 ;установим тип файловой системы
movzx ebx, byte [fat12_buffer.BPB_SecPerClus]
imul eax, ebx
 
cmp eax, 0x10000
jae @f
mov word [fat12_buffer.BPB_TotSec16], ax
mov dword [fat12_buffer.BPB_TotSec32], 0
@@:
;количество секторов занимаемое одной копией фат
; mov word [fat12_buffer.BPB_FATSz16],0x9 ;Для FAT12/FAT16 это количество секторов одной FAT. ??
;;;; заполним BPB_RootEntCnt Для FAT12 и FAT16 дисков, это поле содержит число
;32-байтных элементов корневой директории. Для FAT32 дисков, это поле должно
;быть 0. Пока константа, нужно будет позже доделать.
mov eax, root_dir_entry_count
mov word [fat12_buffer.BPB_RootEntCnt], ax ; count of 32-byte dir. entries (224*32 = 14 sectors= 7 kb)
;по документации рекомендуют отрезать 16 кб для рут дир но это оч много, даже для коос. имхо для начала хватит и 7 кб
;;;;;;;
;DskSize(в секторах)*12 (размерность файловой системы, т.е предположим сколько битов потребуется для адресации этого объема) /8 (что получить размер в байтах)
;полученное число округляем в большую сторону кратное сектору т.е. 512 байт Такой подход не универсален, но пока пойдет
;вообще у мелкософт это все считается ручками, но мы будем юзать только под коос рам диск с фат12
movzx eax, word [fat12_buffer.BPB_TotSec16]
imul eax, 12
shr eax, 3 ;делим на 8 но т.е. нам нужно делить еще и на 512 или более в зависимости от размеров кластера
movzx ebx, word [fat12_buffer.BPB_BytsPerSec] ;размер сектора
cdq
idiv ebx ;разделим на размер кластера
;сейчас у нас в eax значение его нужно округлить в большую сторону кратному 512 байтам
;применим следующее очистим and и добавим 512 байт. таким образом выравним на 512 байт
;но т.к. все равно делить нижний код нам не нужен
; and eax,0xfff200
; add eax,0x200 ;добавим 512 байт для 1.44 дискеты идеально подходит ))
 
inc ax
;по идее должно на каждую фат таблицу
;резервироваться 9 секторов т.е. получается 2*9=18+1 =19 секторов т.е. рут дир находиться на с 20 сетора т.е. с адреса 0х2600
;сейчас нужно вычислить сколько будет секторов занимать фат ) нужно разделить на 512
;FATSz = сейчас частное в eax
mov word [fat12_buffer.BPB_FATSz16], ax
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
get_firstDataSector ;получить смещение до данных
;создадим певую запись в фат по определенному адресу.
first_create_fat_table
;закиним BPB файловой системы за 1 мб.
use_BPB_RAM
;
;копирование файла.
use_RamdiskFile
 
;;;; вычисляем указатель на корневую дир FirstRootDirSecNum = BPB_ResvdSecCnt + (BPB_NumFATs * BPB_FATSz16);
; movzx ebx, [fat12_buffer.BPB_NumFATs]
; movzx eax,ax
; imul eax,ebx
;eax=(BPB_NumFATs * BPB_FATSz16)
; inc eax
; BPB_ResvdSecCnt значение только 1 для fat12/16
;в eax указатель на root dir. для дискеты fat12 должно получиться при кол-во копий fat 1 = 1+ (1*1) =2 или 3
 
if DEBUG
pusha
; mov ax,point_default
; mov ax,cx
mov cx, 0x0a
mov di, show_db1
; mov dword[ds:di],' '
; mov word [ds:di+4],' '
call decode
;Show size
mov si, show_db1
call printplain
;
; xor ax,ax
; int 0x16
popa
end if
 
 
 
 
 
 
 
}
 
macro use_RamdiskSector
{
;для некоторых FS будет игнорироваться
mov di, point_default ;restore value
mov cx, save_cx_d
 
.start_RamdiskSector:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz .end_RamdiskSector ;нету? ну ладно - следующее значение тогда )
 
cmp al, 'R'
jnz .start_RamdiskSector
;проверка на значения RamdiskSize
; parse_RamdiskSize
 
mov bx, cx
mov ax, di
 
mov si, parse_RamdiskSector
mov cx, parse_RamdiskSector_e - parse_RamdiskSector
repe cmpsb
jnz .RamdiskSector_rest_val ;is not compare
 
sub bx, parse_RamdiskSector_e - parse_RamdiskSector;correct cx
add bx, cx
mov cx, bx
 
test status_flag, flag_found_RamdiskSector ;оценка флагов
jz .correct_is_not_set_RamdiskSector
 
; mov si,found_equal_timeout ;мы нашли что флаг уже установлен, информируем
; call printplain
; jmp .get_next_str
 
.correct_is_not_set_RamdiskSector:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
jcxz .end_get_RamS_ERROR_1 ;not found param
cmp ah, byte [es:di-1] ;find '='
jnz .start_RamdiskSector ; перейдем на начало и попробуем найти еще секцию
repe scasb ;cut ' '
inc cx
dec di
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
xor bx, bx
mov cx, 4
@@:
movzx ax, byte [es:di]
cmp al, '0'
jb .end_RamdiskSector
cmp al, '9'
ja .end_RamdiskSector
;;;;;;;;;;;;;;;;;;;
 
imul bx, 10
xor al, 0x30
add bx, ax
 
inc di
 
loop @b
jmp .end_RamdiskSector
 
 
.RamdiskSector_rest_val:
mov cx, bx
mov di, ax
jmp .start_RamdiskSector
.end_get_RamS_ERROR_1:
 
.end_RamdiskSector:
mov ax, bx
 
if DEBUG
pusha
movzx eax, bx;save_cx_d;point_default
mov cx, 0x0a
mov di, RamdiskSector_msg
mov dword[ds:di], ' '
mov dword [ds:di+4], ' '
call decode
;Show size
mov si, RamdiskSector_msg
call printplain
 
popa
end if
 
; pop di
; pop es
}
 
macro use_RamdiskCluster
{
;для некоторых FS будет игнорироваться
; push es
; push di
mov di, point_default ;restore value
mov cx, save_cx_d
; push ini_data_
; pop es
.start_RamdiskCluster:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz .end_RamdiskCluster ;нету? ну ладно - следующее значение тогда )
cmp al, 'R'
jnz .start_RamdiskCluster
;проверка на значения RamdiskSize
; parse_RamdiskSize
 
mov bx, cx
mov ax, di
 
mov si, parse_RamdiskCluster
mov cx, parse_RamdiskCluster_e - parse_RamdiskCluster
repe cmpsb
jnz .RamdiskCluster_rest_val ;is not compare
 
sub bx, parse_RamdiskCluster_e - parse_RamdiskCluster;correct cx
add bx, cx
mov cx, bx
 
test status_flag, flag_found_RamdiskCluster ;оценка флагов
jz .correct_is_not_set_RamdiskCluster
 
; mov si,found_equal_timeout ;мы нашли что флаг уже установлен, информируем
; call printplain
; jmp .get_next_str
 
.correct_is_not_set_RamdiskCluster:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
jcxz .end_get_RamSC_ERROR_1 ;not found param
cmp ah, byte [es:di-1] ;find '='
jnz .start_RamdiskCluster ; перейдем на начало и попробуем найти еще секцию
repe scasb ;cut ' '
inc cx
dec di
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@:
movzx ax, byte [es:di]
cmp al, '0'
jb .end_RamdiskCluster
cmp al, '9'
ja .end_RamdiskCluster
;;;;;;;;;;;;;;;;;;;
xor al, 0x30
 
jmp .end_RamdiskCluster
 
 
.RamdiskCluster_rest_val:
mov cx, bx
mov di, ax
jmp .start_RamdiskCluster
.end_get_RamSC_ERROR_1:
 
.end_RamdiskCluster:
if DEBUG
pusha
mov cx, 0x0a
mov di, RamdiskCluster_msg
; mov word[ds:di],' '
call decode
;Show size
mov si, RamdiskCluster_msg
call printplain
 
popa
end if
 
}
 
macro use_Loader_Image
;предназначен для загрузки образов выше 1 Мб.
;первоначальная версия загружает образ дискеты 1.44 мб
{
local .start_p_LI
local .exit
local .error_LI
local .rest_value_loop
local .found_end_str
mov di, point_default ;restore value
mov cx, save_cx_d
;обработка конструкции типа LoaderModule=kord/kolibri.ldm
.start_p_LI:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz .exit ;нету? ну ладно - следующее значение тогда )
cmp al, 'L'
jnz .start_p_LI
;проверка на значение LoaderModule
; parse_LoaderModule
mov bx, cx
mov ax, di
 
mov si, parse_LoaderImage
mov cx, parse_LoaderImage_e - parse_LoaderImage
repe cmpsb
jnz .rest_value_loop ;is not compare
 
sub bx, parse_LoaderImage_e - parse_LoaderImage;correct cx
add bx, cx
mov cx, bx
 
; test status_flag,flag_found_LM ;оценка флагов
; jz .correct_is_not_set_LI
 
; mov si,found_equal_timeout ;мы нашли что флаг уже установлен, информируем
; call printplain
; jmp .get_next_str
 
;.correct_is_not_set_LI:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
jcxz .rest_value_loop_LI ;not found param timeout
cmp ah, byte [es:di-1] ;find '='
jnz .rest_value_loop_LI
repe scasb ;cut ' '
inc cx
dec di
;di указывает на начало блока информации, в cx длинна до конца секции.
;после загрузки заноситься значение занятой памяти.
;для того что бы загрузить модуль, воспользуемся callback сервисом
;оригинальное решение - разместим dd перед строчкой и после строчки разместим byte =0
;это выглядит так: в ini файле существует строчка LoaderModule = kord/kernel.loader
;мы ее модифицируем до такого состояния dw,dw,db'kord/kernel.loader',0 конечно сохранив те значения которые мы заменяем
;сохранили певые 2 word
push dword [es:di-6]
lea si, [di-6]
 
push word [es:di-2]
xor ax, ax
mov word [es:di-6], ax ;вносим нужные значения
;info_real_mode_size размер и указатель на область в которую можно загрузиться
mov ax, info_real_mode_size ;0x3000 ;следующий сегмент за данными
 
 
mov word [es:di-4], ax
mov word [es:di-2], 16 ;кол-во блоков по 4 кб =64 кб т.е. больше не считаем
;;;;;; поиск конца строчки
@@:
mov al, byte [es:di]
cmp al, ' '
jz .found_end_str
cmp al, 0xa
jz .found_end_str
cmp al, 0xd
jz .found_end_str
inc di
dec cx
jnz @b
;;;not found допустим,что это конец файла и он не имеет привычного заверешния строки
.found_end_str:
; чтение блока по 64 кб в сегмент и забрасывание его выше 1 мб.
push word [es:di]
xor ax, ax
mov word [es:di], ax
; xor ax,ax ; function 1 - read file
mov di, si ;file_data
inc ax
push si
push es
call far dword [loader_callback]
push cs
pop ds
 
pop es
pop si
 
test bx, bx
jnz .error_LM
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; забрасывание блока в 64 кб выше 1 мб.
mov si, table_15_87
push es
push ds
pop es
mov cx, 256*18
mov ah, 0x87
int 0x15
pop es
pop dx cx
test ah, ah
 
 
 
jmp far dword [es:si]
 
 
 
 
.rest_value_loop:
mov di, ax
mov cx, bx
jmp .start_p_LI
 
.exit:
 
 
 
}
 
 
 
macro name_in_root_fat
;макрос, который записывает информацию о загруженном файле в корневую фат таблицу
{
 
}
 
 
 
macro use_RamdiskFile
{
;загрузка файлов с использование callback сервиса первичного загрузчика
;используется только для загрузки необходимых и небольших файлов, т.к. достаточно медленно работает
;для загрузки использует 0х87 функцию int 0x15 прерывания - загрузка блоков данных до 64 кб выше 1 мб
local .start_loop
local ._end
local .rest_value_loop
local .error
mov di, point_default ;restore value
mov cx, save_cx_d
mov data_offset, 0 ;clean offset
;обработка конструкции типа LoaderModule=kord/kolibri.ldm
.start_loop:
call get_firs_sym ;get first symbol on new line
test cx, cx
jz ._end ;нету? ну ладно - следующее значение тогда )
cmp al, 'R'
jnz .start_loop
;проверка на значение RamdiskFile
mov bx, cx
mov ax, di
 
mov si, parse_RamdiskFile
mov cx, parse_RamdiskFile_e - parse_RamdiskFile
repe cmpsb
jnz .rest_value_loop ;is not compare
 
sub bx, parse_RamdiskFile_e - parse_RamdiskFile;correct cx
add bx, cx
mov cx, bx
; test status_flag,flag_found_LM ;оценка флагов
; jz .correct_is_not_set_LM
 
; mov si,found_equal_timeout ;мы нашли что флаг уже установлен, информируем
; call printplain
; jmp .get_next_str
 
;.correct_is_not_set_LM:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
test ecx, ecx
jz .rest_value_loop ;not found param timeout
cmp ah, byte [es:di-1] ;find '='
jnz .rest_value_loop
repe scasb ;cut ' '
inc cx
dec di
 
mov save_di_RAMDISK, di
mov save_cx_RAMDISK, cx
;di указывает на начало блока информации, в cx длинна до конца секции.
;после загрузки заноситься значение занятой памяти.
;для того что бы загрузить модуль, воспользуемся callback сервисом
;оригинальное решение - разместим dd перед строчкой и после строчки разместим byte =0
;это выглядит так: в ini файле существует строчка RamdiskFile = @menu,@menu
;мы ее модифицируем до такого состояния dw,dw,db'@menu',0 конечно сохранив те значения которые мы заменяем
;сохранили певые 2 word
 
;
@@:
mov al, byte [es:di]
cmp al, ',' ; т.е. ищем разделитель
jz .found_end_str
inc di
dec cx
jnz @b
;;;not found допустим,что это конец файла и он не имеет привычного завершения строки
.found_end_str:
; mov al,byte [es:di]
; cmp al,' ' ; убираем пробелы, если они есть
; jnz @f
; inc di
; dec cx
; jnz .found_end_str
 
;@@:
mov point_to_dest_file_name, di
inc di
;проверка индивидуальности имени файла
check_name_file
;/restore di - point and cx -size section
mov di, save_di_RAMDISK
mov cx, save_cx_RAMDISK
 
test al, al
jnz .start_loop ;если в al значение не =0, то такое имя уже существует в системе.
 
 
 
push dword [es:di-6]
lea si, [di-6]
 
push word [es:di-2]
push di
xor ax, ax
mov word [es:di-6], ax ;вносим нужные значения
;info_real_mode_size размер и указатель на область в которую можно загрузиться
mov ax, info_real_mode_size ;0x3000 ;следующий сегмент за данными
 
 
mov word [es:di-4], ax
mov word [es:di-2], 16 ;кол-во блоков по 4 кб =64 кб т.е. больше не читаем
 
mov di, point_to_dest_file_name
 
if DEBUG
pushad
; mov ax,di
mov cx, 0x0a
mov di, name_of_seg_get_64
mov dword[ds:di], ' '
mov word[ds:di+4], ' '
call decode
;Show size
mov si, name_of_seg_get_64
call printplain
 
popad
end if
 
push word [es:di]
push cx
xor ax, ax
mov word [es:di], ax
; xor ax,ax ; function 1 - read file
push di
mov di, si ;file_data
inc ax
push si
push es
push bp
 
push es
pop ds
push cs
pop es
 
call far dword [es:loader_callback]
 
 
push cs
pop ds
 
pop bp
pop es
pop si
 
cmp bx, 2
ja .error
; сейчас у нас в dx:ax размер файла, который мы загрузили.
; возможна ситуация, когда в bx=1 т.е. есть еще данные на диске
mov status_flag_loader_f, bx
 
shl edx, 16
mov dx, ax
; shr edx,10 ;размер файла в кб.
;;в edx размер в байтах.
mov save_file_size, edx
mov eax, edx
;восстановим полностью файл сценария
pop di
pop cx ;длинна остатка с 2-ой частью имени т.е. с именем назначением.
pop word [es:di]
pop di
pop word [es:di-2]
pop dword [es:di-6]
 
if DEBUG
pushad
mov cx, 0x0a
mov di, RamdiskFile_msg
mov dword[ds:di], ' '
call decode
;Show size
mov si, RamdiskFile_msg
call printplain
 
popad
end if
 
 
 
 
 
 
 
 
 
 
; загрузим чему у нас равен кластер
; mov ax,word [fat12_buffer.BPB_BytsPerSec] ;кол-во байтов в секторе может быть любое 512 1024 2048 4096 2 байта
; movzx bx,byte [fat12_buffer.BPB_SecPerClus] ;кол-во секторов в кластере
; imul ax,bx
;сейчас в eax размер кластера (512) байт
;в edx длина файла в байтах до 64 кб
;закиним файл за 1 мб
;1 нам нужно составить фат таблицу т.е. произвести разметку рамдиска, затем перенесем по адресу файл
 
;записать инфорамацию о файле в корневую директорию
register_file_in_fat
;перенести за 1 мб содержимое файла
move_file_up
 
;проверим, загружен ли до конца файл? т.е. если размер файла больше чем 64 кб, то будет подгружать оставшиеся блоки
cmp status_flag_loader_f, 0x1
jnz @f
;нужно дозагузить данные файла и перенести их за 1-ый мб согласно фат структуре
 
 
 
 
 
 
 
 
 
@@:
;тут организован цикл по загрузке файлов в корневую директорию
mov di, save_di_RAMDISK
mov cx, save_cx_RAMDISK
if DEBUG
pusha
xor ax, ax
int 0x16
popa
end if
 
 
jmp .start_loop
 
 
.error:
;call error.LoaderModule
;fixme!
.rest_value_loop:
mov di, ax
mov cx, bx
jmp .start_loop
 
._end:
;перенесем за 1-ый мб фат и рут дир
move_up_fat_and_root_d
 
 
 
 
 
 
;загрузка блока
; mov ah,0x87
; mov cx, ;size in byte
 
;es:si point to descripts
 
 
}
 
macro use_BPB_RAM ;закинуть самые первые 512 байт за 1-й мб
;данный макрос закидывает BPB структуру т.е. первые 512 байт, пока только фат12 за 1 мб
{
mov ax, fat12_buffer
mov si, table_15_87
add word [si+8*2+2], ax
push es
push ds
pop es
mov cx, 256 ;бут сектор укладывается в 512 байт 512/2=256
mov ah, 0x87
int 0x15
pop es
;add 512 byte for destination adress
; add dword [si+8*3+2], 512
; test ah, ah
; jz
if DEBUG
pusha
mov ax, word [si+8*2+2]
mov cx, 0x0a
mov di, BPB_msg
call decode
;Show size
mov si, BPB_msg
call printplain
popa
end if
}
macro first_create_fat_table
;данный макрос создает оформляет 3 первых байта fat таблицы, и устанавливает указатель на следующий блок, и вносит 0 значение
;для смещения в корневой таблице.
{
mov al, byte [fat12_buffer.BPB_Media]
 
 
push ds
 
 
mov di, info_real_mode_size
add di, 0x1000
 
if DEBUG
pushad
 
mov ax, info_real_mode_size
add ax, 0x1000
; mov ax,ds
mov cx, 0xa
mov di, first_entry_in_fat
mov dword [di], ' '
mov word [di+4], ' '
call decode
;Show size
mov si, first_entry_in_fat
call printplain
 
xor ax, ax
int 0x16
popad
end if
 
 
push di ; push word info_real_mode_size+0x1000 ;cледующий сегмент за загруженным участком
xor di, di
mov point_to_free_root, di ;значение смещения =0 в корневой фат таблице описания
 
pop ds ; загружен следующий сегмент т.е. пустой сегмент
 
mov byte [di], al
or ax, -1
inc di
mov word [di], ax
 
pop ds
mov point_next_fat_str, 3
 
if DEBUG
pushad
mov ax, point_next_fat_str
mov cx, 0x0a
mov di, fat_create_msg
call decode
;Show size
mov si, fat_create_msg
call printplain
popad
end if
 
}
macro register_file_in_fat
;макрос регистрации файла в файловой структуре Fat
;пока поддерживается только фат12, пока ))
;вычисление смежных кластеров и занесение инфы в fat/
{
local .step2
local .step3
local .end
local .eof_file
 
;di point on root dir на фри секцию.
push es
 
mov ax, info_real_mode_size
add ax, 0x1000
mov es, ax ; push word info_real_mode_size+0x1000 ;сегмент следующий за загруженным блоком в 64 кб
 
; определяем тип фат пока не определяем, пока только фат 12
; 12 бит, для вычесления соседних каластеров.
mov di, firstDataSect ;в секторах
sub di, size_root_dir
;теперь в ax размер в секторах начала рут дир
shl di, 9;imul 512
add di, point_to_free_root ;смещение в уже записанных 32-х структурах.
;необходимо внести значение в рут дир т.е. 32 байта
if DEBUG
pushad
; mov ax,point_default
; mov ax,
mov cx, 0x0a
mov di, show_db2
mov dword[ds:di], ' '
mov word [ds:di+4], ' '
call decode
;Show size
mov si, show_db2
call printplain
;
; xor ax,ax
; int 0x16
popad
end if
 
 
 
;gs:di - указатель для внесения инфорации в рут область фат таблицы инормации о файле.
mov si, shot_name_fat
mov cx, 11
;запишем в структуру имя
@@:
lodsb
stosb
loop @b
 
;запишем атрибуты файла и DIR_NTRes - зарезеврированный байт =0
xor ax, ax
mov ah, ATTR_VOLUME_ID
mov word [es:di], ax
add di, 2
;DIR_CrtTimeTenth
mov byte [es:di], 100
inc di
;DIR_CrtTime
mov word [es:di], 0x032b ;дата
add di, 2
;DIR_CrtDate
mov word [es:di], 0x0 ;время ><
add di, 2
;DIR_LstAccDate
mov word [es:di], 0x032b ;дата моего
add di, 2
;DIR_FstClusHI
mov word [es:di], 0x0 ;время для фат12 /16 всегда 0
add di, 2
;DIR_WrtTime
mov word [es:di], 0x0 ;время ><
add di, 2
;DIR_WrtDate
mov word [es:di], 0x032b
add di, 2
mov ax, point_next_fat_str
mov word [es:di], ax
add di, 2
 
push di
;DIR_FstClusLO Младшее слово номера первого кластера.
; mov ax,point_next_fat_str ;загрузим указатель на элемент фат таблицы т.е. это номер фат записи
;FATOffset = N + (N / 2) т.е. это уже у нас смещение мы знаем что -начинается все с 3-го элемента записи фат
mov bx, ax
shr bx, 1
add ax, bx
;в ах сейчас FATOffset
;ThisFATEntOffset = BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec);
mov bx, word [fat12_buffer.BPB_BytsPerSec]
cwd
idiv bx
;ax=ThisFATEntOffset= rem (FATOffset / BPB_BytsPerSec) четный или нечетный указатель.
mov si, ax
;нам нужно в цикле записать все кластеры которые будут использованы для размещения файла.
;узнаем размер кластера.
movzx eax, word [fat12_buffer.BPB_BytsPerSec]
movzx ebx, byte [fat12_buffer.BPB_SecPerClus]
imul eax, ebx
;ax - размер кластера.
;сейчас будем записывать во временный буфер фат таблицу для выбранного файла. Поскольку мы его загрузили возможно не полностью
;мы обработаем запись для фат полностью, в не зависимости от предела буфера где возможна часть файла.
mov ebx, save_file_size ;размер файла в байтах
@@:
sub ebx, eax
cmp ebx, eax
jbe .eof_file
 
inc point_next_fat_str
mov cx, point_next_fat_str ;загрузим указатель на элемент фат таблицы т.е. это номер фат записи
;FATOffset = N + (N / 2) т.е. это уже у нас смещение мы знаем что -начинается все с 3-го элемента записи фат
mov dx, ax
shr dx, 1
add cx, dx
 
 
 
test si, 0x1
jz .step2
shl cx, 4
mov word[es:si], cx
inc si
add cx, ax
jmp @b
 
.step2:
and cx, 0x0FFF
mov word[es:si], cx
inc si
add cx, ax
jmp @b
 
.eof_file:
mov cx, 0x0fff
test si, 0x1
jz .step3
shl cx, 4
mov word[es:si], cx
jmp .end
 
.step3:
and cx, 0x0FFF
mov word[es:si], cx
 
.end:
inc point_next_fat_str
 
pop di
;DIR_FileSize 32-битный DWORD содержит размер файла в байтах.
mov eax, save_file_size
mov dword [es:di], eax
 
if DEBUG
pushad
 
mov di, firstDataSect ;в секторах
sub di, size_root_dir
;теперь в ax размер в секторах начала рут дир
shl di, 9;imul 512
add di, point_to_free_root ;смещение в уже записанных 32-х структурах.
 
push di
 
mov si, dest_name_fat
mov cx, 11
 
;запишем в структуру имя
@@:
mov al, byte [es:di]
inc di
mov byte [ds:si], al
inc si
loop @b
mov di, si
inc di
pop ax
mov cx, 0xa
call decode
 
mov si, dest_name_fat
call printplain
popad
 
END IF
 
 
 
 
 
add point_to_free_root, 32 ;увелицим смещение до следующего значения.
pop es
 
}
 
 
 
 
 
macro get_firstDataSector
;макрос для вычисления певого сектора данных т.е. данных файлов в фате
;вычислим FirstDataSector = BPB_ResvdSecCnt + (BPB_NumFATs * FATSz) + RootDirSectors;
{
mov ax, word [fat12_buffer.BPB_FATSz16]
movzx bx, byte [fat12_buffer.BPB_NumFATs]
imul ax, bx ;9x1=9
;ax=BPB_NumFATs * FATSz
mov bx, word [fat12_buffer.BPB_RootEntCnt] ; count of 32-byte dir. entries (224*32 = 14 sectors= 7 kb)
shr bx, 4 ;imul bx,32 and then div 512 -> in bx size in sectors
add ax, bx ;9+14=23
mov size_root_dir, bx
movzx bx, byte [fat12_buffer.BPB_RsvdSecCnt] ;add 1 for fat 16/12
add ax, bx
;ax=firstDataSector - где начинается первый секторо от 0 сектора в секторах. - фактически = 24 сектор
mov firstDataSect, ax ;сохраним для вычисления
; получимзначение кластеров, это объем в который мы можем записать данные
mov bx, word [fat12_buffer.BPB_TotSec16]
sub bx, ax
mov ax, bx
movzx bx, byte [fat12_buffer.BPB_SecPerClus]
cwd
idiv bx
mov DataClasters, ax
 
if DEBUG
pushad
mov ax, firstDataSect ;первый сектор данных
mov cx, 0x0a
mov di, firstDataSect_msg
call decode
;Show size
mov si, firstDataSect_msg
call printplain
;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ax, size_root_dir ;размер рут дир в сетокторах
mov cx, 0x0a
mov di, size_root_dir_msg
call decode
;Show size
mov si, size_root_dir_msg
call printplain
;;;;;;;;;;;;;;;;;;;;;;;;;;
mov ax, DataClasters;кластеры
mov cx, 0x0a
mov di, DataClasters_msg
call decode
;Show size
mov si, DataClasters_msg
call printplain
popad
 
end if
 
}
 
macro use_RamdiskPATHS
;парсинг пути источника файлов.
{
 
}
 
macro use_RamdiskPATHD
;парсинг пути назначения файлов.
{
 
}
macro check_name_file
;макрос проверки имени на повтор, имя должно быть уникальным.
;входные данные: es- сегмент где лежит файл для парсинга т.е. startos.ini
;di - указатель на имя файла т.е. es:di указывает на имя файла назначения
;выходные данные eax =-1 имя совпало, eax=0 имя не совпало.
{
local .no_equal
local .exit
local .loop_size_root_dir
;вычислим длинну строчки имени назначения, которую будем сравнивать с уже записанными данными.
;преобразуем в аналог фат записи сточку с именем назначения
convertion_file_name ; преобразовали имя по нужным правилам
test ax, ax
jnz .exit
 
lea si, [shot_name_fat] ; desination name of file
 
;вычислим указатель на корневую директорию
mov di, firstDataSect
sub di, size_root_dir
;теперь в ax размер в секторах начала рут дир
shl di, 9;imul 512
;di= Это смещение от начала буфера до рут директории. в пределах 64 кб.
;загрузим значение - т.е. кол-во элементов, которые мы можем просматривать.
mov dx, root_dir_entry_count
mov ax, info_real_mode_size
add ax, 0x1000
 
 
mov gs, ax
.loop_size_root_dir:
DEBUG1 equ 0
if DEBUG1
pushad
push di
mov eax, dword[gs:di]
lea si, [check_root_fat_+14]
mov dword [ds:si], '----'
mov dword [ds:si+4], '----'
mov dword [ds:si+8], '----'
mov dword[ds:si], eax
mov eax, dword[gs:di+4]
mov dword[ds:si+4], eax
mov eax, dword[gs:di+8]
mov dword[ds:si+8], eax
 
;
xor eax, eax
mov ax, gs;point_next_fat_str
mov cx, 0x0a
mov di, check_root_fat_
mov dword [di], ' '
mov word [di+4], ' '
call decode
xor eax, eax
pop ax
mov di, (check_root_fat_+7)
mov dword [di], ' '
mov word [di+4], ' '
call decode
 
;Show size
lea si, [check_root_fat_]
call printplain
 
lea si, [shot_name_fat]
call printplain
 
xor ax, ax
int 0x16
popad
end if
 
xor bx, bx
mov cx, 11 ;size of name in struct FAT
 
@@:
mov al, byte [ds:si+bx] ;ds:si - point to name of convertion variable.
mov ah, byte [gs:di+bx] ;gs:di - point to name in fat struct
inc bx
 
if DEBUG
; pushad
; lea si,[check_root_fat_+14]
; mov dword [ds:si],'----'
; mov word [ds:si],ax
; call printplain
 
; xor ax,ax
; int 0x16
 
; popad
end if
 
 
 
cmp ah, al
jnz .no_equal
 
; dec cx
; jnz @b
loop @b
 
;.succesfuly:
;печально, такое имя уже имеется :(
or ax, -1
jmp .exit
 
 
.no_equal:
add di, 32 ;fat struct =32 byte
dec dx
jnz .loop_size_root_dir
 
;.exit_check_name:
and ax, 0
 
.exit:
 
if DEBUG
pushad
;Show size
lea si, [check_name_fat_msg_n]
test ax, ax
jz @f
lea si, [check_name_fat_msg_y]
call printplain
lea si, [alarm_msg]
@@:
call printplain
popad
end if
 
}
 
 
macro convertion_file_name
;макрос конвертации имени, это нужно поскольку формат представленный не соответсвует фат и напрямую редко можно когда использовать
;преобразование имени типа hello.asm в 'HELLO ASM', в соответствии с правилами fat.
;входные параметры es:di указатель на имя файла которое нужно преобразовать, конечный буфер shot_name_fat
{
local .next_step
local .error
local .st1
local .st2
local .st2_l
local .st3
local .st4_s
local .st4
local .st5
 
;вычислим длинну строчки имени назначения, которую будем сравнивать с уже записанными данными.
; mov di,point_to_dest_file_name входной параметр
mov si, shot_name_fat
or first_input, -1 ;при первом входе устанавливаем флаг
mov cx, 11 ;длинна имени в стуктуре фат таблицы
 
@@:
mov al, byte [es:di]
cmp al, 0xa
jz .st4_s
cmp al, 0xd
jz .st4_s
cmp al, 0x20
jz .st4_s
 
cmp al, 0x20
jb .error
cmp al, 0x22
jz .error
cmp al, 0x2a
jz .error
cmp al, 0x2b
jz .error
cmp al, 0x2c
jz .error
cmp al, 0x2F
jz .error
 
cmp al, 0x3a
jz .error
cmp al, 0x3b
jz .error
cmp al, 0x3c
jz .error
cmp al, 0x3d
jz .error
cmp al, 0x3E
jz .error
cmp al, 0x3F
jz .error
 
cmp al, 0x5b
jz .error
cmp al, 0x5c
jz .error
cmp al, 0x5d
jz .error
 
cmp al, 0x7c
jz .error
 
cmp first_input, -1
jnz .next_step
and first_input, 0 ;сборосим флаг.
cmp al, '.'
jz .error ;обработка точки, файл не может начинаться с точки
 
.next_step:
cmp al, 0x2e
jnz .st2 ;обработка точки, в середине файла
;тут у нас установлен разделитель
;все остальнео место займут пробелы
mov al, ' '
 
;!fixme обработаны не все исключения :(
cmp cl, 3 ;формат файла такой GIDGIDIIASM т.е. gidgidii.asm
jbe .st2
 
 
.st3:
mov byte [si], al
inc si
dec cx
cmp cx, 3
ja .st3
; inc cx
inc di
jmp @b
 
.st2:
cmp al, 0x60
jbe .st2_l
xor al, 0x20;сделаем заглавные буквы
.st2_l:
mov byte [si], al
inc di
inc si
; dec cx
; jnz @b
loop @b
.st5:
xor ax, ax
jmp @f
 
;;;;;;;;файл закончился, и нужно внести в конец пробелы
.st4_s:
mov al, ' '
.st4:
mov byte [si], al
inc si
loop .st4
jmp .st5
 
.error:
or ax, -1
@@:
 
if DEBUG
pushad
mov si, convertion_file_name_msg_y
test ax, ax
jz @f
mov si, convertion_file_name_msg_n
@@:
call printplain
 
mov si, shot_name_fat
mov byte [si+12], 0
call printplain
popad
 
end if
}
 
macro move_file_up
;макрос который перемещает за 1 мб с правилами фат данные файла.
{
local .st1
local .correct_on_byte
;сейчас имеет быть ситуация, когда BPB уже перемещен за 1 мб, фат, и рут дир будут позже перемещены,
;а нам нужно вычислить место, и перенести туда содержимое файла
;полученое значение указывает в байтах на начало данных
 
mov ax, info_real_mode_size ; сегмент где расположены данные
mov si, table_15_87
mov word [si+8*2+2], ax
;смещение до данных уже за 1-м мб
movzx eax, firstDataSect
movzx edx, data_offset
add eax, edx
 
movzx ebx, word [fat12_buffer.BPB_BytsPerSec]
movzx edx, byte [fat12_buffer.BPB_SecPerClus]
imul bx, dx ;получим размер кластера
 
 
 
push ebx ;save bx
 
imul eax, ebx
; shl eax,9 ;умножим на 512
if DEBUG
pushad
xor eax, eax
mov ax, info_real_mode_size
mov cx, 0x0a
mov di, seg_where_get_data
mov dword [di], ' '
mov word [di+4], ' '
call decode
;Show size
mov si, seg_where_get_data
call printplain
popad
 
end if
 
; mov bx,word [fat12_buffer.BPB_BytsPerSec]
; movzx dx,byte [fat12_buffer.BPB_SecPerClus]
; imul bx,dx
; cwd
; idiv bx
 
mov dl, 0x10
 
@@:
cmp eax, 0x00010000
jb @f
 
sub eax, 0x00010000
inc dl
jmp @b
 
 
@@:
mov byte [si+8*3+3], dl ;куда писать
mov word [si+8*3+2], ax
 
mov ecx, save_file_size ;размер файла в байтах.
cmp ecx, 0x0000ffff ;размер блока т.е. 64 кб
jbe .correct_on_byte ;корректировка на байт значения
 
 
 
mov ecx, 0x00010000 ;65536
sub save_file_size, ecx ;отнимим
; jmp .st1 ;получим 0х8000
 
 
 
 
;корректировка значения должна быть выполенена на размер кластера
.correct_on_byte:
;/узнаем размер кластера
pop eax ;restore size of claster
push ecx
@@:
inc data_offset
 
cmp eax, ecx
jae @f
sub ecx, eax
jmp @b
@@:
pop ecx
 
 
 
 
test ecx, 0x1
jz .st1
inc ecx
.st1:
shr ecx, 1 ; преобразовать значение для 0x87 function
 
;перенесем блок за 1 мб
push es
push ds
pop es
 
mov ah, 0x87
int 0x15
pop es
 
if DEBUG
pusha
; mov ax,point_next_fat_str
mov cx, 0x0a
mov di, return_code_af_move
call decode
;Show size
mov si, return_code_af_move
call printplain
popa
 
end if
 
}
 
 
macro move_up_fat_and_root_d
;макрос, который позволяет перенести выше 1 мб в структуру образа фат таблицу и рут директорию
{
local .st1
 
mov ax, info_real_mode_size
add ax, 0x1000
 
mov si, table_15_87
mov word [si+8*2+2], ax
;смещение до данных
mov ax, 512
mov word [si+8*3+2], ax
;fixme! тут необходимо сделать подержку т.е. формировать смещение файла в уже записанных данных.
 
movzx ecx, word [fat12_buffer.BPB_FATSz16]
movzx bx, byte [fat12_buffer.BPB_NumFATs]
imul cx, bx ;9x1=9
 
add cx, size_root_dir ;размер корневой дирректории
shl ecx, 9 ;imul 512
 
 
;корректировка значения
test ecx, 0x1
jz .st1
inc ecx
.st1:
shr ecx, 1
 
push es
push ds
pop es
 
mov ah, 0x87
int 0x15
pop es
 
if DEBUG
pusha
; mov ax,point_next_fat_str
mov cx, 0x0a
mov di, return_code_af_fat_m
call decode
;Show size
mov si, return_code_af_fat_m
call printplain
popa
 
end if
 
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/parse_err.inc
0,0 → 1,66
; Copyright (c) 2009, <Lrz>
; 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.
;*****************************************************************************
 
error:
.rest_value:
mov di, ax;restore value after repe cmpsb
mov cx, bx
jmp ret_on_ch ;return
 
;///// ошибка при находжении длинны секции в параметре default
.error_get_size_d_sect:
leave ;clear array in stack
mov si, not_found_def_sect
jmp err_show_ini
 
;/////ERROR
.not_loader:
leave ;clear array in stack
mov si, not_found_sec_loader
jmp err_show_ini
 
.default_eq_loader: ;критическая ошибка default секция = loader
leave
mov si, default_eq_loader
jmp err_show_ini
.correct_exit_bl:
leave
mov si, point_to_default_sec_not_found
jmp err_show_ini
.incorect_section_def:
leave
mov si, incorect_section_define
jmp err_show_ini
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;show message error
.LoaderModule:
push word 0xb800
pop es
 
 
 
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/parse_loader.inc
0,0 → 1,335
; Copyright (c) 2009, <Lrz>
; 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 nickname <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.
;*****************************************************************************
 
;блок макросов по обработке секции [loader]
;входные данные:
;es:di - указатель на секцию начинающиюся с '[' встечающиюся после 0хa
;cx - счетчик кол-во байт для проверке в кадре
;
macro use_parse_loader
{
.parse_loader:
;//////////////////
;/ parse [loader]
;//////////////////
mov bx, cx ;cохраним в регистры значения счетчика и указателя
mov ax, di
 
; mov word [bp-4],.start ;is alredy set, see up
mov si, parse_loader
mov cx, parse_loader_e - parse_loader
repe cmpsb
jnz error.rest_value ;цепочка не совпала :( перейдем далее т.е. будем снова искать))
 
;сохраним указательна loader, что бы потом больше его не искать
mov point_loader, ax
sub bx, parse_loader_e - parse_loader;correct cx
add bx, cx
mov cx, bx
 
if DEBUG
pusha
mov si, lm_l_found
call printplain
popa
end if
;/////////////////end check [loader]. [loader] is found
;parsing section [loader]
;first found end section,let's found '[' -it's start next section
;in previosly steep bx =cx we are not need save cx, save only di - point
mov dx, di
@@:
call get_firs_sym
jcxz .loader_f_end ;.end_loader ; end даже если мы не нашли секцию предположим что секция [loader] стоит в конце
cmp al, '['
jnz @b
 
.loader_f_end:
sub bx, cx ;bx = n byte presend in section [loader]
mov di, dx ;restore di
;////////////////parse parametrs in section [loader]
;//timeout=5
;//default=main
; mov di,dx ;set pointer on section [loader] i think it's not need
mov cx, bx ;set counter for parsing section [loader] cx= кол-ву символов в секции [loader]
mov ret_on_ch, .get_next_str; return point
;;;;;;; parse timeout & default
.get_next_str:
call get_firs_sym ;get first symbol on new line
 
test cx, cx
jz .end_loader
; jcxz .end_loader ;завершение парсинга значений timeout & default
cmp al, 't'
jz .loader_timeout
cmp al, 'd'
jnz .get_next_str
;//////[loader].default
;input di point to data cx=size [loader]
mov bx, cx
mov ax, di
 
mov si, parse_l_default
mov cx, parse_l_default_e - parse_l_default
repe cmpsb
 
jnz error.rest_value ;is not compare цепочка не совпала
 
sub bx, parse_l_default_e - parse_l_default;correct cx
add bx, cx
mov cx, bx
 
test status_flag, flag_found_default
jz .correct_is_not_set
 
mov si, found_equal_default ;мы нашли что флаг уже установлен, информируем
call printplain
jmp .get_next_str
 
.correct_is_not_set:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
test cx, cx
jz .end_loader
cmp ah, byte [es:di-1] ;find '='
jnz .get_next_str
repe scasb ;cut ' '
inc cx
dec di
;сейчас es:di указывают на название секции, имя секции по дефолту не должно быть loader т.е. иначе возможно зацикливание
;установим указатель si на это значение и сначала проверим
 
;получение длинны секции
; cx=bx содержит длинну остатка секции
; di=ax указатель на текущию секцию
mov bx, cx
mov dx, di
 
@@:
mov al, byte [es:di]
inc di
dec cx
test cx, cx
jz error.error_get_size_d_sect ;переход на обработку ошибки по нахождению длины дефолтной секции
cmp al, ' '
jz @b
cmp al, 0xd
jz .found_size_d_sect
cmp al, 0xa
jnz @b
.found_size_d_sect:
;
inc cx ;correct cx
mov ax, bx
sub bx, cx ; в bx длина секции которая определена по дефолту
mov save_cx_d, bx
mov di, dx
 
mov cx, bx ;set size default section
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;проверка на =loader
;save in reg point and счетчик
;check on loader
mov bx, ax
mov ax, dx
 
mov si, parse_loader
inc si ;set only loader and 6 char in counter
repe cmpsb
jnz .check_section ;цепочка не совпала :( перейдем далее )) значит не исключение
 
jmp error.default_eq_loader ;error критическая ошибка т.е. в дефолте присутствует имя [loader]
 
.check_section: ;поиск соответствующей секции нам нужно будет узнать адрес этой секции
mov cx, bx
mov di, ax
 
;/////////////////////////////
; mov ret_on_ch,.start_d ;set return
mov si, di ;установим указатель на нашу секцию, которая по дефолту
 
push di ;save point di
 
push cx ;save cx
;установим указатель es:di на начало ini файла
mov cx, save_cx ;it's placed size of ini file
les di, dword [file_data]
 
 
mov al, byte [es:di]
push word .first_ret_d
cmp al, ' '
jz .first_sp_1_d
jmp get_firs_sym.not_space
.first_sp_1_d:
jmp get_firs_sym.first_sp
 
.start_d:
call get_firs_sym ;get first symbol on new line
.first_ret_d: ;первый возврат
jcxz .correct_exit ;.end_loader ;found or not found parametrs in section exit in section
cmp al, '['
jz .found_sect_d
jmp .start_d
;просматриваем ini файл с начала в поисках секции указаной как default
;идет проверка на наличее значения timeout, для более быстрой работы, этот параметр должен быть уже обработан,т.е. в этом случае при его =0 будет сформирован указатель только на дефолтную секцию, иначе информация будет собрана по всем секциям и составлены указатели в блоке памяти
.found_sect_d:
 
;check on name section
mov bx, cx
mov ax, di
push si ;save point
; mov si,parse_loader
mov cx, save_cx_d;load size section
push es
pop ds
 
inc di
repe cmpsb
push cs
pop ds
pop si
jnz .not_compare_d_s ;цепочка не совпала :( перейдем далее )) значит не исключение
cmp byte[es:di], ']'
jnz .not_compare_d_s ;нет в конце нашей секции завершающего символа :(
 
 
 
;set flag -we have found default -not enter again in this prosedure
or status_flag, flag_found_default
pop cx
pop di
mov point_default, ax ;point to [
 
if DEBUG
pusha
mov si, lm_lf_default_f
call printplain
popa
end if
jmp .get_next_str
 
.not_compare_d_s:
 
mov cx, bx
mov di, ax
jmp .start_d
 
.correct_exit:
pop cx ;восстановим значение счетчика
pop di
 
 
if DEBUG
pusha
mov si, lm_lf_default
call printplain
popa
end if
jmp .get_next_str
 
;//////////[loader].timeout
.loader_timeout:
mov bx, cx
mov ax, di
 
mov si, parse_l_timeout
mov cx, parse_l_timeout_e - parse_l_timeout
repe cmpsb
jnz error.rest_value ;is not compare
 
sub bx, parse_l_timeout_e - parse_l_timeout;correct cx
add bx, cx
mov cx, bx
 
test status_flag, flag_found_timeout
jz .correct_is_not_set_t
 
mov si, found_equal_timeout ;мы нашли что флаг уже установлен, информируем
call printplain
jmp .get_next_str
 
.correct_is_not_set_t:
mov ax, 0x3d20 ;cut al=' ' ah='='
repe scasb
jcxz .timeout_sec_end_d ;not found param timeout
cmp ah, byte [es:di-1] ;find '='
jnz .get_next_str
repe scasb ;cut ' '
inc cx
dec di
;get timeout value
;2 знакa может быть обработано т.е. значение от 0 до 99 секунд
push cx
xor bx, bx
mov cx, 2
@@:
mov al, byte [es:di]
cmp al, '0'
jb .end_get_val_t
cmp al, '9'
ja .end_get_val_t
imul bx, 10
xor al, 0x30
add bl, al
.end_get_val_t:
inc di
loop @b
mov word [value_timeout], bx
; pop cx
 
if DEBUG
pusha
mov si, lm_lf_timeout
call printplain
popa
end if
 
jmp @f
.timeout_sec_end_d:
mov word [value_timeout], default_timeout_value
mov si, set_default_timeout_val
call printplain
@@:
pop cx
jmp .get_next_str
 
;///////here end block loader
.end_loader:
if DEBUG
pusha
mov si, lm_l_end
call printplain
popa
end if
 
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/sl_equ.inc
0,0 → 1,98
; Copyright (c) 2008-2009, <Lrz>
; 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.
;*****************************************************************************
; Предопределения
DEBUG equ 1 ;компиляция с отладочной информацией =1 без отладочной инфорации =0
loop_read_startos_file equ 3 ;кол-во попыток считать через callback сервис файл конфигурации блок2
root_dir_entry_count equ 224 ;кол-во элементов в корневой дирректории
;point_to_fat_struc equ 0xA000 ;временный буфер, куда будет размещена Fat таблица, и затем перенесена за 1 мб
ini_data_ equ 0x2000 ;файл где размещен файл сценария загрузки, там происходит синтаксический разбор
size_show_section equ 18
default_timeout_value equ 5 ;default value to timeout is will was some errors
flag_found_default equ 0x1 ;default value is found
flag_found_timeout equ 0x2 ;timeout value is found
flag_found_LM equ 0x1 ;found LM value
flag_found_RS equ 0x2 ;found RS value
flag_found_GTRFMS equ 0x4 ;found type RamFS
flag_found_RamdiskSector equ 0x8 ;found RamdiskSector
flag_found_RamdiskCluster equ 0x16 ;found RamdiskCluster
;statick data эти данные не предопределяются в течении выполнения всей программы.
save_cx equ word [bp-2] ;save cx size ini file
ret_on_ch equ word [bp-4] ;point to return разрушаемое значение
save_cx_d equ word [bp-6] ;save cx - size default section and working section
status_flag equ word [bp-8] ;status flag
point_loader equ word [bp-10]
point_default equ word [bp-12] ;point to default
 
;данные которые зависимы от ветки выполнения и которые могут быть переопределены в процессе выполнения программы.
point_to_hframe equ word [bp-14] ;point on start frame (for change section)
point_to_1 equ word [bp-16]
point_to_2 equ word [bp-18]
point_to_3 equ word [bp-20]
point_to_4 equ word [bp-22]
point_to_5 equ word [bp-24]
point_to_6 equ word [bp-26]
point_to_7 equ word [bp-28]
point_to_8 equ word [bp-30]
point_to_9 equ word [bp-32]
point_to_10 equ word [bp-34]
point_to_11 equ word [bp-36]
point_to_12 equ word [bp-38]
point_to_13 equ word [bp-40]
point_to_14 equ word [bp-42]
point_to_15 equ word [bp-44]
point_to_16 equ word [bp-46]
point_to_16 equ word [bp-48]
point_to_17 equ word [bp-50]
point_to_18 equ word [bp-52]
;here array for fast scroling 16 word - poin to start section
point_to_point_def equ word [bp-54]
point_to_eframe equ word [bp-56] ;point on point frame
 
 
 
; тут расположено временное хранилище для cx и di при переходе на следующий буфер при поиске секций
find_sec_di equ word [bp-58] ;тут будет храниться di
info_real_mode_size equ word [bp-60];тут храниться информация о занятой области т.е. размер, можно узнать сколько осталось места вычислив
free_ad_memory equ word [bp-62] ;сколько у нас расширенной памяти для формирования рам диска и загрузки модулей
show_errors_sect equ word [bp-64] ;переменая которая хранит биты ошибок для каждой логической секции.
save_descript_size equ word [bp-66] ;save descript size previos section сохраним размер предыдущей секции которую выводили
save_ramdisksize equ dword [bp-70] ;save size of ramdisk in byte
save_file_size equ dword [bp-74] ;save size of reading file
set_ramfs equ word [bp-76] ;определенный тип файловой системы,нужно для формирования рам диска
point_next_fat_str equ word [bp-78] ;указатель на следующий элемент fat таблицы
size_root_dir equ word [bp-80] ;кол-во элементов в секторах по 512 байт корневой директории
firstDataSect equ word [bp-82] ;первый сектор данных в сеторах от 0
DataClasters equ word [bp-84] ;размер массива доступной для записи данных в кластерах.
point_to_free_root equ word [bp-86] ;указатель на следующий пустую запись в рут дир
point_to_dest_file_name equ word [bp-88] ;указывает на начало имени файла назначения. в формате es:point_to_dest_file_name, где es =0x2000
data_offset equ word [bp-90] ;смещение в кластерах для записанных данных т.е перекинутых за 1-й мб
first_input equ word [bp-92] ;поле для флагов в преобразовании имени.
save_di_RAMDISK equ word [bp-94] ;сохраним di -указателя при обработке секции
save_cx_RAMDISK equ word [bp-96] ;сохраним размер остатка секции
status_flag_loader_f equ word [bp-98] ;сохраним результат выполенения загрузки файла
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;данные которые используются при обработке секции, т.е. после нажатия Enter, уже не возможно вернуться в первоначальный экран
;для возврата, необходимо перезапустить полностью код т.е. стартовать с 0х1000:0000
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/sl_proc.inc
0,0 → 1,528
; Copyright (c) 2009, <Lrz>
; 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.
;*****************************************************************************
 
; тут описываются процедуры которые используются в secondary loader
color_sym_black equ 0
color_sym_blue equ 1
color_sym_green equ 2
color_sym_turquoise equ 3
color_sym_red equ 4
 
color_sym_lightgray equ 7
 
color_sym_lightblue equ 9
color_sym_lettuce equ 10
color_sym_pink equ 12
color_sym_yellow equ 14
color_sym_white equ 15
if DEBUG
decode:
;input eax - число, es:di куда писать, cx=10
cmp eax, ecx
jb @f
xor edx, edx
div ecx
push edx
call decode
pop eax
@@:
or al, 0x30
mov [ds:di], al
inc di
ret
 
end if
 
 
putchar:
; in: al=character
mov ah, 0Eh
mov bh, 0
int 10h
ret
 
printplain:
; in: si->string
pushad
lodsb
@@:
call putchar
lodsb
test al, al
jnz @b
mov al, 13
call putchar
 
mov al, 10
call putchar
popad
ret
getkey:
; get number in range [bl,bh] (bl,bh in ['0'..'9'])
; in: bx=range
; out: ax=digit (1..9, 10 for 0)
mov ah, 0
int 16h
cmp al, bl
jb getkey
cmp al, bh
ja getkey
push ax
call putchar
pop ax
and ax, 0Fh
jnz @f
mov al, 10
@@:
ret
 
;setcursor:
; in: dl=column, dh=row
; mov ah, 2
; mov bh, 0
; int 10h
; ret
 
;macro _setcursor row,column
;{
; mov dx, row*256 + column
; call setcursor
;}
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
get_firs_sym:
.start:
mov al, byte [es:di]
inc di
dec cx
jcxz .exit
 
cmp al, 0xa ;cmp al,0xa
jz ._entry
 
cmp al, ';'
jnz .start
 
.first_com:
 
mov al, 0xa
repnz scasb
jcxz .exit
._entry:
mov al, byte [es:di]
.first_sp:
cmp al, ' '
jnz .not_space
 
; mov al,' ' ;cut ' '
repe scasb
dec di
inc cx
mov al, byte [es:di]
.not_space:
cmp al, ';'
jz .first_com
.exit:
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
show_name_section:
push si
push ini_data_
pop es
 
 
mov al, ']'
repnz scasb
test cx, cx
jz error.incorect_section_def
.find_val_name_fb1:
mov al, 'n'
.find_val_name_fb:
repnz scasb
jcxz .not_name_sec_fb
 
mov si, parse_name
 
push cx
push di
 
mov cx, parse_name_e -parse_name
repe cmpsb
pop di
pop cx
jz .yaaa_find_value
 
 
jmp .find_val_name_fb
 
.yaaa_find_value:
sub cx, parse_name_e -parse_name
add di, parse_name_e -parse_name
 
mov ax, 0x3d20 ; ah='='
repe scasb
test cx, cx
jz .not_name_sec_fb
 
cmp ah, byte [es:di-1] ;find '='
jnz .find_val_name_fb1
repe scasb ;cut ' '
inc cx
dec di
 
 
;все вырезали и все готово для вывода имени секции ))
push es
pop ds
 
.def_sect_name:
push 0xb800
pop es
;clear array for message
xor ax, ax
if DEBUG
mov ax, 0x0720
end if
 
mov cx, 39
mov si, di
mov di, dx
sub di, 2
rep stosw
;//////////////////////
 
 
mov di, dx
mov ah, color_sym_white;color_sym_lightblue
mov cx, 36
lodsb
sub di, 2
cmp al, '"'
jz @f
cmp al, "'"
jnz .end_sh_name_sec
@@:
lodsb
@@:
stosw
lodsb
cmp al, '"'
jz .end_sh_name_sec
cmp al, "'"
jz .end_sh_name_sec
loop @b
mov al, '}'
mov ah, color_sym_yellow
stosw
.end_sh_name_sec:
push cs
pop ds
 
pop si
ret
 
.not_name_sec_fb: ;нет имени в названии секции - значит так и скажем об этом
push cs
pop ds
mov di, default_section_name
jmp .def_sect_name
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;процедура поиска вверх следующей секции
;в point_default содержиться указатель на дефаулт секцию, и в пределах врейма мы бегаем по заранее пропарсеными значениям указателей
;для того что бы отобразить и пропарсить следующий фрейм, нам нужно получить за пердыдущий или следующий указатель
find_before_sect:
mov di, point_default
.e:
push ini_data_
pop es
mov cx, di ;предположим будем просматривать к началу, текущая позиция di = сколько символов от начала документа имеется
mov bx, cx ;копия
 
;настроили указатель на дефаулт секцию
;будем искать вверх
.find_start_section:
std ;установка флага направления - будем просматирвать к началу нашего ини файла
;будем искать начало секции т.е. '[' этот символ
mov al, 0xa
repnz scasb ;просканируем на наличее символа начала секции
jcxz .go_ ;мы просмотрели до начала файла, но так и ничего не нашли ;(( по тихому выйдем )
 
mov find_sec_di, di ;сохраним данные
mov cx, di ;
 
sub bx, cx
mov cx, bx ;в сx значение - кол-во символов
cld
call get_firs_sym
.ret_go:
jcxz ._not_section ; в данном случае имеем конструкцию 0xa ... ; hello [секция] обломс ищем далее
 
cmp di, point_loader; секцию loader мы не заносим иначе крах
jz ._not_section
;все удачно мы нашли вхождение секции предыдущей
cmp al, '['
jnz ._not_section
mov point_default, di
.exit_scan_sect:
ret
;;;;;;;; восстановим значения и продолжим поиски начала секции которая нас устроит ))
._not_section:
mov di, find_sec_di
mov cx, di
mov bx, cx
jmp .find_start_section
.go_:
cld
mov cx, bx ;в сx значение - кол-во символов
 
mov al, byte [es:di]
push word .f_go
cmp al, ' '
jz @f
jmp get_firs_sym.not_space
@@:
jmp get_firs_sym.first_sp
 
.f_go:
jcxz .exit_scan_sect ; в данном случае имеем конструкцию 0xa ... ; hello [секция] обломс ищем далее
 
cmp di, point_loader; секцию loader мы не заносим иначе крах
jz .exit_scan_sect
;все удачно мы нашли вхождение секции предыдущей
cmp al, '['
jnz .exit_scan_sect
mov point_default, di
ret
 
 
 
 
 
 
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
find_next_sect:
mov di, point_default
push ini_data_
pop es
mov cx, save_cx;di ;предположим будем просматривать к концу, текущая позиция di = сколько символов от начала документа имеется
sub cx, di ;сейчас в cx остаток т.е. сколько можно крутить до конца и не вылазить на начало
jmp .let_s_go
.h:
push ini_data_
pop es
mov cx, save_cx;di ;предположим будем просматривать к концу, текущая позиция di = сколько символов от начала документа имеется
; sub cx,di ;сейчас в cx остаток т.е. сколько можно крутить до конца и не вылазить на начало
 
mov al, byte [es:di]
push word .let_s_go_ret
cmp al, ' '
jz @f
jmp get_firs_sym.not_space
@@:
jmp get_firs_sym.first_sp
 
 
 
 
;настроили указатель на дефаулт секцию
;будем искать вниз
.let_s_go:
call get_firs_sym
.let_s_go_ret:
jcxz .exit_scan_sect ; в данном случае имеем конструкцию 0xa ... ; hello [секция] обломс ищем далее
cmp al, '['
jnz .let_s_go
cmp di, point_loader
jz .let_s_go
;все удачно мы нашли вхождение секции предыдущей
mov point_default, di
.exit_scan_sect:
ret
 
;;;;;;;;;;;;;;;;;;;;;;;;;;
;clean old cursor
clean_active_cursor:
;не изменяет значение ax
;отображение курсора по умолчанию
lea si, point_to_hframe
mov di, 962-160
mov dx, point_default
mov cx, 18
.clean_show_cur:
mov bx, [si]
add di, 160
cmp bx, dx
jz .clean_cursor_
sub si, 2
loop .clean_show_cur
 
; jmp $
 
.clean_cursor_:
push 0xb800
pop es
push ax
mov point_to_point_def, si
xor ax, ax
if DEBUG
mov ax, 0x0720
end if
stosw
add di, 68
stosw
pop ax
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;установка таймера и отображение счетчика времени
gettime:
mov ah, 0
int 1Ah
xchg ax, cx
shl eax, 10h
xchg ax, dx
ret
newtimer:
push ds
 
push cs
pop ds
 
pushf
call far dword [old_timer]
 
pushad
call gettime
 
sub eax, dword[start_timer]
mov bx, word [value_timeout]
imul bx, 18
sub bx, ax
jbe .timergo
 
push es
 
push 0xb800
pop es
mov ax, bx
 
mov bx, 18
xor dx, dx
div bx
 
mov bx, 10
mov di, 3734
call .decode
 
xor ax, ax
stosw
 
; wait 5/4/3/2 seconds, 1 second
pop es
popad
pop ds
 
iret
.timergo:
push 0
pop es
mov eax, dword [old_timer]
mov [es:8*4], eax
mov dword [timer_], eax
mov sp, word [start_stack]
mov bp, word [save_bp_from_timer]
;;не восстановленый стек :(
sti
jmp parse_start.parse_run_only
 
 
.decode:
;input ax - число, es:di куда писать, bx=10
cmp ax, bx
jb @f
xor dx, dx
div bx
push dx
call .decode
pop ax
@@:
or al, 0x30
push ax
mov ah, 9
stosw
pop ax
ret
 
show_bl_sc_sect:
;1) отображение списка секций. Если секция не имет имя - ошибка - вывод Section unname
;проверка на наличее имени.
;входные данные es:di -указатель на секцию - cx размер секции
; push bp
mov bx, point_to_eframe
lea si, point_to_hframe
mov dx, 966
 
.home_show_fb:
cmp si, bx
jb ._show_space_fb
mov di, [si]
sub si, 2
mov cx, [si]
sub cx, di ;home first section it's end before section
call show_name_section
add dx, 160
jmp .home_show_fb
._show_space_fb:
sub dx, 4
push 0xb800
pop es
@@:
cmp dx, 0xE64
ja .exit_show_fb
mov di, dx
;clear array for message
xor ax, ax
if DEBUG
mov ax, 0x0720
end if
mov cx, 39
rep stosw
;//////////////////////
 
add dx, 160
jmp @b
.exit_show_fb:
; pop bp
ret
 
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/boot_st.inc
0,0 → 1,68
; Copyright (c) 2009, <Lrz>
; 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.
;*****************************************************************************
 
;======================================================================
;
; BOOT DATA
;
;======================================================================
 
 
version db 'Secondary Loader v 0.010',0
version_end:
 
select_section db 'Select section:'
select_section_end:
section_description db 'Section description:'
section_description_end:
soft_mes db 'Soft (c) 2008-2009'
soft_mes_end:
 
badprocessor db '>Fatal - CPU 586+ required.',0
error_ini_f1 db '>Error: cannot load ini file, buffer is full',0
error_ini_f2 db '>Error: ini file not found',0
error_ini_f3 db '>Error: cannot read ini file',0
error_ini_nf db '>Error: unrecognized error when loading ini file',0
not_found_sec_loader db '>Not found section [loader]',0
not_found_def_sect db '>Not found value default in section [loader]',0
default_eq_loader db '>Error in section [loader] parametr default=loader',0
found_equal_default db '>Found equal parametr default will be use first value',0
found_equal_timeout db '>Found equal parametr timeout will be use first value',0
set_default_timeout_val db '>Section timeout has incorrect value, will be use default value',0
error_ini_common db ">I will use predefined settings and try to boot. Let's hope for the best..."
db 13,10,"Press any key to continue...",0
load_ini db '>Ini file loaded successfully',0
parse_ini_end db '>End parsing ini file',0
point_to_default_sec_not_found db '>Point to default section is not found in ini file',0
incorect_section_define db ">Incorect section define not found ']'",0
default_section_name db '"Section unname"'
 
start_msg db "Press any key to change default section, press [Enter] to continue booting"
start_msg_e:
time_msg db "or wait 4 seconds before default continuation"
time_msg_e:
time_str db "seconds before default continuation"
time_str_e:
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/listing.inc
0,0 → 1,635
; Listing generator
; LocoDelAssembly 2007.06.01
 
INSTRUCTIONS equ bt in ja jb jc je jg jl jo jp js jz or \
aaa aad aam aas adc add and bsf bsr btc btr bts cbw cdq clc \
cld cli cmc cmp cqo cwd daa das dec div fld fst hlt inc ins \
int jae jbe jge jle jmp jna jnb jnc jne jng jnl jno jnp jns \
jnz jpe jpo lar lds lea les lfs lgs lsl lss ltr mov mul neg \
nop not out pop por rcl rcr ret rol ror rsm sal sar sbb shl \
shr stc std sti str sub ud2 xor \
arpl call cdqe clgi clts cmps cwde emms fabs fadd fbld fchs \
fcom fcos fdiv feni fild fist fld1 fldz fmul fnop fsin fstp \
fsub ftst fxam fxch idiv imul insb insd insw int1 int3 into \
invd iret jcxz jnae jnbe jnge jnle lahf lgdt lidt lldt lmsw \
lods loop movd movq movs orpd orps outs pand popa popd popf \
popq popw push pxor retd retf retn retq retw sahf salc scas \
seta setb setc sete setg setl seto setp sets setz sgdt shld \
shrd sidt sldt smsw stgi stos test verr verw wait xadd xchg \
xlat \
addpd addps addsd addss andpd andps bound bswap cmova cmovb \
cmovc cmove cmovg cmovl cmovo cmovp cmovs cmovz cmppd cmpps \
cmpsb cmpsd cmpsq cmpss cmpsw cpuid divpd divps divsd divss \
enter f2xm1 faddp fbstp fclex fcomi fcomp fdisi fdivp fdivr \
femms ffree fiadd ficom fidiv fimul finit fistp fisub fldcw \
fldpi fmulp fneni fprem fptan fsave fsqrt fstcw fstsw fsubp \
fsubr fucom fwait fyl2x icebp iretd iretq iretw jecxz jrcxz \
lddqu leave lodsb lodsd lodsq lodsw loopd loope loopq loopw \
loopz maxpd maxps maxsd maxss minpd minps minsd minss movsb \
movsd movsq movss movsw movsx movzx mulpd mulps mulsd mulss \
mwait outsb outsd outsw pabsb pabsd pabsw paddb paddd paddq \
paddw pandn pause pavgb pavgw pf2id pf2iw pfacc pfadd pfmax \
pfmin pfmul pfrcp pfsub pi2fd pi2fw popad popaw popfd popfq \
popfw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb \
psubd psubq psubw pusha pushd pushf pushq pushw rcpps rcpss \
rdmsr rdpmc rdtsc retfd retfq retfw retnd retnq retnw scasb \
scasd scasq scasw setae setbe setge setle setna setnb setnc \
setne setng setnl setno setnp setns setnz setpe setpo stosb \
stosd stosq stosw subpd subps subsd subss vmrun vmxon wrmsr \
xlatb xorpd xorps \
andnpd andnps cmovae cmovbe cmovge cmovle cmovna cmovnb cmovnc\
cmovne cmovng cmovnl cmovno cmovnp cmovns cmovnz cmovpe cmovpo\
comisd comiss fcmovb fcmove fcmovu fcomip fcompp fdivrp ffreep\
ficomp fidivr fisttp fisubr fldenv fldl2e fldl2t fldlg2 fldln2\
fnclex fndisi fninit fnsave fnstcw fnstsw fpatan fprem1 frstor\
frstpm fscale fsetpm fstenv fsubrp fucomi fucomp fxsave haddpd\
haddps hsubpd hsubps invlpg lfence looped loopeq loopew loopne\
loopnz loopzd loopzq loopzw mfence movapd movaps movdqa movdqu\
movhpd movhps movlpd movlps movnti movntq movsxd movupd movups\
paddsb paddsw pextrw pfnacc pfsubr phaddd phaddw phsubd phsubw\
pinsrw pmaxsw pmaxub pminsw pminub pmulhw pmullw psadbw pshufb\
pshufd pshufw psignb psignd psignw pslldq psrldq psubsb psubsw\
pswapd pushad pushaw pushfd pushfq pushfw rdmsrq rdtscp setalc\
setnae setnbe setnge setnle sfence shufpd shufps skinit sqrtpd\
sqrtps sqrtsd sqrtss swapgs sysret vmcall vmload vmread vmsave\
vmxoff wbinvd wrmsrq \
clflush cmovnae cmovnbe cmovnge cmovnle cmpeqpd cmpeqps \
cmpeqsd cmpeqss cmplepd cmpleps cmplesd cmpless cmpltpd \
cmpltps cmpltsd cmpltss cmpxchg fcmovbe fcmovnb fcmovne \
fcmovnu fdecstp fincstp fnstenv frndint fsincos fucomip \
fucompp fxrstor fxtract fyl2xp1 invlpga ldmxcsr loopned \
loopneq loopnew loopnzd loopnzq loopnzw monitor movddup \
movdq2q movhlps movlhps movntdq movntpd movntps movq2dq \
paddusb paddusw palignr pavgusb pcmpeqb pcmpeqd pcmpeqw \
pcmpgtb pcmpgtd pcmpgtw pfcmpeq pfcmpge pfcmpgt pfpnacc \
pfrsqrt phaddsw phsubsw pmaddwd pmulhrw pmulhuw pmuludq \
pshufhw pshuflw psubusb psubusw rsqrtps rsqrtss stmxcsr \
syscall sysexit sysretq ucomisd ucomiss vmclear vmmcall \
vmptrld vmptrst vmwrite \
addsubpd addsubps cmpneqpd cmpneqps cmpneqsd cmpneqss cmpnlepd\
cmpnleps cmpnlesd cmpnless cmpnltpd cmpnltps cmpnltsd cmpnltss\
cmpordpd cmpordps cmpordsd cmpordss cvtdq2pd cvtdq2ps cvtpd2dq\
cvtpd2pi cvtpd2ps cvtpi2pd cvtpi2ps cvtps2dq cvtps2pd cvtps2pi\
cvtsd2si cvtsd2ss cvtsi2sd cvtsi2ss cvtss2sd cvtss2si fcmovnbe\
maskmovq movmskpd movmskps movshdup movsldup packssdw packsswb\
packuswb pfrcpit1 pfrcpit2 pfrsqit1 pmovmskb pmulhrsw prefetch\
sysenter sysexitq unpckhpd unpckhps unpcklpd unpcklps vmlaunch\
vmresume \
cmpxchg8b cvttpd2dq cvttpd2pi cvttps2dq cvttps2pi cvttsd2si \
cvttss2si pmaddubsw prefetchw punpckhbw punpckhdq punpckhwd \
punpcklbw punpckldq punpcklwd \
cmpunordpd cmpunordps cmpunordsd cmpunordss cmpxchg16b \
loadall286 loadall386 maskmovdqu prefetcht0 prefetcht1 \
prefetcht2 punpckhqdq punpcklqdq prefetchnta
 
PREFIXES equ rep lock repe repz repne repnz
 
DATA_DEFINITORS equ db dw du dd dp df dq dt file
DATA_RESERVERS equ rb rw rd rp rf rq rt
 
CRLF equ 13, 10 ; Remove 13 for Linux
MAX_BYTES equ 13
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; MODE MACROSES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
macro use16
{
use16
_USE = 16
}
 
macro use32
{
use32
_USE = 32
}
 
macro use64
{
use64
_USE = 64
}
 
macro detect_mode
{
local aux
 
_USE = 32
 
virtual at 0
xchg eax, eax
load aux byte from 0
 
if aux = $66
_USE = 16
else if aux = $87
_USE = 64
end if
end virtual
}
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;; DISPLAYING MACROSES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
macro display_address address*
{
local aux, digit
 
aux = address
 
repeat _USE / 4
digit = aux shr (_USE - 4 * %) and $F
 
display digit + '0' + ('9' - 'B') and (9 - digit) shr 4 and $F
end repeat
 
display ': '
}
 
macro display_bytes pointer
{
local aux, size, digit
 
size = $ - pointer
 
if size > MAX_BYTES
size = MAX_BYTES
end if
 
repeat size
load aux byte from pointer+%-1
 
digit = aux shr 4
display digit + '0' + ('9' - 'B') and (9 - digit) shr 4 and $F
 
digit = aux and $F
display digit + '0' + ('9' - 'B') and (9 - digit) shr 4 and $F
 
 
display ' '
end repeat
 
repeat MAX_BYTES - size
display ' '
end repeat
}
 
; The macro below in some situations doesn't adds a space to separate things unfortunatelly, so for readability ensurance
; another one will be used instead...
;macro display_args [args]
;{
;common
; aux = 1
;
;forward
; if ~args eq
; if aux
; display ' '
; else
; display ', '
; end if
;
; aux = 0
;
; match =ON, _RESOLVE_EQUATES
; \{
; match args, args
; \\{
; irps arg, args
; \\\{
; display \\\`arg
; \\\}
; \\}
; \}
; match =OFF, _RESOLVE_EQUATES
; \{
; irps arg, args
; \\{
; display \\`arg
; \\}
;
; \}
; end if
;}
 
; This one separates everything with one space. A very ugly listing but at least you will not see things
; like "push ebxesiedi" nor "ret word0"
 
macro display_args [args]
{
common
aux = 1
 
forward
if ~args eq
if ~aux
display ','
end if
 
aux = 0
 
match =ON, _RESOLVE_EQUATES
\{
match args, args
\\{
if ~args eqtype ""
irps arg, args
\\\{
display ' ', \\\`arg
\\\}
else
display " '", args, "'"
end if
\\}
\}
match =OFF, _RESOLVE_EQUATES
\{
if ~args eqtype ""
irps arg, args
\\{
display ' ', \\`arg
\\}
else
display " '", args, "'"
end if
\}
end if
}
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;; INSTRUCTIONS & PREFIXES MACROSES ;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
macro prefix mnemonic
{
local aux
 
macro mnemonic [args]
\{
\common
match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
match =equ, args\\{_LISTING equ 0\\}
match =equ any, args\\{_LISTING equ 0\\}
 
match =1, _LISTING
\\{
display_address $
aux = $
\\}
 
mnemonic
 
match =1, _LISTING
\\{
display_bytes aux
 
display \`mnemonic
display CRLF
\\}
 
match =1, _ON_VIRTUAL\\{restore _LISTING\\}
match =equ, args\\{restore _LISTING\\}
match =equ any, args\\{restore _LISTING\\}
 
def_prefix mnemonic
args
purge mnemonic
\}
}
 
macro def_prefix mnemonic
{
macro def_prefix mnemonic
\{
prefix mnemonic
\}
def_prefix mnemonic
}
 
macro instruction mnemonic
{
local aux
 
macro mnemonic [args]
\{
\common
match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
match =equ, args\\{_LISTING equ 0\\}
match =equ any, args\\{_LISTING equ 0\\}
 
match =1, _LISTING
\\{
display_address $
aux = $
\\}
 
mnemonic args
 
match =1, _LISTING
\\{
display_bytes aux
 
display \`mnemonic
 
virtual at 0
db \`mnemonic
repeat 11 - $
display ' '
end repeat
end virtual
 
display_args args
display CRLF
\\}
 
match =1, _ON_VIRTUAL\\{restore _LISTING\\}
match =equ, args\\{restore _LISTING\\}
match =equ any, args\\{restore _LISTING\\}
\}
}
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; DATA MACROSES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
macro data_define mnemonic
{
local aux
macro mnemonic [args]
\{
\common
match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
match =equ, args\\{_LISTING equ 0\\}
match =equ any, args\\{_LISTING equ 0\\}
 
match =1, _LISTING
\\{
display_address $
aux = $
\\}
 
mnemonic args
 
match =1, _LISTING
\\{
display_bytes aux
 
display \`mnemonic
 
display_args args
display CRLF
 
aux = aux + MAX_BYTES
 
repeat ($ - aux + MAX_BYTES - 1) / MAX_BYTES
display_address aux
display_bytes aux
display CRLF
 
aux = aux + MAX_BYTES
end repeat
\\}
 
match =1, _ON_VIRTUAL\\{restore _LISTING\\}
match =equ, args\\{restore _LISTING\\}
match =equ any, args\\{restore _LISTING\\}
\}
 
struc mnemonic [args]
\{
\common
match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
match =equ, args\\{_LISTING equ 0\\}
match =equ any, args\\{_LISTING equ 0\\}
 
match =1, _LISTING
\\{
display_address $
aux = $
\\}
 
. mnemonic args
 
match =1, _LISTING
\\{
display_bytes aux
 
display \`., ' ', \`mnemonic
 
display_args args
display CRLF
 
aux = aux + MAX_BYTES
 
repeat ($ - aux + MAX_BYTES - 1) / MAX_BYTES
display_address aux
display_bytes aux
display CRLF
 
aux = aux + MAX_BYTES
end repeat
\\}
 
match =1, _ON_VIRTUAL\\{restore _LISTING\\}
match =equ, args\\{restore _LISTING\\}
match =equ any, args\\{restore _LISTING\\}
\}
}
 
macro data_reserve mnemonic
{
local aux
macro mnemonic [args]
\{
\common
match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
match =equ, args\\{_LISTING equ 0\\}
match =equ any, args\\{_LISTING equ 0\\}
 
match =1, _LISTING
\\{
display_address $
aux = $
\\}
 
mnemonic args
 
match =1, _LISTING
\\{
times MAX_BYTES display ' '
 
display \`mnemonic
 
display_args args
display CRLF
\\}
 
match =1, _ON_VIRTUAL\\{restore _LISTING\\}
match =equ, args\\{restore _LISTING\\}
match =equ any, args\\{restore _LISTING\\}
\}
 
struc mnemonic [args]
\{
\common
match =1, _ON_VIRTUAL\\{_LISTING equ 0\\}
match =equ, args\\{_LISTING equ 0\\}
match =equ any, args\\{_LISTING equ 0\\}
 
match =1, _LISTING
\\{
display_address $
aux = $
\\}
 
. mnemonic args
 
match =1, _LISTING
\\{
times MAX_BYTES display ' '
 
display \`., ' ', \`mnemonic
 
display_args args
display CRLF
\\}
 
match =1, _ON_VIRTUAL\\{restore _LISTING\\}
match =equ, args\\{restore _LISTING\\}
match =equ any, args\\{restore _LISTING\\}
\}
}
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;; LISTING CONTROL MACROSES ;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
macro virtual [args]
{
common
_ON_VIRTUAL equ 1
 
virtual args
}
 
macro end [args]
{
common
match =virtual, args\{restore _ON_VIRTUAL\}
 
end args
}
 
macro enable_listing
{
detect_mode
 
match =0, _MACROSES_INSTALLED
\{
match instructions, INSTRUCTIONS
\\{
irps ins, instructions
\\\{
instruction ins
\\\}
\\}
 
match prefixes, PREFIXES
\\{
irps prefix, prefixes
\\\{
def_prefix prefix
\\\}
\\}
 
match data_definitors, DATA_DEFINITORS
\\{
irps def, data_definitors
\\\{
data_define def
\\\}
\\}
 
match data_reservers, DATA_RESERVERS
\\{
irps def, data_reservers
\\\{
data_reserve def
\\\}
\\}
\}
 
_MACROSES_INSTALLED equ 1
_LISTING equ 1
}
 
macro disable_listing
{
_LISTING equ 0
}
 
macro enable [feature*]
{
forward
UNKNOWN equ 1
 
match =resolve_equates, feature
\{
restore _RESOLVE_EQUATES
_RESOLVE_EQUATES equ ON
UNKNOWN equ 0
\}
 
match =listing, feature
\{
enable_listing
UNKNOWN equ 0
\}
 
match =1, UNKNOWN
\{
display 'ERROR: Unknown "',`feature, '" feature', 13, 10
err
\}
 
restore UNKNOWN
restore UNKNOWN
}
 
macro disable [feature*]
{
UNKNOWN equ 1
 
match =resolve_equates, feature
\{
restore _RESOLVE_EQUATES
_RESOLVE_EQUATES equ OFF
UNKNOWN equ 0
\}
 
match =listing, feature
\{
disable_listing
UNKNOWN equ 0
\}
 
match =1, UNKNOWN
\{
display 'ERROR: Unknown "',`feature, '" feature', 13, 10
err
\}
 
restore UNKNOWN
restore UNKNOWN
}
 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; INITIALIZATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
_MACROSES_INSTALLED equ 0
_ON_VIRTUAL equ 0
 
disable resolve_equates
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk/build_ru.bat
0,0 → 1,4
@fasm -m 65535 loader.asm loader
@echo off
REM @fasm -m 65535 loader.asm loader > loader.lst
REM @pause
/kernel/branches/kolibrios-pe-clevermouse/sec_loader/trunk
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sec_loader
Property changes:
Added: tsvn:logminsize
+5
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/data32et.inc
0,0 → 1,48
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
boot_initirq latin1 'Algväärtustan IRQ',0
boot_picinit latin1 'Algväärtustan PIC',0
boot_v86machine latin1 'Algväärtustan süsteemi V86 masinat',0
boot_inittimer latin1 'Algväärtustan süsteemi taimerit (IRQ0)',0
boot_initramdisk latin1 'Initialize ramdisk',0
boot_initapic latin1 'Proovin Algväärtustada APIC',0
boot_enableirq latin1 'Luban katkestused 2, 13',0
boot_disabling_ide latin1 'Keelan IDE kontrolleri katkestused',0
boot_enabling_ide latin1 'Luban IDE kontrolleri katkestused',0
boot_set_int_IDE latin1 'Määran IDE kontrolleri halduri',0
boot_detectfloppy latin1 'Otsin floppi kettaid',0
boot_detecthdcd latin1 'Otsin kõvakettaid ja ATAPI seadmeid',0
boot_getcache latin1 'Küsin puhvri mälu',0
boot_detectpart latin1 'Otsin kettaseadmete partitsioone',0
boot_init_sys latin1 'Algväärtustan süsteemi kataloogi /sys',0
boot_loadlibs latin1 'Laadin mooduleid (.obj)',0
boot_memdetect latin1 'Avastan mälu mahtu',0
boot_tss latin1 'Määran TSSe',0
boot_cpuid latin1 'Loen CPUIDd',0
; boot_devices db 'Detecting devices',0
boot_setmouse latin1 'Seadistan hiirt',0
boot_windefs latin1 'Seadistan akende vaikeväärtusi',0
boot_bgr latin1 'Kalkuleerin tausta',0
boot_resirqports latin1 'Reserveerin IRQsi ja porte',0
boot_setostask latin1 'Seadistan OS protsessi',0
boot_allirqs latin1 'Unmasking IRQs',0
boot_tsc latin1 'Loen TSC',0
boot_cpufreq latin1 'CPU sagedus on ',' ',' MHz',0
boot_pal_ega latin1 'Seadistan EGA/CGA 320x200 paletti',0
boot_pal_vga latin1 'Seadistan VGA 640x480 paletti',0
boot_failed latin1 'Esimese programmi käivitamine ebaõnnestus',0
boot_mtrr latin1 'Määran MTRR',0
 
boot_APIC_found latin1 'APIC aktiveeritud', 0
boot_APIC_nfound latin1 'APIC ei leitud', 0
if preboot_blogesc
boot_tasking latin1 'Kõik valmis - vajuta ESC alustamiseks',0
end if
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/data32sp.inc
0,0 → 1,54
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
boot_initirq: cp850 'Inicializar IRQ',0
boot_picinit: cp850 'Inicializar PIC',0
boot_v86machine: cp850 'Inicializar sistema V86',0
boot_inittimer: cp850 'Inicializar reloj del sistema (IRQ0)',0
boot_initramdisk cp850 'Initialize ramdisk',0
boot_initapic: cp850 'Prueba inicializar APIC',0
boot_enableirq: cp850 'Habilitar interrupciones 2, 13',0
boot_disabling_ide:cp850 'Habiliar interrupciones en controladores IDE',0
boot_enabling_ide:cp850 'Habilitar interrupciones en controladores IDE',0
boot_set_int_IDE: cp850 'Configuración del controlador de interrupciones para el IDE',0
boot_detectfloppy:cp850 'Buscar unidades de disquete',0
boot_detecthdcd: cp850 'Buscar discos duros y unidades ATAPI',0
boot_getcache: cp850 'Tomar memoria para caché',0
boot_detectpart: cp850 'Buscar particiones en discos',0
boot_init_sys: cp850 'Inicializar directorio del sistema /sys',0
boot_loadlibs: cp850 'Cargando librerías (.obj)',0
boot_memdetect: cp850 'Determinando cantidad de memoria',0
boot_tss: cp850 'Configurando TSSs',0
boot_cpuid: cp850 'Leyendo CPUIDs',0
; boot_devices: cp850 'Detectando dispositivos',0
boot_setmouse: cp850 'Configurando el ratón',0
boot_windefs: cp850 'Setting window defaults',0
boot_bgr: cp850 'Calculating background',0
boot_resirqports: cp850 'Reservando IRQs y puertos',0
boot_setostask: cp850 'Configurando tarea OS',0
boot_allirqs: cp850 'Desenmascarando IRQs',0
boot_tsc: cp850 'Leyendo TSC',0
boot_cpufreq: cp850 'La frequencia del CPU es ',' ',' MHz',0
boot_pal_ega: cp850 'Configurando paleta EGA/CGA 320x200',0
boot_pal_vga: cp850 'Configurando paleta VGA 640x480',0
boot_failed: cp850 'Fallo al iniciar la primer aplicación',0
boot_mtrr: cp850 'Configurando MTRR',0
 
boot_APIC_found: cp850 'APIC habilitado', 0
boot_APIC_nfound: cp850 'APIC no encontrado', 0
if preboot_blogesc
boot_tasking: cp850 'Todo configurado - presiona ESC para iniciar',0
end if
 
;msg_version: cp850 'versión incompatible del controlador',13,10,0
;msg_www: cp850 'por favor, visita www.kolibrios.org',13,10,0
 
ud_user_message:cp850 'Error: instrucción no soportada por el procesador',0
mtrr_user_message cp850 '"There is a problem with MTRR configuration.\nPerformance can be low" -dW',0
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/encoding.inc
0,0 → 1,145
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; fetch the UTF-8 character in addrspace:offs to char
macro fetch_utf8_char addrspace, offs, char
{ local first_byte, b
; fetch first byte
load first_byte byte from addrspace:offs
if first_byte < 0x80
char = first_byte
offs = offs + 1
else if first_byte < 0xC0
err Invalid UTF-8 string
else if first_byte < 0xE0
char = first_byte and 0x1F
load b byte from addrspace:offs + 1
char = (char shl 6) + (b and 0x3F)
offs = offs + 2
else if first_byte < 0xF0
char = first_byte and 0xF
load b byte from addrspace:offs + 1
char = (char shl 6) + (b and 0x3F)
load b byte from addrspace:offs + 2
char = (char shl 6) + (b and 0x3F)
offs = offs + 3
else if first_byte < 0xF8
char = first_byte and 0x7
load b byte from addrspace:offs + 1
char = (char shl 6) + (b and 0x3F)
load b byte from addrspace:offs + 2
char = (char shl 6) + (b and 0x3F)
load b byte from addrspace:offs + 3
char = (char shl 6) + (b and 0x3F)
offs = offs + 4
else
err Invalid UTF-8 string
end if
}
 
; Worker macro for all encodings.
; Common part for all encodings: map characters 0-0x7F trivially,
; translate pseudographics.
; Pseudographics for the boot screen:
; 0x2500 -> 0xC4, 0x2502 -> 0xB3, 0x250C -> 0xDA, 0x2510 -> 0xBF,
; 0x2514 -> 0xC0, 0x2518 -> 0xD9, 0x252C -> 0xC2, 0x2534 -> 0xC1, 0x2551 -> 0xBA
macro convert_utf8 encoding, [arg]
{ common
local ..addrspace, offs, char
offs = 0
virtual at 0
..addrspace:: db arg
..addrspace#.size = $
end virtual
while offs < ..addrspace#.size
fetch_utf8_char ..addrspace, offs, char
if char = 0x2500
db 0xC4
else if char = 0x2502
db 0xB3
else if char = 0x250C
db 0xDA
else if char = 0x2510
db 0xBF
else if char = 0x2514
db 0xC0
else if char = 0x2518
db 0xD9
else if char = 0x252C
db 0xC2
else if char = 0x2534
db 0xC1
else if char = 0x2551
db 0xBA
else if char < 0x80
db char
else
encoding char
end if
end while
}
 
macro declare_encoding encoding
{
macro encoding [arg]
\{ common convert_utf8 encoding#char, arg \}
struc encoding [arg]
\{ common convert_utf8 encoding#char, arg \}
macro encoding#char char
}
 
; Russian: use CP866.
; 0x410-0x43F -> 0x80-0xAF
; 0x440-0x44F -> 0xE0-0xEF
; 0x401 -> 0xF0, 0x451 -> 0xF1
declare_encoding cp866
{
if char = 0x401
db 0xF0
else if char = 0x451
db 0xF1
else if (char < 0x410) | (char > 0x44F)
err Failed to convert to CP866
else if char < 0x440
db char - 0x410 + 0x80
else
db char - 0x440 + 0xE0
end if
}
 
; Latin-1 encoding
; 0x00-0xFF - trivial map
declare_encoding latin1
{
if char < 0x100
db char
else
err Failed to convert to Latin-1
end if
}
 
; CP850 encoding
declare_encoding cp850
{
if char = 0xBF
db 0xA8
else if char = 0xE1
db 0xA0
else if char = 0xE9
db 0x82
else if char = 0xED
db 0xA1
else if char = 0xF3
db 0xA2
else if char = 0xFA
db 0xA3
else
err Failed to convert to CP850
end if
}
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/imports.inc
0,0 → 1,27
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
;============================================================================
;
; External kernel dependencies
;
;============================================================================
 
$Revision$
 
 
align 4
@IMPORT:
 
library \
libini,'libini.obj'
 
import libini, \
ini.lib_init,'lib_init',\
ini.get_str,'ini.get_str',\
ini.enum_keys,'ini.enum_keys',\
ini.get_int,'ini.get_int'
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/kernelsp.inc
0,0 → 1,14
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; 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
 
version cp850 'Kolibri OS versión 0.7.7.0+ ',13,10,13,10,0
diff16 "fin del código del kernel",0,$
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/kglobals.inc
0,0 → 1,69
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
;------------------------------------------------------------------
; use "iglobal" for inserting initialized global data definitions.
;------------------------------------------------------------------
macro iglobal {
IGlobals equ IGlobals,
macro __IGlobalBlock { }
 
macro iglobal_nested {
IGlobals equ IGlobals,
macro __IGlobalBlock \{ }
 
;-------------------------------------------------------------
; use 'uglobal' for inserting uninitialized global definitions.
; even when you define some data values, these variables
; will be stored as uninitialized data.
;-------------------------------------------------------------
macro uglobal {
UGlobals equ UGlobals,
macro __UGlobalBlock { }
 
macro uglobal_nested {
UGlobals equ UGlobals,
macro __UGlobalBlock \{ }
 
endg fix } ; Use endg for ending iglobal and uglobal blocks.
endg_nested fix \}
 
macro IncludeIGlobals{
macro IGlobals dummy,[n] \{ __IGlobalBlock
purge __IGlobalBlock \}
match I, IGlobals \{ I \} }
 
 
macro IncludeUGlobals{
macro UGlobals dummy,[n] \{
\common
\local begin, size
begin = $
virtual at $
\forward
__UGlobalBlock
purge __UGlobalBlock
\common
size = $ - begin
end virtual
rb size
\}
match U, UGlobals \{ U \} }
 
macro IncludeAllGlobals {
IncludeIGlobals
IncludeUGlobals
}
iglobal
endg
 
uglobal
endg
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sound/playnote.inc
0,0 → 1,166
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;; PLAYNOTE.INC version 1.1 22 November 2003 ;;
;; ;;
;; Player Notes for Speaker PC ;;
;; subfunction #55 from function #55 Menuet OS ;;
;; ;;
;; Copyright 2003 VaStaNi ;;
;; vastani@ukr.net ;;
;; >>>- SIMPLY - QUICKLY - SHORTLY -<<< ;;
;; ;;
;; Note: playnote.txt ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
align 4
sound_interface:
 
cmp eax, ebx ; this is subfunction #55 ?
jne retFunc55 ; if no then return.
 
cmp byte [sound_flag], 0
jne retFunc55
 
movzx eax, byte [countDelayNote]
or al, al ; player is busy ?
jnz retFunc55 ; return counter delay Note
 
mov [memAdrNote], esi;edx
call get_pid
mov [pidProcessNote], eax
xor eax, eax ; Ok! EAX = 0
retFunc55:
mov [esp+32], eax ; return value EAX for application
ret
 
iglobal
align 4
kontrOctave dw 0x4742, 0x4342, 0x3F7C, 0x3BEC, 0x388F, 0x3562
dw 0x3264, 0x2F8F, 0x2CE4, 0x2A5F, 0x2802, 0x25BF
memAdrNote dd 0
pidProcessNote dd 0
slotProcessNote dd 0
count_timer_Note dd 1
mem8253r42 dw 0
countDelayNote db 0
endg
 
playNote:
; jmp NotPlayNotes
mov esi, [memAdrNote]
or esi, esi ; ESI = 0 ? - OFF Notes Play ?
jz NotPlayNotes ; if ESI = 0 -> ignore play pocedure
cmp eax, [count_timer_Note]
jb NotPlayNotes
push eax
inc eax
mov [count_timer_Note], eax
mov al, [countDelayNote]
dec al ; decrement counter Delay for Playing Note
jz NewLoadNote@Delay
cmp al, 0xFF ; this is first Note Play ?
jne NextDelayNote
;This is FIRST Note, save counter channel 2 chip 8253
mov al, 0xB6 ; control byte to timer chip 8253
out 0x43, al ; Send it to the control port chip 8253
in al, 0x42 ; Read Lower byte counter channel 2 chip 8253
mov ah, al ; AH = Lower byte counter channel 2
in al, 0x42 ; Read Upper byte counter channel 2 chip 8253
mov [mem8253r42], ax ; Save counter channel 2 timer chip 8253
NewLoadNote@Delay:
cld
; lodsb ; load AL - counter Delay
call ReadNoteByte
or al, al ; THE END ?
jz EndPlayNote
cmp al, 0x81
jnc NoteforOctave
mov [countDelayNote], al
; lodsw ; load AX - counter for Note!
call ReadNoteByte
mov ah, al
call ReadNoteByte
xchg al, ah
jmp pokeNote
 
EndPlayNote: ; THE END Play Notes!
in al, 0x61 ; Get contents of system port B chip 8255
and al, 0xFC ; Turn OFF timer and speaker
out 0x61, al ; Send out new values to port B chip 8255
mov ax, [mem8253r42] ; memorize counter channel 2 timer chip 8253
xchg al, ah ; reverse byte in word
out 0x42, al ; restore Lower byte counter channel 2
mov al, ah ; AL = Upper byte counter channel 2
out 0x42, al ; restore Upper byte channel 2
xor eax, eax ; EAX = 0
mov [memAdrNote], eax; clear header control Delay-Note string
NextDelayNote:
mov [countDelayNote], al; save new counter delay Note
pop eax
NotPlayNotes:
RET
 
NoteforOctave:
sub al, 0x81 ; correction value for delay Note
mov [countDelayNote], al; save counter delay this new Note
; lodsb ; load pack control code
call ReadNoteByte
cmp al, 0xFF ; this is PAUSE ?
jne packCode ; no, this is PACK CODE
in al, 0x61 ; Get contents of system port B chip 8255
and al, 0xFC ; Turn OFF timer and speaker
out 0x61, al ; Send out new values to port B chip 8255
jmp saveESI
 
packCode:
mov cl, al ; save code
and al, 0xF ; clear upper bits
dec al ; correction
add al, al ; transform number to offset constant
movsx eax, al ; EAX - offset
add eax, dword kontrOctave; EAX - address from constant
mov ax, [eax] ; read constant
shr cl, 4 ; transform for number Octave
shr ax, cl ; calculate from Note this Octave!
pokeNote:
out 0x42, al ; Lower byte Out to channel 2 timer chip 8253
mov al, ah
out 0x42, al ; Upper byte Out to channel 2 timer chip 8253
in al, 0x61 ; Get contents of system port B chip 8255
or al, 3 ; Turn ON timer and speaker
out 0x61, al ; Send out new values to port B chip 8255
saveESI:
; mov [memAdrNote], esi ; save new header control Delay-Note string
pop eax
RET
ReadNoteByte:
;result:
; al - note
push eax
push ecx
push edx
push esi
 
mov eax, [pidProcessNote]
call pid_to_slot
test eax, eax
jz .failed
lea ecx, [esp+12]
mov edx, 1
mov esi, [memAdrNote]
inc [memAdrNote]
 
call read_process_memory
.failed:
pop esi
pop edx
pop ecx
pop eax
ret
;------------------- END CODE -------------------
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/sound
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
/kernel/branches/kolibrios-pe-clevermouse/sys.conf
0,0 → 1,18
[path]
/rd/1=/sys
/rd/1/dll=/sys/lib
 
[net]
active=1
addr=192.168.1.2
mask=255.255.255.0
gate=192.168.1.1
 
[gui]
mouse_speed=1
mouse_delay=0x00A
 
[dev]
sb16=0x220
sound_dma=1
midibase=0x320
/kernel/branches/kolibrios-pe-clevermouse/COPYING.TXT
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.
/kernel/branches/kolibrios-pe-clevermouse
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj
Added: tsvn:logminsize
+5
\ No newline at end of property