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